ReportersController.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers;
  4. use App\ApiClient\AdminClient;
  5. use App\ApiClient\ApiException;
  6. use App\ApiClient\ApiNotFoundException;
  7. use App\Auth\SessionManager;
  8. use Psr\Http\Message\ResponseInterface;
  9. use Psr\Http\Message\ServerRequestInterface;
  10. use Slim\Views\Twig;
  11. /**
  12. * `/app/reporters` — list, edit, create, soft-delete.
  13. *
  14. * RBAC: list/show ⇒ Viewer; write ⇒ Admin.
  15. */
  16. final class ReportersController
  17. {
  18. use CrudControllerSupport;
  19. public function __construct(
  20. private readonly Twig $twigEngine,
  21. private readonly SessionManager $sessionManager,
  22. private readonly AdminClient $admin,
  23. ) {
  24. }
  25. protected function twig(): Twig
  26. {
  27. return $this->twigEngine;
  28. }
  29. protected function sessions(): SessionManager
  30. {
  31. return $this->sessionManager;
  32. }
  33. public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
  34. {
  35. $redirect = $this->requireUser($request, $response);
  36. if ($redirect !== null) {
  37. return $redirect;
  38. }
  39. $user = $this->sessionManager->getUser();
  40. \assert($user !== null);
  41. try {
  42. $list = $this->admin->listReporters($user->userId);
  43. } catch (ApiException $e) {
  44. $list = ['data' => [], 'total' => 0];
  45. $this->flashFromException($e);
  46. }
  47. return $this->twigEngine->render($response, 'pages/reporters/index.twig', [
  48. 'active_section' => 'reporters',
  49. 'list' => $list,
  50. 'can_write' => $this->userIs($user, 'admin'),
  51. ]);
  52. }
  53. /**
  54. * @param array{id: string} $args
  55. */
  56. public function edit(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
  57. {
  58. $redirect = $this->requireUser($request, $response);
  59. if ($redirect !== null) {
  60. return $redirect;
  61. }
  62. $user = $this->sessionManager->getUser();
  63. \assert($user !== null);
  64. $id = $this->parseId($args['id']);
  65. if ($id === null) {
  66. return $this->twigEngine->render($response->withStatus(404), 'pages/error.twig', [
  67. 'status' => 404, 'is_client_error' => true, 'message' => 'Reporter not found',
  68. ]);
  69. }
  70. try {
  71. $reporter = $this->admin->getReporter($user->userId, $id);
  72. } catch (ApiNotFoundException) {
  73. return $this->twigEngine->render($response->withStatus(404), 'pages/error.twig', [
  74. 'status' => 404, 'is_client_error' => true, 'message' => 'Reporter not found',
  75. ]);
  76. } catch (ApiException $e) {
  77. $this->flashFromException($e);
  78. return $response->withStatus(303)->withHeader('Location', '/app/reporters');
  79. }
  80. return $this->twigEngine->render($response, 'pages/reporters/edit.twig', [
  81. 'active_section' => 'reporters',
  82. 'reporter' => $reporter,
  83. 'can_write' => $this->userIs($user, 'admin'),
  84. ]);
  85. }
  86. public function create(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
  87. {
  88. $redirect = $this->requireUser($request, $response);
  89. if ($redirect !== null) {
  90. return $redirect;
  91. }
  92. $user = $this->sessionManager->getUser();
  93. \assert($user !== null);
  94. $body = $this->formBody($request);
  95. $payload = ['name' => isset($body['name']) && is_string($body['name']) ? trim($body['name']) : ''];
  96. if (isset($body['description']) && is_string($body['description'])) {
  97. $payload['description'] = trim($body['description']) === '' ? null : trim($body['description']);
  98. }
  99. if (isset($body['trust_weight']) && is_numeric($body['trust_weight'])) {
  100. $payload['trust_weight'] = (float) $body['trust_weight'];
  101. }
  102. try {
  103. $created = $this->admin->createReporter($user->userId, $payload);
  104. $this->sessionManager->flash('success', 'Reporter created.');
  105. $newId = (int) ($created['id'] ?? 0);
  106. return $response->withStatus(303)->withHeader('Location', $newId > 0 ? '/app/reporters/' . $newId : '/app/reporters');
  107. } catch (ApiException $e) {
  108. $this->flashFromException($e);
  109. }
  110. return $response->withStatus(303)->withHeader('Location', '/app/reporters');
  111. }
  112. /**
  113. * @param array{id: string} $args
  114. */
  115. public function update(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
  116. {
  117. $redirect = $this->requireUser($request, $response);
  118. if ($redirect !== null) {
  119. return $redirect;
  120. }
  121. $user = $this->sessionManager->getUser();
  122. \assert($user !== null);
  123. $id = $this->parseId($args['id']);
  124. if ($id === null) {
  125. return $response->withStatus(303)->withHeader('Location', '/app/reporters');
  126. }
  127. $body = $this->formBody($request);
  128. $payload = [];
  129. if (isset($body['name']) && is_string($body['name'])) {
  130. $payload['name'] = trim($body['name']);
  131. }
  132. if (isset($body['description']) && is_string($body['description'])) {
  133. $payload['description'] = trim($body['description']) === '' ? null : trim($body['description']);
  134. }
  135. if (isset($body['trust_weight']) && is_numeric($body['trust_weight'])) {
  136. $payload['trust_weight'] = (float) $body['trust_weight'];
  137. }
  138. if (array_key_exists('is_active', $body)) {
  139. $payload['is_active'] = $this->formBool($body['is_active']);
  140. }
  141. try {
  142. $this->admin->updateReporter($user->userId, $id, $payload);
  143. $this->sessionManager->flash('success', 'Reporter saved.');
  144. } catch (ApiException $e) {
  145. $this->flashFromException($e);
  146. }
  147. return $response->withStatus(303)->withHeader('Location', '/app/reporters/' . $id);
  148. }
  149. /**
  150. * @param array{id: string} $args
  151. */
  152. public function delete(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
  153. {
  154. $redirect = $this->requireUser($request, $response);
  155. if ($redirect !== null) {
  156. return $redirect;
  157. }
  158. $user = $this->sessionManager->getUser();
  159. \assert($user !== null);
  160. $id = $this->parseId($args['id']);
  161. if ($id === null) {
  162. return $response->withStatus(303)->withHeader('Location', '/app/reporters');
  163. }
  164. try {
  165. $this->admin->deleteReporter($user->userId, $id);
  166. $this->sessionManager->flash('success', 'Reporter deactivated.');
  167. } catch (ApiException $e) {
  168. $this->flashFromException($e);
  169. }
  170. return $response->withStatus(303)->withHeader('Location', '/app/reporters');
  171. }
  172. }