firstWhere('email', 'newsroom@skinbase.local') ?? User::query()->updateOrCreate( ['email' => 'newsroom@skinbase.local'], [ 'name' => 'Skinbase Editorial', 'username' => 'skinbaseeditorial', 'role' => 'moderator', 'password' => bcrypt('password'), 'email_verified_at' => now(), 'onboarding_step' => 'complete', 'username_changed_at' => now()->subDays(180), ] ); $retroCreator = $this->upsertCreator('retrogrid', 'Retro Grid', 'retrogrid@skinbase.local'); $pixelCreator = $this->upsertCreator('pixelpilot', 'Pixel Pilot', 'pixelpilot@skinbase.local'); $sceneCreator = $this->upsertCreator('scenelab', 'Scene Lab', 'scenelab@skinbase.local'); $artworks = [ $this->upsertArtwork($retroCreator, 'Retro Grid Dreams', 'retro-grid-dreams', 'Chrome gradients, CRT glow, and 90s interface nostalgia.'), $this->upsertArtwork($pixelCreator, 'Pixel Transit', 'pixel-transit', 'A city-night loop built around tiny lights and sharp palette control.'), $this->upsertArtwork($sceneCreator, 'Signal Bloom', 'signal-bloom', 'Abstract demoscene energy translated into layered light fields.'), ]; $collections = [ $this->upsertCollection($retroCreator, 'Retro Month Essentials', 'retro-month-essentials', 'Editorial picks for glossy nostalgia, synth palettes, and interface-era mood.'), $this->upsertCollection($pixelCreator, 'Pixel Week Highlights', 'pixel-week-highlights', 'A compact collection of crisp sprite work, handheld vibes, and tiny-scale craft.'), ]; $groups = [ $this->upsertGroup($sceneCreator, 'Signal Foundry', 'signal-foundry', 'A collaborative demoscene-inspired group for experiments, releases, and themed drops.'), $this->upsertGroup($retroCreator, 'Afterglow Archive', 'afterglow-archive', 'Creators building glossy retro-futurist interfaces, wallpapers, and cover art.'), ]; $newsArticles = $this->seedableNewsArticles(); $cards = $this->seedableCards(); $now = now(); $currentYear = (int) $now->year; $springVibes = $this->upsertWorld('spring-vibes-' . $currentYear, [ 'title' => 'Spring Vibes ' . $currentYear, 'tagline' => 'Fresh palettes, softer light, and a friendly live participation moment across Skinbase.', 'summary' => 'A live seasonal world for bright artwork, curated collections, creator spotlights, and active submissions.', 'teaser_title' => 'Now live: Spring Vibes', 'teaser_summary' => 'Fresh seasonal artwork, open submissions, and curated highlights are all running inside the current Spring Vibes campaign.', 'description' => 'Spring Vibes is the first fully activated world. It is meant to feel like a live public campaign across homepage, worlds discovery, and upload participation rather than a buried editorial page.', 'theme_key' => 'seasonal', 'accent_color' => '#84cc16', 'accent_color_secondary' => '#14532d', 'background_motif' => 'bloomwave', 'icon_name' => 'fa-solid fa-seedling', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_SEASONAL, 'starts_at' => $now->copy()->subDays(6)->startOfDay(), 'ends_at' => $now->copy()->addDays(18)->endOfDay(), 'promotion_starts_at' => $now->copy()->subDays(2)->startOfDay(), 'promotion_ends_at' => $now->copy()->addDays(12)->endOfDay(), 'is_featured' => true, 'is_active_campaign' => true, 'is_homepage_featured' => true, 'campaign_priority' => 900, 'campaign_label' => 'Live now', 'accepts_submissions' => true, 'participation_mode' => World::PARTICIPATION_MODE_MANUAL_APPROVAL, 'submission_starts_at' => $now->copy()->subDays(4)->startOfDay(), 'submission_ends_at' => $now->copy()->addDays(10)->endOfDay(), 'is_recurring' => true, 'recurrence_key' => 'spring-vibes', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month, 'edition_year' => $currentYear, 'cta_label' => 'Join Spring Vibes', 'cta_url' => '/worlds/spring-vibes-' . $currentYear, 'badge_label' => 'Homepage spotlight', 'badge_description' => 'The primary live world promoted across homepage, upload, and worlds discovery surfaces.', 'badge_url' => '/worlds', 'seo_title' => 'Spring Vibes ' . $currentYear . ' on Skinbase', 'seo_description' => 'Spring Vibes is the live seasonal world on Skinbase right now, with open participation and editorially promoted discovery.', 'related_tags_json' => ['spring', 'seasonal', 'fresh', 'bloom'], 'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_creators', 'featured_groups', 'news', 'cards'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(9), ]); $springArchive = $this->upsertWorld('spring-vibes-' . ($currentYear - 1), [ 'title' => 'Spring Vibes ' . ($currentYear - 1), 'tagline' => 'Last year\'s edition of the recurring spring campaign.', 'summary' => 'Archived spring edition kept visible as part of the recurring worlds record.', 'teaser_title' => 'Spring Vibes archive', 'teaser_summary' => 'The previous edition remains browsable so recurring worlds build continuity over time.', 'description' => 'Spring Vibes archive keeps the prior edition public so the recurring seasonal world feels like a real continuing program.', 'theme_key' => 'seasonal', 'accent_color' => '#65a30d', 'accent_color_secondary' => '#365314', 'background_motif' => 'bloomwave', 'icon_name' => 'fa-solid fa-seedling', 'status' => World::STATUS_ARCHIVED, 'type' => World::TYPE_SEASONAL, 'starts_at' => $now->copy()->subYear()->subDays(6)->startOfDay(), 'ends_at' => $now->copy()->subYear()->addDays(18)->endOfDay(), 'is_featured' => false, 'is_active_campaign' => false, 'is_homepage_featured' => false, 'campaign_priority' => null, 'campaign_label' => 'Archive edition', 'is_recurring' => true, 'recurrence_key' => 'spring-vibes', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month, 'edition_year' => $currentYear - 1, 'cta_label' => 'Browse archive', 'cta_url' => '/worlds/spring-vibes-' . ($currentYear - 1), 'badge_label' => 'Archive edition', 'badge_description' => 'The prior Spring Vibes edition remains visible for continuity.', 'badge_url' => '/worlds', 'seo_title' => 'Spring Vibes ' . ($currentYear - 1) . ' archive', 'seo_description' => 'The previous Spring Vibes edition remains public as part of the recurring worlds archive.', 'related_tags_json' => ['spring', 'archive'], 'section_order_json' => ['featured_artworks', 'featured_creators', 'news'], 'parent_world_id' => $springVibes->id, 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subYear()->subDays(12), ]); $retroMonth = $this->upsertWorld('retro-month-' . $currentYear, [ 'title' => 'Retro Month ' . $currentYear, 'tagline' => 'Chrome, scanlines, glossy interfaces, and warm-digital nostalgia.', 'summary' => 'A featured editorial world that packages retro-inspired artworks, collections, creators, groups, news, and Nova cards into one recurring seasonal destination.', 'teaser_title' => 'Explore Retro Month', 'teaser_summary' => 'A live supporting campaign for glossy nostalgia, synth palettes, and editorially curated retro culture.', 'description' => "Retro Month curates the surface language of nostalgia into a single destination. It highlights polished throwback artwork, creator identity, collaborative groups, and the editorial context that makes seasonal programming feel intentional instead of accidental.", 'theme_key' => 'retro-month', 'accent_color' => '#f97316', 'accent_color_secondary' => '#0f172a', 'background_motif' => 'grid-horizon', 'icon_name' => 'fa-solid fa-compact-disc', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_CAMPAIGN, 'starts_at' => $now->copy()->subDays(10)->startOfDay(), 'ends_at' => $now->copy()->addDays(18)->endOfDay(), 'promotion_starts_at' => $now->copy()->subDays(5)->startOfDay(), 'promotion_ends_at' => $now->copy()->addDays(9)->endOfDay(), 'is_featured' => true, 'is_active_campaign' => true, 'is_homepage_featured' => false, 'campaign_priority' => 450, 'campaign_label' => 'Supporting campaign', 'is_recurring' => true, 'recurrence_key' => 'retro-month', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month, 'edition_year' => $currentYear, 'cta_label' => 'Enter Retro Month', 'cta_url' => '/worlds/retro-month-' . $currentYear, 'badge_label' => 'Featured now', 'badge_description' => 'The active spotlight world on the public homepage and Worlds index.', 'badge_url' => '/worlds', 'seo_title' => 'Retro Month ' . $currentYear . ' on Skinbase', 'seo_description' => 'Retro Month bundles curated artwork, collections, groups, creators, news, and cards into a single recurring editorial world.', 'related_tags_json' => ['retro', 'synthwave', 'interface', 'nostalgia'], 'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_creators', 'featured_groups', 'news', 'cards'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(14), ]); $retroArchive = $this->upsertWorld('retro-month-' . ($currentYear - 1), [ 'title' => 'Retro Month ' . ($currentYear - 1), 'tagline' => 'The previous edition of the recurring retro programming world.', 'summary' => 'Archived edition kept online for continuity and discoverability.', 'description' => 'The previous Retro Month edition remains visible so the recurrence feels like a true archive instead of a disposable campaign.', 'theme_key' => 'retro-month', 'accent_color' => '#fb7185', 'accent_color_secondary' => '#312e81', 'background_motif' => 'sunset-grid', 'icon_name' => 'fa-solid fa-compact-disc', 'status' => World::STATUS_ARCHIVED, 'type' => World::TYPE_CAMPAIGN, 'starts_at' => $now->copy()->subYear()->subDays(10)->startOfDay(), 'ends_at' => $now->copy()->subYear()->addDays(18)->endOfDay(), 'is_featured' => false, 'is_active_campaign' => false, 'is_homepage_featured' => false, 'campaign_priority' => null, 'campaign_label' => 'Archive edition', 'is_recurring' => true, 'recurrence_key' => 'retro-month', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month, 'edition_year' => $currentYear - 1, 'cta_label' => 'Browse archive', 'cta_url' => '/worlds/retro-month-' . ($currentYear - 1), 'badge_label' => 'Archive edition', 'badge_description' => 'Previous recurring edition kept available for context and archival browsing.', 'badge_url' => '/worlds', 'seo_title' => 'Retro Month ' . ($currentYear - 1) . ' archive', 'seo_description' => 'The archived Retro Month edition remains public as part of the recurring Worlds archive.', 'related_tags_json' => ['retro', 'archive'], 'section_order_json' => ['featured_artworks', 'featured_creators', 'news'], 'parent_world_id' => $retroMonth->id, 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subYear()->subDays(18), ]); $pixelWeek = $this->upsertWorld('pixel-week-' . $currentYear, [ 'title' => 'Pixel Week ' . $currentYear, 'tagline' => 'Small-scale craft, tight palettes, and highly legible form.', 'summary' => 'An upcoming themed week focused on pixel art, sprites, handheld aesthetics, and compact visual systems.', 'teaser_title' => 'Pixel Week is coming up', 'teaser_summary' => 'The next campaign is queued with a tight pixel-art brief, creator spotlights, and themed collections.', 'description' => 'Pixel Week is scheduled as the next clear editorial world, giving the public navigation a real forward-looking destination instead of a dead module stub.', 'theme_key' => 'pixel-week', 'accent_color' => '#38bdf8', 'accent_color_secondary' => '#0f172a', 'background_motif' => 'pixel-burst', 'icon_name' => 'fa-solid fa-gamepad', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_EVENT, 'starts_at' => $now->copy()->addDays(24)->startOfDay(), 'ends_at' => $now->copy()->addDays(31)->endOfDay(), 'promotion_starts_at' => $now->copy()->addDays(18)->startOfDay(), 'promotion_ends_at' => $now->copy()->addDays(31)->endOfDay(), 'is_featured' => false, 'is_active_campaign' => true, 'is_homepage_featured' => false, 'campaign_priority' => 300, 'campaign_label' => 'Upcoming campaign', 'is_recurring' => true, 'recurrence_key' => 'pixel-week', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->copy()->addDays(24)->month, 'edition_year' => (int) $now->copy()->addDays(24)->year, 'cta_label' => 'Preview Pixel Week', 'cta_url' => '/worlds/pixel-week-' . $currentYear, 'badge_label' => 'Upcoming', 'badge_description' => 'A seeded upcoming world so the public index is populated beyond a single spotlight.', 'badge_url' => '/worlds', 'seo_title' => 'Pixel Week ' . $currentYear, 'seo_description' => 'Upcoming Pixel Week world for pixel art, creator spotlights, groups, and themed collections.', 'related_tags_json' => ['pixel-art', 'sprites', 'handheld'], 'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_creators', 'news'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(7), ]); $summerWorld = $this->upsertWorld('summer-world-' . $currentYear, [ 'title' => 'Summer World ' . $currentYear, 'tagline' => 'Bright color, open-air mood, and high-energy seasonal programming.', 'summary' => 'A seeded summer world for warm palettes, standout drops, and lightweight seasonal storytelling.', 'description' => 'Summer World exists to make the Worlds feature feel like a living editorial calendar instead of a one-off campaign tool.', 'theme_key' => 'summer', 'accent_color' => '#f59e0b', 'accent_color_secondary' => '#0f766e', 'background_motif' => 'heat-haze', 'icon_name' => 'fa-solid fa-sun', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_SEASONAL, 'starts_at' => $now->copy()->addDays(60)->startOfDay(), 'ends_at' => $now->copy()->addDays(120)->endOfDay(), 'is_featured' => false, 'is_recurring' => true, 'recurrence_key' => 'summer-world', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->copy()->addDays(60)->month, 'edition_year' => (int) $now->copy()->addDays(60)->year, 'cta_label' => 'See summer lineup', 'cta_url' => '/worlds/summer-world-' . $currentYear, 'badge_label' => 'Seasonal program', 'badge_description' => 'Summer launch world seeded for editorial planning and public browsing.', 'badge_url' => '/worlds', 'seo_title' => 'Summer World ' . $currentYear, 'seo_description' => 'Summer World curates warm-season artwork, collections, groups, and related editorial stories.', 'related_tags_json' => ['summer', 'bright', 'seasonal'], 'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_groups', 'news'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(7), ]); $halloweenWorld = $this->upsertWorld('halloween-world-' . $currentYear, [ 'title' => 'Halloween World ' . $currentYear, 'tagline' => 'Dark color, eerie polish, and a platform-wide seasonal event shell.', 'summary' => 'An annual Halloween world with room for creepy artwork, challenge hooks, groups, and seasonal editorial coverage.', 'description' => 'Halloween World gives the Worlds system a recognizable recurring flagship outside the currently active spotlight.', 'theme_key' => 'halloween', 'accent_color' => '#f97316', 'accent_color_secondary' => '#3f3cbb', 'background_motif' => 'moon-fog', 'icon_name' => 'fa-solid fa-ghost', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_SEASONAL, 'starts_at' => $now->copy()->addDays(170)->startOfDay(), 'ends_at' => $now->copy()->addDays(205)->endOfDay(), 'is_featured' => false, 'is_recurring' => true, 'recurrence_key' => 'halloween-world', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->copy()->addDays(170)->month, 'edition_year' => (int) $now->copy()->addDays(170)->year, 'cta_label' => 'Plan Halloween world', 'cta_url' => '/worlds/halloween-world-' . $currentYear, 'badge_label' => 'Recurring seasonal', 'badge_description' => 'Seeded so editors have a real recurring Halloween world from day one.', 'badge_url' => '/worlds', 'seo_title' => 'Halloween World ' . $currentYear, 'seo_description' => 'Recurring Halloween World for seasonal artwork, groups, and themed editorial programming.', 'related_tags_json' => ['halloween', 'dark', 'seasonal'], 'section_order_json' => ['featured_artworks', 'featured_groups', 'news'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(7), ]); $christmasWorld = $this->upsertWorld('christmas-world-' . $currentYear, [ 'title' => 'Christmas World ' . $currentYear, 'tagline' => 'Snowlight, soft-glow palettes, and year-end editorial programming.', 'summary' => 'A seeded Christmas world that rounds out the launch calendar with a second major recurring seasonal destination.', 'description' => 'Christmas World completes the initial recurring lineup so the Worlds system launches with a believable editorial calendar.', 'theme_key' => 'christmas', 'accent_color' => '#22c55e', 'accent_color_secondary' => '#b91c1c', 'background_motif' => 'snowfall', 'icon_name' => 'fa-solid fa-tree', 'status' => World::STATUS_PUBLISHED, 'type' => World::TYPE_SEASONAL, 'starts_at' => $now->copy()->addDays(235)->startOfDay(), 'ends_at' => $now->copy()->addDays(275)->endOfDay(), 'is_featured' => false, 'is_recurring' => true, 'recurrence_key' => 'christmas-world', 'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->copy()->addDays(235)->month, 'edition_year' => (int) $now->copy()->addDays(235)->year, 'cta_label' => 'Preview Christmas world', 'cta_url' => '/worlds/christmas-world-' . $currentYear, 'badge_label' => 'Holiday program', 'badge_description' => 'Seeded holiday world for recurring year-end curation and promotion.', 'badge_url' => '/worlds', 'seo_title' => 'Christmas World ' . $currentYear, 'seo_description' => 'Christmas World packages holiday artwork, collections, creators, groups, and editorial context.', 'related_tags_json' => ['christmas', 'holiday', 'winter'], 'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_creators', 'news'], 'created_by_user_id' => $editor->id, 'published_at' => $now->copy()->subDays(7), ]); $this->syncRelations($springVibes, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Live seasonal feature', true, 0), $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[1]?->id, 'Community highlight', false, 1), $this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[1]?->id, 'Fresh picks', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Spring spotlight creator', true, 0), $this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[0]?->id, 'Collaborative feature', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Launch coverage', true, 0), $this->relation('cards', WorldRelation::TYPE_CARD, ($cards[0] ?? null)?->id, 'Campaign card', true, 0), ]); $this->syncRelations($springArchive, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Archive favorite', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Returning creator', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Previous launch notes', true, 0), ]); $this->syncRelations($retroMonth, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[0]?->id, 'Signature piece', true, 0), $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Editorial pick', false, 1), $this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[0]?->id, 'Start here', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $retroCreator->id, 'Resident creator', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Guest spotlight', false, 1), $this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[0]?->id, 'Group spotlight', true, 0), $this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[1]?->id, 'Archive-minded collective', false, 1), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Editorial context', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[1] ?? null)?->id, 'Related update', false, 1), $this->relation('cards', WorldRelation::TYPE_CARD, ($cards[0] ?? null)?->id, 'Theme card', true, 0), ]); $this->syncRelations($retroArchive, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[0]?->id, 'Archive favorite', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $retroCreator->id, 'Returning creator', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Launch notes', true, 0), ]); $this->syncRelations($pixelWeek, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[1]?->id, 'Pixel craft', true, 0), $this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[1]?->id, 'Week collection', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $pixelCreator->id, 'Week host', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[2] ?? null)?->id, 'Preparation guide', true, 0), ]); $this->syncRelations($summerWorld, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Summer signal', true, 0), $this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[0]?->id, 'Warm palette roundup', true, 0), $this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[1]?->id, 'Collaborative feature', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[3] ?? null)?->id, 'Publishing guide', true, 0), ]); $this->syncRelations($halloweenWorld, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[0]?->id, 'Seasonal teaser', true, 0), $this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[0]?->id, 'Event collaborators', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[4] ?? null)?->id, 'Spotlight coverage', true, 0), ]); $this->syncRelations($christmasWorld, [ $this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Holiday mood', true, 0), $this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[0]?->id, 'Gift-guide curation', true, 0), $this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Seasonal creator', true, 0), $this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[5] ?? null)?->id, 'Release coverage', true, 0), ]); }); } private function upsertCreator(string $username, string $name, string $email): User { return User::query()->updateOrCreate( ['email' => $email], [ 'username' => $username, 'username_changed_at' => now()->subDays(120), 'onboarding_step' => 'complete', 'name' => $name, 'password' => bcrypt('password'), 'email_verified_at' => now(), ] ); } private function upsertArtwork(User $creator, string $title, string $slug, string $description): Artwork { $attributes = Artwork::factory()->make([ 'user_id' => $creator->id, 'uploaded_by_user_id' => $creator->id, 'primary_author_user_id' => $creator->id, 'published_as_type' => Artwork::PUBLISHED_AS_USER, 'published_as_id' => $creator->id, 'title' => $title, 'slug' => $slug, 'description' => $description, 'visibility' => Artwork::VISIBILITY_PUBLIC, 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDays(12), 'artwork_status' => 'published', ])->getAttributes(); return Artwork::query()->updateOrCreate(['slug' => $slug], $attributes); } private function upsertCollection(User $creator, string $title, string $slug, string $description): Collection { $attributes = Collection::factory()->make([ 'user_id' => $creator->id, 'title' => $title, 'slug' => $slug, 'description' => $description, 'summary' => $description, 'visibility' => Collection::VISIBILITY_PUBLIC, 'published_at' => now()->subDays(10), ])->getAttributes(); return Collection::query()->updateOrCreate(['slug' => $slug], $attributes); } private function upsertGroup(User $owner, string $name, string $slug, string $bio): Group { $attributes = Group::factory()->make([ 'owner_user_id' => $owner->id, 'name' => $name, 'slug' => $slug, 'headline' => $bio, 'bio' => $bio, 'visibility' => Group::VISIBILITY_PUBLIC, 'status' => Group::LIFECYCLE_ACTIVE, ])->getAttributes(); return Group::query()->updateOrCreate(['slug' => $slug], $attributes); } private function upsertWorld(string $slug, array $attributes): World { return World::query()->updateOrCreate(['slug' => $slug], $attributes); } private function syncRelations(World $world, array $relations): void { $world->worldRelations()->delete(); foreach (array_values(array_filter($relations)) as $relation) { $world->worldRelations()->create($relation); } } private function relation(string $sectionKey, string $relatedType, ?int $relatedId, string $contextLabel, bool $featured, int $sortOrder): ?array { if (! $relatedId) { return null; } return [ 'section_key' => $sectionKey, 'related_type' => $relatedType, 'related_id' => $relatedId, 'context_label' => $contextLabel, 'sort_order' => $sortOrder, 'is_featured' => $featured, ]; } /** * @return array */ private function seedableNewsArticles(): array { if (! Schema::hasTable((new NewsArticle())->getTable())) { return []; } return NewsArticle::query() ->published() ->orderByDesc('published_at') ->limit(6) ->get() ->values() ->all(); } /** * @return array */ private function seedableCards(): array { if (! Schema::hasTable((new NovaCard())->getTable())) { return []; } return NovaCard::query() ->whereNotNull('published_at') ->orderByDesc('published_at') ->limit(3) ->get() ->values() ->all(); } }