Wire admin studio SSR and search infrastructure

This commit is contained in:
2026-05-01 11:46:06 +02:00
parent 257b0dbef6
commit 18cea8b0f0
329 changed files with 197465 additions and 2741 deletions

View File

@@ -11,6 +11,7 @@ use App\Models\ForumPost;
use App\Models\ForumThread;
use App\Models\User;
use App\Models\UserActivity;
use App\Models\WorldRewardGrant;
use App\Support\AvatarUrl;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
@@ -20,7 +21,7 @@ use Illuminate\Support\Str;
final class UserActivityService
{
public const DEFAULT_PER_PAGE = 20;
private const FEED_SCHEMA_VERSION = 2;
private const FEED_SCHEMA_VERSION = 3;
private const FILTER_ALL = 'all';
private const FILTER_UPLOADS = 'uploads';
@@ -65,6 +66,11 @@ final class UserActivityService
return $this->log($userId, UserActivity::TYPE_ACHIEVEMENT, UserActivity::ENTITY_ACHIEVEMENT, $achievementId, $meta);
}
public function logWorldReward(int $userId, int $worldRewardGrantId, array $meta = []): ?UserActivity
{
return $this->log($userId, UserActivity::TYPE_WORLD_REWARD, UserActivity::ENTITY_WORLD_REWARD, $worldRewardGrantId, $meta);
}
public function logForumPost(int $userId, int $threadId, array $meta = []): ?UserActivity
{
return $this->log($userId, UserActivity::TYPE_FORUM_POST, UserActivity::ENTITY_FORUM_THREAD, $threadId, $meta);
@@ -220,6 +226,14 @@ final class UserActivityService
->values()
->all();
$worldRewardIds = $rows
->filter(fn (UserActivity $activity): bool => $activity->entity_type === UserActivity::ENTITY_WORLD_REWARD)
->pluck('entity_id')
->map(fn (mixed $id): int => (int) $id)
->unique()
->values()
->all();
return [
'artworks' => empty($artworkIds)
? collect()
@@ -245,7 +259,7 @@ final class UserActivityService
? collect()
: User::query()
->with('profile:user_id,avatar_hash')
->withCount('artworks')
->with('statistics:user_id,uploads_count')
->whereIn('id', $userIds)
->where('is_active', true)
->whereNull('deleted_at')
@@ -276,6 +290,13 @@ final class UserActivityService
->whereHas('thread', fn ($query) => $query->where('visibility', 'public')->whereNull('deleted_at'))
->get()
->keyBy('id'),
'world_rewards' => empty($worldRewardIds)
? collect()
: WorldRewardGrant::query()
->with(['world', 'artwork'])
->whereIn('id', $worldRewardIds)
->get()
->keyBy('id'),
];
}
@@ -299,6 +320,7 @@ final class UserActivityService
UserActivity::TYPE_REPLY => $this->formatCommentActivity($base, $activity, $related),
UserActivity::TYPE_FOLLOW => $this->formatFollowActivity($base, $activity, $related),
UserActivity::TYPE_ACHIEVEMENT => $this->formatAchievementActivity($base, $activity, $related),
UserActivity::TYPE_WORLD_REWARD => $this->formatWorldRewardActivity($base, $activity, $related),
UserActivity::TYPE_FORUM_POST,
UserActivity::TYPE_FORUM_REPLY => $this->formatForumActivity($base, $activity, $related),
default => null,
@@ -374,6 +396,37 @@ final class UserActivityService
];
}
private function formatWorldRewardActivity(array $base, UserActivity $activity, array $related): ?array
{
/** @var WorldRewardGrant|null $grant */
$grant = $related['world_rewards']->get((int) $activity->entity_id);
if (! $grant || ! $grant->world) {
return null;
}
return [
...$base,
'world_reward' => [
'id' => (int) $grant->id,
'reward_type' => $grant->reward_type->value,
'reward_label' => $grant->reward_type->label(),
'badge_label' => trim($grant->world->title . ' ' . $grant->reward_type->label()),
'tone' => $grant->reward_type->tone(),
'world' => [
'id' => (int) $grant->world->id,
'title' => (string) $grant->world->title,
'url' => $grant->world->publicUrl(),
],
'artwork' => $grant->artwork ? [
'id' => (int) $grant->artwork->id,
'title' => (string) ($grant->artwork->title ?? 'Artwork'),
'url' => route('art.show', ['id' => (int) $grant->artwork->id, 'slug' => $grant->artwork->slug ?: Str::slug((string) $grant->artwork->title)]),
] : null,
'note' => (string) ($grant->note ?? ''),
],
];
}
private function formatForumActivity(array $base, UserActivity $activity, array $related): ?array
{
if ($activity->type === UserActivity::TYPE_FORUM_POST) {
@@ -510,7 +563,7 @@ final class UserActivityService
return ['label' => 'Moderator', 'tone' => 'amber'];
}
if ((int) ($user->artworks_count ?? 0) > 0) {
if ((int) ($user->statistics?->uploads_count ?? $user->artworks_count ?? 0) > 0) {
return ['label' => 'Creator', 'tone' => 'sky'];
}
@@ -533,6 +586,7 @@ final class UserActivityService
UserActivity::TYPE_FAVOURITE,
UserActivity::TYPE_FOLLOW,
UserActivity::TYPE_ACHIEVEMENT,
UserActivity::TYPE_WORLD_REWARD,
UserActivity::TYPE_FORUM_POST,
UserActivity::TYPE_FORUM_REPLY,
],