src/EventListener/OneupUploadListener.php line 235

Open in your IDE?
  1. <?php
  2. namespace MedBrief\MSR\EventListener;
  3. use DateTime;
  4. use Doctrine\ORM\EntityManagerInterface;
  5. use Doctrine\ORM\OptimisticLockException;
  6. use Exception;
  7. use MedBrief\MSR\Entity\BatchDocument;
  8. use MedBrief\MSR\Entity\BatchRequest;
  9. use MedBrief\MSR\Entity\Collection;
  10. use MedBrief\MSR\Entity\Disc;
  11. use MedBrief\MSR\Entity\Document;
  12. use MedBrief\MSR\Entity\ProjectUser;
  13. use MedBrief\MSR\Entity\User;
  14. use MedBrief\MSR\Repository\BatchRequestRepository;
  15. use MedBrief\MSR\Repository\CollectionRepository;
  16. use MedBrief\MSR\Service\ArchiveProcessor\BatchDocumentArchiveProcessorService;
  17. use MedBrief\MSR\Service\ArchiveProcessor\MedicalRecordArchiveProcessorService;
  18. use MedBrief\MSR\Service\FilesizeHelperService;
  19. use MedBrief\MSR\Service\Notification\UserNotificationService;
  20. use MedBrief\MSR\Service\VirusScan\VirusScannerService;
  21. use Oneup\UploaderBundle\Event\PostPersistEvent;
  22. use Oneup\UploaderBundle\Event\PreUploadEvent;
  23. use Oneup\UploaderBundle\Event\ValidationEvent;
  24. use Oneup\UploaderBundle\Uploader\Exception\ValidationException;
  25. use RuntimeException;
  26. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  27. use Symfony\Component\HttpFoundation\File\File;
  28. use Symfony\Component\HttpFoundation\File\UploadedFile;
  29. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  30. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  31. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  32. /**
  33. * Listener responsible for taking uploaded Archive files and assigning them to
  34. * the appropriate Disc. The setup of this Listener is described in the
  35. * OneupUploaderBundle documentation
  36. * Listener responsible for handling custom processing for all files uploaded
  37. * via Oneup uploader. Implemented as per:
  38. * https://github.com/1up-lab/OneupUploaderBundle/blob/master/Resources/doc/custom_logic.md
  39. */
  40. class OneupUploadListener
  41. {
  42. /**
  43. * @var TokenStorageInterface
  44. */
  45. public $securityToken;
  46. /**
  47. * @var EntityManagerInterface
  48. */
  49. public $em;
  50. /**
  51. * @var VirusScannerService|object|null
  52. */
  53. public $virusScanner;
  54. // accepted mimetypes
  55. // Alphabetized and trimmed this because it would have been wasting resources when we do checks with it - Stuart
  56. private array $avMimeTypes = [
  57. 'audio/aiff',
  58. 'audio/amr',
  59. 'audio/basic',
  60. 'audio/it',
  61. 'audio/m4a',
  62. 'audio/make',
  63. 'audio/make.my.funk',
  64. 'audio/mid',
  65. 'audio/midi',
  66. 'audio/mod',
  67. 'audio/mp3',
  68. 'audio/mpeg',
  69. 'audio/mpeg3',
  70. 'audio/nspaudio',
  71. 'audio/s3m',
  72. 'audio/tsp-audio',
  73. 'audio/tsplayer',
  74. 'audio/vnd.qcelp',
  75. 'audio/voc',
  76. 'audio/voxware',
  77. 'audio/wav',
  78. 'audio/wma',
  79. 'audio/x-adpcm',
  80. 'audio/x-aiff',
  81. 'audio/x-au',
  82. 'audio/x-gsm',
  83. 'audio/x-jam',
  84. 'audio/x-liveaudio',
  85. 'audio/x-mid',
  86. 'audio/x-midi',
  87. 'audio/x-mod',
  88. 'audio/x-mpeg',
  89. 'audio/x-mpeg-3',
  90. 'audio/x-mpequrl',
  91. 'audio/x-nspaudio',
  92. 'audio/x-pn-realaudio',
  93. 'audio/x-pn-realaudio-plugin',
  94. 'audio/x-psid',
  95. 'audio/x-realaudio',
  96. 'audio/x-twinvq',
  97. 'audio/x-twinvq-plugin',
  98. 'audio/x-vnd.audioexplosion.mjuicemediafile',
  99. 'audio/x-voc',
  100. 'audio/x-wav',
  101. 'audio/xm',
  102. 'music/crescendo',
  103. 'music/x-karaoke',
  104. 'video/3gp',
  105. 'video/animaflex',
  106. 'video/avi',
  107. 'video/avs-video',
  108. 'video/dl',
  109. 'video/fli',
  110. 'video/flv',
  111. 'video/gl',
  112. 'video/m4v',
  113. 'video/mov',
  114. 'video/mp4',
  115. 'video/mpeg',
  116. 'video/mpg',
  117. 'video/msvideo',
  118. 'video/quicktime',
  119. 'video/vdo',
  120. 'video/vivo',
  121. 'video/vnd.rn-realvideo',
  122. 'video/vnd.vivo',
  123. 'video/vosaic',
  124. 'video/wmv',
  125. 'video/x-amt-demorun',
  126. 'video/x-amt-showrun',
  127. 'video/x-atomic3d-feature',
  128. 'video/x-dl',
  129. 'video/x-dv',
  130. 'video/x-fli',
  131. 'video/x-gl',
  132. 'video/x-isvideo',
  133. 'video/x-matroska',
  134. 'video/x-motion-jpeg',
  135. 'video/x-mpeg',
  136. 'video/x-mpeq2a',
  137. 'video/x-ms-asf',
  138. 'video/x-ms-asf-plugin',
  139. 'video/x-msvideo',
  140. 'video/x-qtc',
  141. 'video/x-scm',
  142. 'video/x-sgi-movie',
  143. 'video/x-ms-dvr',
  144. ];
  145. // Accepted document types
  146. // Adding this here because the above was just gross! - Stuart
  147. private array $documentMimeTypes = [
  148. 'application/msword',
  149. 'application/pdf',
  150. 'application/vnd.ms-excel',
  151. 'application/vnd.ms-office',
  152. 'application/vnd.ms-powerpoint',
  153. 'application/vnd.oasis.opendocument.spreadsheet',
  154. 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  155. 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  156. 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  157. 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  158. 'application/x-pdf',
  159. 'application/encrypted',
  160. ];
  161. // Accepted archive mime types
  162. private array $archiveMimeTypes = [
  163. 'application/x-7z-compressed',
  164. 'application/zip',
  165. // 'application/x-rar', We currently don't support RAR file uploads
  166. ];
  167. // Accepted image mime types
  168. private array $imageMimeTypes = [
  169. 'image/bmp',
  170. 'image/x-windows-bmp',
  171. 'image/gif',
  172. 'image/jpeg',
  173. 'image/png',
  174. 'image/tiff',
  175. 'image/x-tiff',
  176. 'image/jpg',
  177. ];
  178. // Accepted text or html mime types
  179. private array $textOrHtmlMimeTypes = [
  180. 'text/html',
  181. 'text/htm',
  182. 'text/plain',
  183. ];
  184. // Accepted eml or msg mime types
  185. private array $emlOrMsgMimeTypes = [
  186. 'message/rfc822',
  187. 'application/vnd.ms-outlook',
  188. 'application/octet-stream',
  189. ];
  190. private readonly CollectionRepository $collectionRepository;
  191. private readonly BatchRequestRepository $batchRequestRepository;
  192. public function __construct(
  193. EntityManagerInterface $doctrine,
  194. TokenStorageInterface $securityToken,
  195. VirusScannerService $virusScanner,
  196. private readonly MedicalRecordArchiveProcessorService $medicalRecordsArchiveProcessor,
  197. private readonly FilesizeHelperService $filesizeHelper,
  198. private readonly UserNotificationService $userNotificationService,
  199. private readonly BatchDocumentArchiveProcessorService $batchDocumentArchiveProcessor,
  200. EventDispatcherInterface $eventDispatcher,
  201. private readonly AuthorizationCheckerInterface $authorizationChecker,
  202. private readonly string $maxFileSize
  203. ) {
  204. $this->em = $doctrine;
  205. $this->securityToken = $securityToken;
  206. $this->virusScanner = $virusScanner;
  207. $this->collectionRepository = $this->em->getRepository(Collection::class);
  208. $this->batchRequestRepository = $this->em->getRepository(BatchRequest::class);
  209. }
  210. /**
  211. * This function is fired prior to the upload doing some stuff.
  212. *
  213. *
  214. *
  215. *
  216. * @param PreUploadEvent $event
  217. *
  218. * @throws Exception
  219. */
  220. public function preUpload(PreUploadEvent $event): void
  221. {
  222. // we grab the mapping, then based on the value we invoke the
  223. // appropriate logic
  224. $mapping = $event->getType();
  225. if ($mapping === 'discArchive') {
  226. $this->preUploadDiscArchive($event);
  227. return;
  228. }
  229. if ($mapping === 'medicalRecord') {
  230. $this->preUploadMedicalRecord($event);
  231. return;
  232. }
  233. if ($mapping === 'batchDocument') {
  234. $this->preUploadMedicalRecord($event);
  235. return;
  236. }
  237. // This listener does not handle this type of file upload
  238. }
  239. /**
  240. * Handle some pre upload processing for a zip archive uploaded to a disc
  241. *
  242. *
  243. *
  244. * @param PreUploadEvent $event
  245. *
  246. * @throws OptimisticLockException
  247. */
  248. public function preUploadDiscArchive(PreUploadEvent $event): void
  249. {
  250. $request = $event->getRequest();
  251. $uploadedFile = $event->getFile();
  252. // grab the original filename of the uploaded file
  253. $uploadName = $uploadedFile->getClientOriginalName();
  254. // Strip the UUID
  255. $strippedName = preg_filter('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}_/i', '', (string) $uploadName);
  256. // If we have a string, use it, otherwise fall back to the uploaded filename
  257. $originalFilename = $strippedName ?: $uploadName;
  258. // set the original filename on the request, so we can use it in the onUpload post hook
  259. $request->request->set('originalFilename', $originalFilename);
  260. // grab the discID
  261. $discId = $request->get('discId');
  262. if (!$discId) {
  263. throw new RuntimeException('Disc id is required.');
  264. }
  265. // grab the disc
  266. /** @var Disc $disc */
  267. $disc = $this->em->getRepository(Disc::class)->findOneById($discId);
  268. if (!($disc instanceof Disc)) {
  269. throw new RuntimeException('Disc id is required.');
  270. }
  271. // Check if the user is authorized to upload this disc
  272. if ($this->authorizationChecker->isGranted('RADIOLOGY_ADMINISTRATION', $disc) === false && $this->authorizationChecker->isGranted('ADMINISTRATION', $disc) === false) {
  273. throw new AccessDeniedException('User does not have permission to upload this disc.');
  274. }
  275. // set the original archive name on the disc - we need to do this because
  276. // the vich uploader doesnt keep track or the original filename
  277. $disc->setArchiveOriginalName($originalFilename);
  278. $this->em->persist($disc);
  279. $this->em->flush();
  280. }
  281. /**
  282. * Handle some preprocessing for medical record PDF's uploaded to a collection
  283. *
  284. * @param PreUploadEvent $event
  285. */
  286. public function preUploadMedicalRecord(PreUploadEvent $event): void
  287. {
  288. $request = $event->getRequest();
  289. $uploadedFile = $event->getFile();
  290. $collectionId = $request->get('collectionId');
  291. if ($collectionId) {
  292. $collection = $this->collectionRepository->find($collectionId);
  293. if ($collection === null) {
  294. throw new RuntimeException('Collection not found');
  295. }
  296. if (
  297. $this->authorizationChecker->isGranted('MEDICAL_RECORDS_ADMINISTRATION', $collection->getProject()) === false
  298. && $this->authorizationChecker->isGranted('UPDATE', $collection) === false) {
  299. throw new AccessDeniedException('User does not have permissions to upload to this collection.');
  300. }
  301. }
  302. $batchRequestId = $request->get('batchRequestId');
  303. if ($batchRequestId) {
  304. $batchRequest = $this->batchRequestRepository->find($batchRequestId);
  305. if ($batchRequest === null) {
  306. throw new RuntimeException('BatchRequest not found');
  307. }
  308. if ($this->authorizationChecker->isGranted('UPLOAD_DOCUMENT', $batchRequest) === false) {
  309. throw new AccessDeniedException('User does not have permissions to upload to this batch request.');
  310. }
  311. }
  312. // grab the original filename of the uploaded file
  313. $uploadName = $uploadedFile->getClientOriginalName();
  314. // Strip the UUID
  315. $strippedName = preg_filter('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}_/i', '', (string) $uploadName);
  316. // If we have a string, use it, otherwise fall back to the uploaded filename
  317. $originalFilename = $strippedName ?: $uploadName;
  318. // set the original filename on the request, so we can use it in the onUpload post hook
  319. $request->request->set('originalFilename', $originalFilename);
  320. }
  321. /**
  322. * @todo Ensure that this method is secure I.E. only users with appropriate
  323. * authorization are able to upload disc archives.
  324. * After a Zip archive has been successfully uploaded for a disc, we assign
  325. * it to the Disc and update the status of the disk
  326. *
  327. * @param PostPersistEvent $event
  328. *
  329. * @throws Exception
  330. */
  331. public function onUpload(PostPersistEvent $event): void
  332. {
  333. // grab the request so we can get the original file name
  334. $request = $event->getRequest();
  335. // prep an array that we will return
  336. /** @var File $file */
  337. $file = $event->getFile();
  338. $fileResponse = [
  339. 'name' => $request->get('originalFilename'),
  340. 'size' => $file->getSize(),
  341. ];
  342. // we grab the mapping, then based on the value we invoke the
  343. // appropriate logic
  344. $mapping = $event->getType();
  345. // Only scan medical records on upload, discs are scanned offline to prevent delays for large uploads.
  346. if ($mapping === 'medicalRecord') {
  347. // Scan for viruses
  348. $virusScanResult = $this->virusScanner->scanFile($file->getRealPath());
  349. // Check if the file is infected. If the virus scan fails, the isFail flag will be true and logged.
  350. // We will need to check for failed virus scans, but not prevent the upload in this case.
  351. if ($virusScanResult->isInfected()) {
  352. $fileResponse['status'] = 'fail';
  353. $fileResponse['message'] = 'This file could be harmful to the system, and could not be uploaded. Please contact your MedBrief system administrator.';
  354. unlink($file->getRealPath());
  355. }
  356. }
  357. // If we already have a fileResponse status, the file has been set to fail
  358. // by the virus scanner, and we don't want to process the file.
  359. if (!isset($fileResponse['status'])) {
  360. if ($mapping === 'discArchive') {
  361. // At the moment we don't do any mimetype checking on zip files, but we should
  362. $this->onUploadDiscArchive($event);
  363. $fileResponse['status'] = 'success';
  364. $fileResponse['message'] = 'Uploaded';
  365. } elseif ($mapping === 'medicalRecord') {
  366. // If the file uploaded is a zip archive, we process the the entire zip archive.
  367. if (in_array($file->getMimeType(), $this->archiveMimeTypes)) {
  368. if ($this->onUploadMedicalRecordArchive($event)) {
  369. $fileResponse['status'] = 'success';
  370. $fileResponse['message'] = 'Uploaded';
  371. // We gots to do a bit here to get the right stuff for sending a notification
  372. // @todo: make this a function
  373. $uploadingUser = $this->securityToken->getToken()->getUser();
  374. $collectionId = $request->get('collectionId');
  375. /** @var Collection $collection */
  376. $collection = $this->em->getRepository(Collection::class)->findOneById($collectionId);
  377. $project = $collection->getProject();
  378. $projectUser = $this->em->getRepository(ProjectUser::class)
  379. ->findOneBy([
  380. 'project' => $project,
  381. 'user' => $uploadingUser,
  382. ])
  383. ;
  384. //checks if there is a project user and whether they have a private folder in the medical records page
  385. if ($projectUser && $projectUser->getPrivateSandboxCollection() && $projectUser->getPrivateSandboxCollection()->containsCollectionRecursive($collection)) {
  386. $this->userNotificationService->generateFileUploadByUserNotification($project, $uploadingUser);
  387. }
  388. } else {
  389. $fileResponse['status'] = 'fail';
  390. if ($this->medicalRecordsArchiveProcessor->hasError()) {
  391. $fileResponse['message'] = $this->medicalRecordsArchiveProcessor->getError();
  392. } else {
  393. $fileResponse['message'] = 'There was a problem processing the ZIP file you uploaded.';
  394. }
  395. unlink($file->getRealPath());
  396. }
  397. } elseif (in_array($file->getMimeType(), $this->getMedicalRecordsMimeTypes())) {
  398. // Also accepting the file if the mimetype appears in our accepted mimetypes
  399. $this->onUploadMedicalRecord($event);
  400. $fileResponse['status'] = 'success';
  401. $fileResponse['message'] = 'Uploaded';
  402. } else {
  403. $fileResponse['status'] = 'fail';
  404. $fileResponse['message'] = 'This file format is not supported. (File type detected: ' . $file->getMimeType() . ')';
  405. unlink($file->getRealPath());
  406. }
  407. } elseif ($mapping === 'batchDocument') {
  408. // If the file uploaded is a zip archive, we process the the entire zip archive.
  409. if (in_array($file->getMimeType(), $this->archiveMimeTypes)) {
  410. if ($this->onUploadBatchDocumentArchive($event)) {
  411. $fileResponse['status'] = 'success';
  412. $fileResponse['message'] = 'Uploaded';
  413. } else {
  414. $fileResponse['status'] = 'fail';
  415. if ($this->batchDocumentArchiveProcessor->hasError()) {
  416. $fileResponse['message'] = $this->batchDocumentArchiveProcessor->getError();
  417. } else {
  418. $fileResponse['message'] = 'There was a problem processing the ZIP file you uploaded.';
  419. }
  420. unlink($file->getRealPath());
  421. }
  422. } elseif (in_array($file->getMimeType(), $this->getBatchDocumentsMimeTypes())) {
  423. // Also accepting the file if the mimetype appears in our accepted mimetypes
  424. $this->onUploadBatchDocument($event);
  425. $fileResponse['status'] = 'success';
  426. $fileResponse['message'] = 'Uploaded';
  427. } else {
  428. $fileResponse['status'] = 'fail';
  429. $fileResponse['message'] = 'File is not a valid document or image file. (File type detected: ' . $file->getMimeType() . ')';
  430. unlink($file->getRealPath());
  431. }
  432. } else {
  433. // This listener does not handle this type of file upload
  434. $fileResponse['status'] = 'fail';
  435. $fileResponse['message'] = 'File is not a valid PDF, audio, video or supported zip file. (File type detected: ' . $file->getMimeType() . ')';
  436. unlink($file->getRealPath());
  437. }
  438. }
  439. // Ensuring some JSON data is returned for each file upload call
  440. // as per: https://github.com/1up-lab/OneupUploaderBundle/issues/42
  441. // Note we should do this before any logic that will remove this file
  442. $response = $event->getResponse();
  443. $response['files'] = [$fileResponse];
  444. }
  445. /**
  446. * Handle some post processing on zip archive uploaded to a disc
  447. *
  448. *
  449. *
  450. * @param PostPersistEvent $event
  451. *
  452. * @throws OptimisticLockException
  453. */
  454. public function onUploadDiscArchive(PostPersistEvent $event): void
  455. {
  456. $request = $event->getRequest();
  457. $discId = $request->get('discId');
  458. // grab the original filename of the uploaded file
  459. $originalFilename = $request->get('originalFilename');
  460. // @todo Fail if no Original filename
  461. if (!$discId) {
  462. // @todo throw an error that disc id is required
  463. }
  464. // get the symfony File
  465. /** @var File $uploadedFile */
  466. $uploadedFile = $event->getFile();
  467. // @todo throw an error if this is not a file
  468. // find the disc
  469. /** @var Disc $disc */
  470. $disc = $this->em->getRepository(Disc::class)->findOneById($discId);
  471. // @todo throw an error if we cannot find a disc
  472. // create a new file to inject into the Disc
  473. $fileToInject = new UploadedFile(
  474. $uploadedFile->getRealPath(),
  475. $originalFilename,
  476. $uploadedFile->getMimeType(),
  477. $uploadedFile->getSize(),
  478. UPLOAD_ERR_OK,
  479. false
  480. );
  481. $disc->setArchiveFile($fileToInject);
  482. $disc->setUpdated(new DateTime('now')); // Rowan we only do this because we used to do it in the setArchiveFile() method, but now we dont.
  483. $disc->setStatus(Disc::STATUS_PENDING_PROCESSING); // update the disc stats to say it is pending processing
  484. // Use our filesize helper to determine the archive's filesize, as it handles
  485. // files > 2GB correctly.
  486. $archiveFilesize = $this->filesizeHelper->getFilesize($uploadedFile->getRealPath());
  487. if ($archiveFilesize) {
  488. $disc->setArchiveFilesize($archiveFilesize);
  489. }
  490. $this->em->persist($disc);
  491. $this->em->flush();
  492. // get rid of the original file provided that the injection went ok
  493. unlink($uploadedFile->getRealPath());
  494. }
  495. /**
  496. * Handles the upload of a single medical records file.
  497. *
  498. *
  499. *
  500. * @param PostPersistEvent $event
  501. *
  502. * @throws OptimisticLockException
  503. * @throws Exception
  504. */
  505. public function onUploadMedicalRecord(PostPersistEvent $event): void
  506. {
  507. $request = $event->getRequest();
  508. $collectionId = $request->get('collectionId');
  509. // grab the original filename of the uploaded file
  510. $originalFilename = $request->get('originalFilename');
  511. if (!$collectionId || empty($originalFilename)) {
  512. throw new Exception('Collection or Filename not found for uploaded file');
  513. }
  514. // get the symfony File
  515. $uploadedFile = $event->getFile();
  516. // @todo throw an error if this is not a file
  517. // find the collection
  518. $collection = $this->em->getRepository(Collection::class)->findOneById($collectionId);
  519. // @todo: We need to update the below because of SecurityContext being deprecated
  520. // Let's grab the uploading user to a) set as the document creator and b) we need to see if they are uploading
  521. // to their own folder.
  522. $uploadingUser = $this->securityToken->getToken()->getUser();
  523. $document = $this->medicalRecordsArchiveProcessor->createDocument(
  524. $originalFilename,
  525. $uploadedFile,
  526. $collection,
  527. $uploadingUser
  528. );
  529. $project = $document->getProject();
  530. $projectUser = $this->em->getRepository(ProjectUser::class)
  531. ->findOneBy([
  532. 'project' => $project,
  533. 'user' => $uploadingUser,
  534. ])
  535. ;
  536. if ($projectUser && $projectUser->getPrivateSandboxCollection()->containsDocumentRecursive($document)) {
  537. $this->userNotificationService->generateFileUploadByUserNotification($project, $uploadingUser);
  538. }
  539. }
  540. /**
  541. * Handles the upload of a Medical Record Zip archive
  542. *
  543. *
  544. *
  545. *
  546. * @param PostPersistEvent $event
  547. *
  548. * @throws Exception
  549. */
  550. public function onUploadMedicalRecordArchive(PostPersistEvent $event): bool
  551. {
  552. $request = $event->getRequest();
  553. $collectionId = $request->get('collectionId');
  554. $originalFilename = $request->get('originalFilename');
  555. if (!$collectionId || empty($originalFilename)) {
  556. throw new Exception('Collection or Filename not found for uploaded file');
  557. }
  558. // Get the collection we are uploading to
  559. $collection = $this->em->getRepository(Collection::class)->findOneById($collectionId);
  560. // Process the zip archive
  561. // !NB! We don't create activity feed items for Documents created via zip archive upload
  562. // as activity feed functionality will be removed in a future release.
  563. return $this->medicalRecordsArchiveProcessor->processArchive(
  564. $event->getFile(),
  565. $collection,
  566. $this->securityToken->getToken()->getUser(),
  567. $this->getMedicalRecordsMimeTypes()
  568. );
  569. }
  570. /**
  571. * Handles the upload of BatchDocument
  572. *
  573. *
  574. *
  575. *
  576. * @param PostPersistEvent $event
  577. *
  578. * @throws Exception
  579. */
  580. public function onUploadBatchDocument(PostPersistEvent $event): bool
  581. {
  582. $request = $event->getRequest();
  583. $batchRequestId = $request->get('batchRequestId');
  584. $batchRequest = $this->em->getRepository(BatchRequest::class)->find($batchRequestId);
  585. // grab the original filename of the uploaded file
  586. $originalFilename = $request->get('originalFilename');
  587. if (empty($originalFilename)) {
  588. throw new Exception('Collection or Filename not found for uploaded file');
  589. }
  590. // get the symfony File
  591. $uploadedFile = $event->getFile();
  592. $batchDocument = new BatchDocument();
  593. $document = $this->medicalRecordsArchiveProcessor->createDocument(
  594. $originalFilename,
  595. $uploadedFile,
  596. null,
  597. $this->securityToken->getToken()->getUser(),
  598. $batchRequest->getProject(),
  599. true
  600. );
  601. $batchDocument->setDocument($document);
  602. $batchDocument->setBatchRequest($batchRequest);
  603. $this->em->persist($batchDocument);
  604. $this->em->flush();
  605. return true;
  606. }
  607. /**
  608. * Handles the upload of a Batch Document Zip archive
  609. *
  610. *
  611. *
  612. *
  613. * @param PostPersistEvent $event
  614. *
  615. * @throws Exception
  616. */
  617. public function onUploadBatchDocumentArchive(PostPersistEvent $event): bool
  618. {
  619. $request = $event->getRequest();
  620. $batchRequestId = $request->get('batchRequestId');
  621. $batchRequest = $this->em->getRepository(BatchRequest::class)->find($batchRequestId);
  622. $originalFilename = $request->get('originalFilename');
  623. if (empty($originalFilename)) {
  624. throw new Exception('Collection or Filename not found for uploaded file');
  625. }
  626. // Process the zip archive
  627. return $this->batchDocumentArchiveProcessor->processArchive(
  628. $event->getFile(),
  629. $this->securityToken->getToken()->getUser(),
  630. $this->getBatchDocumentsMimeTypes(),
  631. $batchRequest
  632. );
  633. }
  634. /**
  635. * This function is fired prior to the upload doing some stuff.
  636. *
  637. * @param ValidationEvent $event
  638. */
  639. public function onValidate(ValidationEvent $event): void
  640. {
  641. $event->getConfig();
  642. $file = $event->getFile();
  643. $event->getType();
  644. $event->getRequest();
  645. // check if the file has a valid size
  646. $maxFileSize = $this->maxFileSize;
  647. if ($file->getSize() > $maxFileSize) {
  648. throw new ValidationException('medbrief.maxsize:' . $file->getClientOriginalName());
  649. }
  650. }
  651. /**
  652. * Returns an array of all the Mime Types accepted for Medical Record uploads
  653. */
  654. private function getMedicalRecordsMimeTypes(): array
  655. {
  656. return array_merge($this->avMimeTypes, $this->documentMimeTypes, $this->imageMimeTypes, $this->textOrHtmlMimeTypes, $this->emlOrMsgMimeTypes);
  657. }
  658. /**
  659. * Returns an array of all the Mime Types accepted for Batch Document uploads
  660. */
  661. private function getBatchDocumentsMimeTypes(): array
  662. {
  663. return array_merge($this->documentMimeTypes, $this->imageMimeTypes);
  664. }
  665. }