feat(blog): add admin endpoint to list all blog posts with status filtering
This commit is contained in:
@@ -149,6 +149,37 @@ class BlogController extends BaseController
|
||||
|
||||
// ── Admin CRUD ────────────────────────────────────────────────────────────
|
||||
|
||||
#[OA\Get(
|
||||
path: '/api/v1/admin/blogs',
|
||||
summary: 'List blog posts of ALL statuses for the admin panel (draft/published/archived)',
|
||||
security: [['bearerAuth' => []]],
|
||||
parameters: [
|
||||
new OA\Parameter(name: 'page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)),
|
||||
new OA\Parameter(name: 'limit', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 20, maximum: 50)),
|
||||
new OA\Parameter(name: 'status', in: 'query', required: false, schema: new OA\Schema(type: 'string', enum: ['draft', 'published', 'archived'])),
|
||||
new OA\Parameter(name: 'search', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
|
||||
],
|
||||
responses: [new OA\Response(response: 200, description: 'Paginated blog list (all statuses)')]
|
||||
)]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/admin/blogs', methods: ['GET'])]
|
||||
public function adminList(Request $request): JsonResponse
|
||||
{
|
||||
$page = max(1, (int) $request->query->get('page', 1));
|
||||
$limit = min(50, max(1, (int) $request->query->get('limit', 20)));
|
||||
$status = $request->query->get('status') ?: null;
|
||||
$search = $request->query->get('search') ?: null;
|
||||
|
||||
$items = array_map(
|
||||
fn(Blog $b) => $b->toListArray(),
|
||||
$this->blogRepo->findForAdmin($page, $limit, $status, $search)
|
||||
);
|
||||
$total = $this->blogRepo->countForAdmin($status, $search);
|
||||
|
||||
return $this->paginated($items, $total, $page, $limit);
|
||||
}
|
||||
|
||||
|
||||
#[OA\Post(
|
||||
path: '/api/v1/blog',
|
||||
summary: 'Create a new blog post (admin only)',
|
||||
|
||||
@@ -40,6 +40,40 @@ class BlogRepository extends ServiceEntityRepository
|
||||
->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin list — ALL statuses (draft/published/archived), newest first, with
|
||||
* optional status + title search. The public list only returns published, so
|
||||
* the admin panel must use this to see drafts.
|
||||
* @return Blog[]
|
||||
*/
|
||||
public function findForAdmin(int $page, int $limit, ?string $status = null, ?string $search = null): array
|
||||
{
|
||||
$qb = $this->adminQb($status, $search)
|
||||
->leftJoin('b.city', 'c')->addSelect('c')
|
||||
->orderBy('b.createdAt', 'DESC')
|
||||
->setFirstResult(($page - 1) * $limit)
|
||||
->setMaxResults($limit);
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function countForAdmin(?string $status = null, ?string $search = null): int
|
||||
{
|
||||
return (int) $this->adminQb($status, $search)
|
||||
->select('COUNT(b.id)')->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
private function adminQb(?string $status, ?string $search): \Doctrine\ORM\QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('b');
|
||||
if ($status !== null && $status !== '') {
|
||||
$qb->andWhere('b.status = :status')->setParameter('status', $status);
|
||||
}
|
||||
if ($search !== null && $search !== '') {
|
||||
$qb->andWhere('b.title LIKE :q')->setParameter('q', '%' . $search . '%');
|
||||
}
|
||||
return $qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* A representative's own posts, newest first, optionally filtered by status.
|
||||
* @return Blog[]
|
||||
|
||||
Reference in New Issue
Block a user