Unify portal thread rows and add summary API

This commit is contained in:
Micha
2026-01-16 02:44:04 +01:00
parent f9de433545
commit 24c16ed0dd
12 changed files with 380 additions and 188 deletions

View File

@@ -0,0 +1,149 @@
<?php
namespace App\Http\Controllers;
use App\Models\Forum;
use App\Models\Post;
use App\Models\Thread;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class PortalController extends Controller
{
public function __invoke(Request $request): JsonResponse
{
$forums = Forum::query()
->withoutTrashed()
->withCount(['threads', 'posts'])
->withSum('threads', 'views_count')
->orderBy('position')
->orderBy('name')
->get();
$forumIds = $forums->pluck('id')->all();
$lastPostByForum = $this->loadLastPostsByForum($forumIds);
$forumPayload = $forums->map(
fn (Forum $forum) => $this->serializeForum($forum, $lastPostByForum[$forum->id] ?? null)
);
$threads = Thread::query()
->withoutTrashed()
->withCount('posts')
->with([
'user' => fn ($query) => $query->withCount('posts')->with('rank'),
'latestPost.user',
])
->latest('created_at')
->limit(12)
->get()
->map(fn (Thread $thread) => $this->serializeThread($thread));
$stats = [
'threads' => Thread::query()->withoutTrashed()->count(),
'posts' => Post::query()->withoutTrashed()->count(),
'users' => User::query()->count(),
];
$user = auth('sanctum')->user();
return response()->json([
'forums' => $forumPayload,
'threads' => $threads,
'stats' => $stats,
'profile' => $user ? [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'avatar_url' => $user->avatar_path ? Storage::url($user->avatar_path) : null,
'location' => $user->location,
'rank' => $user->rank ? [
'id' => $user->rank->id,
'name' => $user->rank->name,
] : null,
] : null,
]);
}
private function serializeForum(Forum $forum, ?Post $lastPost): array
{
return [
'id' => $forum->id,
'name' => $forum->name,
'description' => $forum->description,
'type' => $forum->type,
'parent' => $forum->parent_id ? "/api/forums/{$forum->parent_id}" : null,
'position' => $forum->position,
'threads_count' => $forum->threads_count ?? 0,
'posts_count' => $forum->posts_count ?? 0,
'views_count' => (int) ($forum->threads_sum_views_count ?? 0),
'last_post_at' => $lastPost?->created_at?->toIso8601String(),
'last_post_user_id' => $lastPost?->user_id,
'last_post_user_name' => $lastPost?->user?->name,
'created_at' => $forum->created_at?->toIso8601String(),
'updated_at' => $forum->updated_at?->toIso8601String(),
];
}
private function serializeThread(Thread $thread): array
{
return [
'id' => $thread->id,
'title' => $thread->title,
'body' => $thread->body,
'forum' => "/api/forums/{$thread->forum_id}",
'user_id' => $thread->user_id,
'posts_count' => $thread->posts_count ?? 0,
'views_count' => $thread->views_count ?? 0,
'user_name' => $thread->user?->name,
'user_avatar_url' => $thread->user?->avatar_path
? Storage::url($thread->user->avatar_path)
: null,
'user_posts_count' => $thread->user?->posts_count,
'user_created_at' => $thread->user?->created_at?->toIso8601String(),
'user_rank_name' => $thread->user?->rank?->name,
'user_rank_badge_type' => $thread->user?->rank?->badge_type,
'user_rank_badge_text' => $thread->user?->rank?->badge_text,
'user_rank_badge_url' => $thread->user?->rank?->badge_image_path
? Storage::url($thread->user->rank->badge_image_path)
: null,
'last_post_at' => $thread->latestPost?->created_at?->toIso8601String()
?? $thread->created_at?->toIso8601String(),
'last_post_id' => $thread->latestPost?->id,
'last_post_user_id' => $thread->latestPost?->user_id ?? $thread->user_id,
'last_post_user_name' => $thread->latestPost?->user?->name
?? $thread->user?->name,
'created_at' => $thread->created_at?->toIso8601String(),
'updated_at' => $thread->updated_at?->toIso8601String(),
];
}
private function loadLastPostsByForum(array $forumIds): array
{
if (empty($forumIds)) {
return [];
}
$posts = Post::query()
->select('posts.*', 'threads.forum_id as forum_id')
->join('threads', 'posts.thread_id', '=', 'threads.id')
->whereIn('threads.forum_id', $forumIds)
->whereNull('posts.deleted_at')
->whereNull('threads.deleted_at')
->orderByDesc('posts.created_at')
->with('user')
->get();
$byForum = [];
foreach ($posts as $post) {
$forumId = (int) ($post->forum_id ?? 0);
if ($forumId && !array_key_exists($forumId, $byForum)) {
$byForum[$forumId] = $post;
}
}
return $byForum;
}
}

View File

@@ -128,6 +128,7 @@ class ThreadController extends Controller
: null,
'last_post_at' => $thread->latestPost?->created_at?->toIso8601String()
?? $thread->created_at?->toIso8601String(),
'last_post_id' => $thread->latestPost?->id,
'last_post_user_id' => $thread->latestPost?->user_id ?? $thread->user_id,
'last_post_user_name' => $thread->latestPost?->user?->name
?? $thread->user?->name,