TIDE/backend/app/Controllers/PostController.php
Yisroel Baum 8ac5a5b18a
implement featured post admin endpoints
Adds POST /admin/posts/feature, POST /admin/posts/unfeature
(both auth-required, admin-checked inside controller via the
use case's ForbiddenException), and public GET /posts/featured.
Post serialization now includes featureSlot.
2026-05-06 22:32:46 +03:00

260 lines
8.1 KiB
PHP

<?php
namespace App\Controllers;
use App\Exceptions\BadRequestException;
use App\Exceptions\ForbiddenException;
use App\Post\Post;
use App\Post\UseCases\ClearFeaturedPost\ClearFeaturedPost;
use App\Post\UseCases\ClearFeaturedPost\ClearFeaturedPostRequest;
use App\Post\UseCases\CreatePost\CreatePost;
use App\Post\UseCases\CreatePost\CreatePostRequest;
use App\Post\UseCases\DeletePost\DeletePost;
use App\Post\UseCases\DeletePost\DeletePostRequest;
use App\Post\UseCases\GetPost\GetPost;
use App\Post\UseCases\ListFeaturedPosts\ListFeaturedPosts;
use App\Post\UseCases\ListRecentPosts\ListRecentPosts;
use App\Post\UseCases\ListRecentPosts\ListRecentPostsRequest;
use App\Post\UseCases\ListUserPosts\ListUserPosts;
use App\Post\UseCases\ListUserPosts\ListUserPostsRequest;
use App\Post\UseCases\SetFeaturedPost\SetFeaturedPost;
use App\Post\UseCases\SetFeaturedPost\SetFeaturedPostRequest;
use App\User\User;
use App\User\UserRepository;
use DomainException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PostController
{
private const RECENT_LIMIT = 20;
public function __construct(
private CreatePost $createPost,
private DeletePost $deletePost,
private GetPost $getPost,
private ListRecentPosts $listRecentPosts,
private ListUserPosts $listUserPosts,
private SetFeaturedPost $setFeaturedPost,
private ClearFeaturedPost $clearFeaturedPost,
private ListFeaturedPosts $listFeaturedPosts,
private UserRepository $userRepo,
) {}
public function recent(Request $request): JsonResponse
{
try {
$posts = $this->listRecentPosts->execute(
new ListRecentPostsRequest(limit: self::RECENT_LIMIT),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
}
return new JsonResponse([
'posts' => array_map(
function (Post $post) {
return $this->serialize($post);
},
$posts,
),
], 200);
}
public function show(Request $request, int $id): JsonResponse
{
try {
$post = $this->getPost->execute($id);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
}
if ($post === null) {
return new JsonResponse(['error' => 'post not found'], 404);
}
return new JsonResponse([
'post' => $this->serialize($post),
], 200);
}
public function listByUser(
Request $request,
string $displayName,
): JsonResponse {
$user = $this->userRepo->findByDisplayName($displayName);
if ($user === null) {
return new JsonResponse(['error' => 'user not found'], 404);
}
try {
$posts = $this->listUserPosts->execute(
new ListUserPostsRequest(userId: $user->getId()),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
}
return new JsonResponse([
'user' => [
'id' => $user->getId(),
'displayName' => $user->getDisplayName(),
],
'posts' => array_map(
function (Post $post) {
return $this->serialize($post);
},
$posts,
),
], 200);
}
public function create(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->attributes->get('user');
try {
$post = $this->createPost->execute(new CreatePostRequest(
userId: $user->getId(),
title: $request->input('title'),
body: $request->input('body'),
));
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
}
return new JsonResponse([
'post' => $this->serialize($post),
], 201);
}
public function listFeatured(Request $request): JsonResponse
{
$posts = $this->listFeaturedPosts->execute();
return new JsonResponse([
'posts' => array_map(
function (Post $post) {
return $this->serialize($post);
},
$posts,
),
], 200);
}
public function feature(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->attributes->get('user');
try {
$post = $this->setFeaturedPost->execute(
new SetFeaturedPostRequest(
postId: (int) $request->input('postId'),
slot: (int) $request->input('slot'),
requesterIsAdmin: $user->isAdmin(),
),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
} catch (ForbiddenException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 403,
);
} catch (DomainException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 404,
);
}
return new JsonResponse([
'post' => $this->serialize($post),
], 200);
}
public function unfeature(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->attributes->get('user');
try {
$this->clearFeaturedPost->execute(
new ClearFeaturedPostRequest(
postId: (int) $request->input('postId'),
requesterIsAdmin: $user->isAdmin(),
),
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
} catch (ForbiddenException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 403,
);
}
return new JsonResponse(null, 204);
}
public function delete(Request $request, int $id): JsonResponse
{
/** @var User $user */
$user = $request->attributes->get('user');
try {
$this->deletePost->execute(new DeletePostRequest(
postId: $id,
requesterId: $user->getId(),
requesterIsAdmin: $user->isAdmin(),
));
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400,
);
} catch (ForbiddenException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 403,
);
} catch (DomainException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 409,
);
}
return new JsonResponse(null, 204);
}
/**
* @return array{
* id: int,
* userId: int,
* authorDisplayName: string,
* title: string,
* body: string,
* createdAt: string,
* featureSlot: ?int
* }
*/
private function serialize(Post $post): array
{
$author = $this->userRepo->find($post->getUserId());
return [
'id' => $post->getId(),
'userId' => $post->getUserId(),
'authorDisplayName' => $author === null
? ''
: $author->getDisplayName(),
'title' => $post->getTitle(),
'body' => $post->getBody(),
'createdAt' => $post->getCreatedAt()->format(DATE_ATOM),
'featureSlot' => $post->getFeatureSlot(),
];
}
}