src/Controller/ApiV2/Residents/ProblemController.php line 92

  1. <?php
  2. namespace App\Controller\ApiV2\Residents;
  3. use App\Controller\ApiV2\AbstractController;
  4. use App\Entity\Task;
  5. use App\Entity\TaskType;
  6. use App\Enums\AttachmentTypeEnum;
  7. use App\Exception\FormException;
  8. use App\Form\ApiV2\BuildingProblemType;
  9. use App\Repository\BuildingRepository;
  10. use App\Repository\FlatRepository;
  11. use App\Repository\TaskFileRepository;
  12. use App\Repository\TaskRepository;
  13. use App\Repository\TaskTypeRepository;
  14. use App\Repository\UserRepository;
  15. use App\Security\Voter\FlatVoter;
  16. use App\Services\MailService;
  17. use App\Services\NotificationTokenService;
  18. use App\Services\TaskFileService;
  19. use App\Services\TaskService;
  20. use Doctrine\ORM\NonUniqueResultException;
  21. use Doctrine\ORM\NoResultException;
  22. use Exception;
  23. use FOS\RestBundle\Controller\Annotations as Rest;
  24. use GuzzleHttp\Exception\GuzzleException;
  25. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  26. use Symfony\Component\HttpFoundation\File\UploadedFile;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\HttpKernel\Exception\HttpException;
  29. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  30. class ProblemController extends AbstractController
  31. {
  32. private FlatRepository $flatRepository;
  33. private TaskRepository $taskRepository;
  34. private TaskTypeRepository $taskTypeRepository;
  35. private TaskFileService $taskFileService;
  36. private TaskFileRepository $taskFileRepository;
  37. private TaskService $taskService;
  38. private NotificationTokenService $notificationTokenService;
  39. private UserRepository $userRepository;
  40. private MailService $mailService;
  41. private string $projectDir;
  42. /**
  43. * @param BuildingRepository $buildingRepository
  44. * @param UserRepository $userRepository
  45. * @param FlatRepository $flatRepository
  46. * @param TaskRepository $taskRepository
  47. * @param TaskTypeRepository $taskTypeRepository
  48. * @param TaskFileRepository $taskFileRepository
  49. * @param TaskFileService $taskFileService
  50. * @param TaskService $taskService
  51. * @param NotificationTokenService $notificationTokenService
  52. * @param MailService $mailService
  53. * @param string $projectDir
  54. */
  55. public function __construct(
  56. BuildingRepository $buildingRepository,
  57. UserRepository $userRepository,
  58. FlatRepository $flatRepository,
  59. TaskRepository $taskRepository,
  60. TaskTypeRepository $taskTypeRepository,
  61. TaskFileRepository $taskFileRepository,
  62. TaskFileService $taskFileService,
  63. TaskService $taskService,
  64. NotificationTokenService $notificationTokenService,
  65. MailService $mailService,
  66. string $projectDir
  67. ) {
  68. parent::__construct($buildingRepository);
  69. $this->flatRepository = $flatRepository;
  70. $this->taskRepository = $taskRepository;
  71. $this->taskTypeRepository = $taskTypeRepository;
  72. $this->taskFileService = $taskFileService;
  73. $this->taskFileRepository = $taskFileRepository;
  74. $this->taskService = $taskService;
  75. $this->notificationTokenService = $notificationTokenService;
  76. $this->userRepository = $userRepository;
  77. $this->mailService = $mailService;
  78. $this->projectDir = $projectDir;
  79. }
  80. /**
  81. * @param Request $request
  82. * @param int $id
  83. * @return array<string, mixed>
  84. * @throws NoResultException
  85. * @throws NonUniqueResultException
  86. */
  87. #[Rest\Get('/', name: 'residents_flats_problems_index')]
  88. public function index(Request $request, int $id): array
  89. {
  90. $flat = $this->flatRepository->find($id);
  91. if (!$flat) {
  92. $this->createNotFoundException();
  93. }
  94. $this->denyAccessUnlessGranted(FlatVoter::FLAT_BELONGS_TO_RESIDENT, $flat);
  95. $options = $this->getListOptions($request);
  96. $status = $request->get('status');
  97. $tasks = $this->taskRepository->findTasksByBuildingPaginated2(
  98. $flat->getBuilding(),
  99. $options,
  100. $status
  101. );
  102. $countTask = $this->taskRepository->countTasksByBuildingPaginated2(
  103. $flat->getBuilding(),
  104. $options,
  105. $status
  106. );
  107. return [
  108. 'data' => $tasks,
  109. 'count' => $countTask
  110. ];
  111. }
  112. /**
  113. * @param Request $request
  114. * @param int $id
  115. * @param int $scope
  116. * @return array<string, mixed>
  117. * @throws NoResultException
  118. * @throws NonUniqueResultException
  119. */
  120. #[Rest\Get('/{scope}', name: 'residents_flats_problems_scope', requirements: ['scope' => '\d+'])]
  121. public function getResidentsFlatProblemsWithScope(Request $request, int $id, int $scope): array
  122. {
  123. $flat = $this->flatRepository->find($id);
  124. if (!$flat) {
  125. $this->createNotFoundException();
  126. }
  127. $this->denyAccessUnlessGranted(FlatVoter::FLAT_BELONGS_TO_RESIDENT, $flat);
  128. $options = $this->getListOptions($request);
  129. $status = $request->get('status');
  130. $tasks = $this->taskRepository->findTasksByFlatPaginated(
  131. $flat,
  132. $options,
  133. $scope,
  134. $status
  135. );
  136. $countTask = $this->taskRepository->countTasksByFlatPaginated(
  137. $flat,
  138. $scope,
  139. $status
  140. );
  141. return [
  142. 'data' => $tasks,
  143. 'count' => $countTask
  144. ];
  145. }
  146. /**
  147. * @param Request $request
  148. * @param int $id
  149. * @return array<mixed>
  150. * @throws Exception
  151. * @throws GuzzleException
  152. */
  153. #[Rest\Post('/', name: 'residents_flats_problems_store')]
  154. public function store(Request $request, int $id): array
  155. {
  156. $flat = $this->flatRepository->find($id);
  157. if (!$flat) {
  158. throw $this->createNotFoundException('Ovaj stan ne postoji.');
  159. }
  160. $this->denyAccessUnlessGranted(FlatVoter::FLAT_BELONGS_TO_RESIDENT, $flat);
  161. $building = $flat->getBuilding();
  162. $problemTypes = $this->taskTypeRepository->findAllTaskTypeIds();
  163. try {
  164. $problemData = $this->validateForm($request, BuildingProblemType::class, null, [
  165. 'types' => $problemTypes
  166. ]);
  167. $problemData['flatNumber'] = $flat->getDisplayFlatId();
  168. $problemData['email'] = $flat->getOwnerEmail();
  169. $problemData['phoneNumber'] = $flat->getOwnerContact();
  170. $problemData['resident'] = $this->getUser();
  171. $result = $this->taskService->saveTask(null, $building, $problemData);
  172. if (!($result instanceof Task)) {
  173. throw new HttpException($result['code'], $result['message']);
  174. }
  175. $this->notificationTokenService->sendPushNotificationAction($building, $problemData);
  176. $task = $result;
  177. /** @var array<UploadedFile> $uploadedTaskFiles */
  178. $uploadedTaskFiles = $request->files->get('file') ?? [];
  179. foreach ($uploadedTaskFiles as $uploadedTaskFile) {
  180. $originalFilename = pathinfo($uploadedTaskFile->getClientOriginalName(), PATHINFO_FILENAME);
  181. $safeFilename = transliterator_transliterate(
  182. 'Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()',
  183. $originalFilename
  184. );
  185. $newFilename = sprintf("%s-%s.%s", $safeFilename, uniqid(), $uploadedTaskFile->guessClientExtension());
  186. try {
  187. $uploadedTaskFile->move(
  188. $this->getParameter('tasks_files_directory'),
  189. $newFilename
  190. );
  191. } catch (FileException $fileException) {
  192. }
  193. $taskFile = $this->taskFileService->createTaskFile($newFilename, $task);
  194. $task->addFile($taskFile);
  195. $this->taskFileRepository->save($taskFile);
  196. }
  197. return [
  198. 'data' => $task
  199. ];
  200. } catch (FormException $exception) {
  201. return $exception->getFormError();
  202. }
  203. }
  204. /**
  205. * @param Request $request
  206. * @param int $id
  207. * @return array<mixed>
  208. * @throws Exception
  209. * @throws GuzzleException|TransportExceptionInterface
  210. */
  211. #[Rest\Post('/v3', name: 'residents_flats_problems_store_new')]
  212. public function storeNew(Request $request, int $id): array
  213. {
  214. $flat = $this->flatRepository->find($id);
  215. if (!$flat) {
  216. throw $this->createNotFoundException('Ovaj stan ne postoji.');
  217. }
  218. $this->denyAccessUnlessGranted(FlatVoter::FLAT_BELONGS_TO_RESIDENT, $flat);
  219. $building = $flat->getBuilding();
  220. $problemTypes = $this->taskTypeRepository->findAllTaskTypeIds();
  221. try {
  222. $problemData = $this->validateForm($request, BuildingProblemType::class, null, [
  223. 'types' => $problemTypes
  224. ]);
  225. $problemData['flatNumber'] = $flat->getDisplayFlatId();
  226. $problemData['email'] = $flat->getOwnerEmail();
  227. $problemData['resident'] = $this->getUser();
  228. $result = $this->taskService->saveTask(null, $building, $problemData);
  229. if (!($result instanceof Task)) {
  230. throw new HttpException($result['code'], $result['message']);
  231. }
  232. $this->notificationTokenService->sendPushNotificationAction($building, $problemData);
  233. $task = $result;
  234. $user = $this->userRepository->findOneBy(['id' => $flat->getUser()->getId()]);
  235. /** @var UploadedFile|null $uploadedTaskFile */
  236. $uploadedTaskFile = $request->files->get('file') ?? [];
  237. $newFilename = null;
  238. $route = null;
  239. if (!empty($uploadedTaskFile)) {
  240. try {
  241. $originalFilename = pathinfo($uploadedTaskFile->getClientOriginalName(), PATHINFO_FILENAME);
  242. $safeFilename = transliterator_transliterate(
  243. 'Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()',
  244. $originalFilename
  245. );
  246. $newFilename = sprintf(
  247. "%s-%s.%s",
  248. $safeFilename,
  249. uniqid(),
  250. $uploadedTaskFile->guessClientExtension()
  251. );
  252. list($w, $h) = getimagesize($uploadedTaskFile);
  253. $new_width = 735;
  254. $new_height = 1000;
  255. $dst = imagecreatetruecolor($new_width, $new_height);
  256. $src = imagecreatefromjpeg($uploadedTaskFile);
  257. imagecopyresampled($dst, $src, 0, 0, 0, 0, $new_width, $new_height, $w, $h);
  258. $path = sprintf("%s/src/uploads/residentProblems/%s", $this->projectDir, $building->getId());
  259. if (!is_dir($path)) {
  260. mkdir($path, 0777, true);
  261. }
  262. $path = sprintf("%s/%s", $path, $newFilename);
  263. imagejpeg($dst, $path);
  264. $route = sprintf(
  265. "%s%s/%s",
  266. $this->getParameter('tasks_files_directory'),
  267. $building->getId(),
  268. $newFilename
  269. );
  270. $taskFile = $this->taskFileService->createTaskFile($newFilename, $task);
  271. $task->addFile($taskFile);
  272. $this->taskFileRepository->save($taskFile);
  273. } catch (Exception $fileException) {
  274. throw new Exception($fileException->getMessage());
  275. }
  276. }
  277. $subject = 'Prijava problema';
  278. if ($user->getTaskNotificationEmail()) {
  279. $recipient = $user->getTaskNotificationEmail();
  280. } else {
  281. $mainUser = $user->getMainUser();
  282. if ($mainUser === null) {
  283. $recipient = $user->getEmail();
  284. } elseif ($mainUser->getTaskNotificationEmail()) {
  285. $recipient = $mainUser->getTaskNotificationEmail();
  286. } else {
  287. $recipient = $user->getEmail();
  288. }
  289. }
  290. $text = sprintf(
  291. "Poštovani,<br><br>Prijavljen problem za zgradu %s<br>Tip problema: %s<br>Opis problema: %s<br>
  292. Broj stana koji je prijavio problem: %s<br>Broj telefona stanara: %s<br><br>Srdačan pozdrav.",
  293. $building->getAddress(),
  294. $result->getTaskType()->getName(),
  295. $result->getDescription(),
  296. $result->getDisplayFlatId(),
  297. $result->getPhoneNumber()
  298. );
  299. $this->mailService->sendEmail(
  300. $subject,
  301. [$recipient],
  302. null,
  303. $text,
  304. [],
  305. $newFilename == null ? null : AttachmentTypeEnum::FROM_PATH->value,
  306. $route,
  307. $newFilename,
  308. null,
  309. true
  310. );
  311. return [
  312. 'data' => $task,
  313. 'code' => 200
  314. ];
  315. } catch (FormException $exception) {
  316. return $exception->getFormError();
  317. }
  318. }
  319. /**
  320. * @return array<TaskType>
  321. */
  322. #[Rest\Get('/types', name: 'residents_flats_problems_types')]
  323. public function getProblemTypes(): array
  324. {
  325. $types = $this->taskTypeRepository->findAll();
  326. return [
  327. 'data' => $types
  328. ];
  329. }
  330. }