AzuraCast/src/Controller/Api/Admin/UsersController.php

244 lines
8.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controller\Api\Admin;
use App\Controller\Api\Traits\CanSortResults;
use App\Controller\Frontend\Account\MasqueradeAction;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use InvalidArgumentException;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;
/** @extends AbstractAdminApiCrudController<Entity\User> */
#[
OA\Get(
path: '/admin/users',
operationId: 'getUsers',
description: 'List all current users in the system.',
security: OpenApi::API_KEY_SECURITY,
tags: ['Administration: Users'],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/User')
)
),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_GENERIC_ERROR, response: 500),
]
),
OA\Post(
path: '/admin/users',
operationId: 'addUser',
description: 'Create a new user.',
security: OpenApi::API_KEY_SECURITY,
requestBody: new OA\RequestBody(
content: new OA\JsonContent(ref: '#/components/schemas/User')
),
tags: ['Administration: Users'],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(ref: '#/components/schemas/User')
),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_GENERIC_ERROR, response: 500),
]
),
OA\Get(
path: '/admin/user/{id}',
operationId: 'getUser',
description: 'Retrieve details for a single current user.',
security: OpenApi::API_KEY_SECURITY,
tags: ['Administration: Users'],
parameters: [
new OA\Parameter(
name: 'id',
description: 'User ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'integer', format: 'int64')
),
],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(ref: '#/components/schemas/User')
),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_NOT_FOUND, response: 404),
new OA\Response(ref: OpenApi::REF_RESPONSE_GENERIC_ERROR, response: 500),
]
),
OA\Put(
path: '/admin/user/{id}',
operationId: 'editUser',
description: 'Update details of a single user.',
security: OpenApi::API_KEY_SECURITY,
requestBody: new OA\RequestBody(
content: new OA\JsonContent(ref: '#/components/schemas/User')
),
tags: ['Administration: Users'],
parameters: [
new OA\Parameter(
name: 'id',
description: 'User ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'integer', format: 'int64')
),
],
responses: [
new OA\Response(ref: OpenApi::REF_RESPONSE_SUCCESS, response: 200),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_NOT_FOUND, response: 404),
new OA\Response(ref: OpenApi::REF_RESPONSE_GENERIC_ERROR, response: 500),
]
),
OA\Delete(
path: '/admin/user/{id}',
operationId: 'deleteUser',
description: 'Delete a single user.',
security: OpenApi::API_KEY_SECURITY,
tags: ['Administration: Users'],
parameters: [
new OA\Parameter(
name: 'id',
description: 'User ID',
in: 'path',
required: true,
schema: new OA\Schema(type: 'integer', format: 'int64')
),
],
responses: [
new OA\Response(ref: OpenApi::REF_RESPONSE_SUCCESS, response: 200),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_NOT_FOUND, response: 404),
new OA\Response(ref: OpenApi::REF_RESPONSE_GENERIC_ERROR, response: 500),
]
)
]
class UsersController extends AbstractAdminApiCrudController
{
use CanSortResults;
protected string $entityClass = Entity\User::class;
protected string $resourceRouteName = 'api:admin:user';
public function listAction(
ServerRequest $request,
Response $response
): ResponseInterface {
$qb = $this->em->createQueryBuilder()
->select('e')
->from(Entity\User::class, 'e');
$qb = $this->sortQueryBuilder(
$request,
$qb,
[
'name' => 'e.name',
],
'e.name'
);
$searchPhrase = trim($request->getParam('searchPhrase', ''));
if (!empty($searchPhrase)) {
$qb->andWhere('(e.name LIKE :name OR e.email LIKE :name)')
->setParameter('name', '%' . $searchPhrase . '%');
}
return $this->listPaginatedFromQuery($request, $response, $qb->getQuery());
}
protected function viewRecord(object $record, ServerRequest $request): mixed
{
if (!($record instanceof Entity\User)) {
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
}
$return = $this->toArray($record);
$isInternal = ('true' === $request->getParam('internal', 'false'));
$router = $request->getRouter();
$csrf = $request->getCsrf();
$currentUser = $request->getUser();
$return['is_me'] = $currentUser->getIdRequired() === $record->getIdRequired();
$return['links'] = [
'self' => (string)$router->fromHere(
route_name: $this->resourceRouteName,
route_params: ['id' => $record->getIdRequired()],
absolute: !$isInternal
),
'masquerade' => (string)$router->fromHere(
route_name: 'account:masquerade',
route_params: [
'id' => $record->getIdRequired(),
'csrf' => $csrf->generate(MasqueradeAction::CSRF_NAMESPACE),
],
absolute: !$isInternal
),
];
return $return;
}
public function editAction(
ServerRequest $request,
Response $response,
string $id
): ResponseInterface {
$record = $this->getRecord($id);
if (null === $record) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
}
$currentUser = $request->getUser();
if ($record->getId() === $currentUser->getId()) {
return $response->withStatus(403)
->withJson(new Entity\Api\Error(403, __('You cannot modify yourself.')));
}
$this->editRecord((array)$request->getParsedBody(), $record);
return $response->withJson(Entity\Api\Status::updated());
}
public function deleteAction(
ServerRequest $request,
Response $response,
string $id
): ResponseInterface {
$record = $this->getRecord($id);
if (null === $record) {
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
}
$currentUser = $request->getUser();
if ($record->getId() === $currentUser->getId()) {
return $response->withStatus(403)
->withJson(new Entity\Api\Error(403, __('You cannot remove yourself.')));
}
$this->deleteRecord($record);
return $response->withJson(Entity\Api\Status::deleted());
}
}