114 lines
4.0 KiB
PHP
114 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\JsonResponse;
|
|
use App\Models\ArtworkComment;
|
|
use App\Support\AvatarUrl;
|
|
use App\Services\ThumbnailPresenter;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Str;
|
|
use Carbon\Carbon;
|
|
|
|
class LatestCommentsApiController extends Controller
|
|
{
|
|
private const PER_PAGE = 20;
|
|
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$type = $request->query('type', 'all');
|
|
|
|
// Validate filter type
|
|
if (! in_array($type, ['all', 'following', 'mine'], true)) {
|
|
$type = 'all';
|
|
}
|
|
|
|
// 'mine' and 'following' require auth
|
|
if (in_array($type, ['mine', 'following'], true) && ! $request->user()) {
|
|
return response()->json(['error' => 'Unauthenticated'], 401);
|
|
}
|
|
|
|
$query = ArtworkComment::with(['user', 'user.profile', 'artwork'])
|
|
->whereHas('artwork', function ($q) {
|
|
$q->public()->published()->whereNull('deleted_at');
|
|
})
|
|
->orderByDesc('artwork_comments.created_at');
|
|
|
|
switch ($type) {
|
|
case 'mine':
|
|
$query->where('artwork_comments.user_id', $request->user()->id);
|
|
break;
|
|
|
|
case 'following':
|
|
$followingIds = $request->user()
|
|
->following()
|
|
->pluck('users.id');
|
|
$query->whereIn('artwork_comments.user_id', $followingIds);
|
|
break;
|
|
|
|
default:
|
|
// 'all' — cache the first page only
|
|
if ((int) $request->query('page', 1) === 1) {
|
|
$cacheKey = 'comments.latest.all.page1';
|
|
$ttl = 120; // 2 minutes
|
|
|
|
$paginator = Cache::remember($cacheKey, $ttl, fn () => $query->paginate(self::PER_PAGE));
|
|
} else {
|
|
$paginator = $query->paginate(self::PER_PAGE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (! isset($paginator)) {
|
|
$paginator = $query->paginate(self::PER_PAGE);
|
|
}
|
|
|
|
$items = $paginator->getCollection()->map(function (ArtworkComment $c) {
|
|
$art = $c->artwork;
|
|
$user = $c->user;
|
|
|
|
$present = $art ? ThumbnailPresenter::present($art, 'md') : null;
|
|
$thumb = $present ? ($present['url'] ?? null) : null;
|
|
|
|
$userId = (int) ($c->user_id ?? 0);
|
|
$avatarHash = $user?->profile?->avatar_hash ?? null;
|
|
|
|
return [
|
|
'comment_id' => $c->getKey(),
|
|
'comment_text' => e(strip_tags($c->content ?? '')),
|
|
'created_at' => $c->created_at?->toIso8601String(),
|
|
'time_ago' => $c->created_at ? Carbon::parse($c->created_at)->diffForHumans() : null,
|
|
|
|
'commenter' => [
|
|
'id' => $userId,
|
|
'username' => $user?->username ?? null,
|
|
'display' => $user?->username ?? $user?->name ?? 'User',
|
|
'profile_url' => $user?->username ? '/@' . $user->username : '/profile/' . $userId,
|
|
'avatar_url' => AvatarUrl::forUser($userId, $avatarHash, 64),
|
|
],
|
|
|
|
'artwork' => $art ? [
|
|
'id' => $art->id,
|
|
'title' => $art->title,
|
|
'slug' => $art->slug ?? Str::slug($art->title ?? ''),
|
|
'url' => '/art/' . $art->id . '/' . ($art->slug ?? Str::slug($art->title ?? '')),
|
|
'thumb' => $thumb,
|
|
] : null,
|
|
];
|
|
});
|
|
|
|
return response()->json([
|
|
'data' => $items,
|
|
'meta' => [
|
|
'current_page' => $paginator->currentPage(),
|
|
'last_page' => $paginator->lastPage(),
|
|
'per_page' => $paginator->perPage(),
|
|
'total' => $paginator->total(),
|
|
'has_more' => $paginator->hasMorePages(),
|
|
],
|
|
]);
|
|
}
|
|
}
|