Implement academy analytics, billing, and web stories updates

This commit is contained in:
2026-05-26 07:27:29 +02:00
parent 456c3d6bb0
commit 0b33a1b074
177 changed files with 27360 additions and 2685 deletions

View File

@@ -17,6 +17,7 @@ use App\Models\User;
use App\Models\World;
use App\Models\WorldRelation;
use App\Models\WorldSubmission;
use App\Models\WorldWebStory;
use App\Services\CollectionService;
use App\Services\GroupCardService;
use App\Services\Maturity\ArtworkMaturityService;
@@ -591,7 +592,7 @@ final class WorldService
public function publicShowPayload(World $world, ?User $viewer = null, bool $includeDraftRecap = false): array
{
$world->loadMissing(['createdBy.profile', 'parentWorld', 'worldRelations', 'linkedChallenge.group', 'recapArticle.author.profile', 'recapArticle.category']);
$world->loadMissing(['createdBy.profile', 'parentWorld', 'worldRelations', 'linkedChallenge.group', 'recapArticle.author.profile', 'recapArticle.category', 'publishedWebStory']);
$sections = $this->resolveSections($world, $viewer);
$familyEditions = $this->familyEditionsForWorld($world);
@@ -673,6 +674,7 @@ final class WorldService
'archiveEditions' => $archiveEditions,
'familySummary' => $this->mapRecurringFamilySummary($world),
'relatedWorlds' => $relatedWorlds,
'webStory' => $this->publishedWebStoryPayload($world),
];
}
@@ -1406,7 +1408,7 @@ final class WorldService
private function mapWorldDetail(World $world): array
{
$world->loadMissing(['linkedChallenge.group', 'worldRelations', 'recapArticle.author.profile', 'recapArticle.category']);
$world->loadMissing(['linkedChallenge.group', 'worldRelations', 'recapArticle.author.profile', 'recapArticle.category', 'publishedWebStory']);
$theme = $this->themePayload($world);
$familyTitle = $this->recurrenceFamilyLabel($world);
$familyUrl = $this->familyUrlForWorld($world);
@@ -1477,6 +1479,26 @@ final class WorldService
'rewarded_contributor_count' => (int) $world->worldRewardGrants()->count(),
'relation_count' => (int) ($world->world_relations_count ?? $world->worldRelations()->count()),
'public_url' => $this->publicUrlForWorld($world),
'published_web_story' => $this->publishedWebStoryPayload($world),
];
}
private function publishedWebStoryPayload(World $world): ?array
{
$story = $world->publishedWebStory;
if (! $story instanceof WorldWebStory) {
return null;
}
return [
'id' => (int) $story->id,
'slug' => (string) $story->slug,
'title' => (string) $story->title,
'excerpt' => (string) ($story->excerpt ?? ''),
'poster_portrait_url' => $story->posterPortraitUrl(),
'url' => $story->publicUrl(),
'published_at' => optional($story->published_at)?->toIso8601String(),
];
}