src/Security/Voter/ProjectVoter.php line 20

Open in your IDE?
  1. <?php
  2. namespace MedBrief\MSR\Security\Voter;
  3. use InvalidArgumentException;
  4. use MedBrief\MSR\Entity\Account;
  5. use MedBrief\MSR\Entity\Firm;
  6. use MedBrief\MSR\Entity\InterpartyDisclosure;
  7. use MedBrief\MSR\Entity\Project;
  8. use MedBrief\MSR\Entity\User;
  9. use MedBrief\MSR\Service\EntityHelper\UserHelper;
  10. use MedBrief\MSR\Service\Role\RoleParserService;
  11. use MedBrief\MSR\Traits\Security\Authorization\Voter\ClientSortingSessionTrait;
  12. use Override;
  13. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  14. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  15. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  16. use Symfony\Component\Security\Core\User\UserInterface;
  17. class ProjectVoter implements VoterInterface
  18. {
  19. use ClientSortingSessionTrait;
  20. // CONSTANTS
  21. public const CREATE = 'CREATE';
  22. public const READ = 'READ';
  23. public const UPDATE = 'UPDATE';
  24. public const DELETE = 'DELETE';
  25. public const ADMINISTRATION = 'ADMINISTRATION';
  26. public const MEDICAL_RECORDS_ADMINISTRATION = 'MEDICAL_RECORDS_ADMINISTRATION';
  27. public const RADIOLOGY_ADMINISTRATION = 'RADIOLOGY_ADMINISTRATION';
  28. // Determines if a user may view the "File details" panel for a project document.
  29. // Matter-level Expert, Expert - View Only, Scanner and Scanner - Download Enabled roles are excluded.
  30. public const VIEW_FILE_DETAILS = 'VIEW_FILE_DETAILS';
  31. public const USER_ADMINISTRATION = 'USER_ADMINISTRATION';
  32. public const CLINICAL_SUMMARY_PROJECT_ADMINISTRATION = 'CLINICAL_SUMMARY_PROJECT_ADMINISTRATION';
  33. public const PROJECT_USER_LIST = 'PROJECT_USER_LIST';
  34. public const VIEW_DASHBOARD = 'VIEW_DASHBOARD';
  35. public const TOGGLE_STATUS = 'TOGGLE_STATUS';
  36. public const ARCHIVE = 'ARCHIVE';
  37. public const CANCEL_DELETE = 'CANCEL_DELETE';
  38. public const RADIOLOGY_DOWNLOAD = 'RADIOLOGY_DOWNLOAD';
  39. public const RADIOLOGY_DOWNLOAD_AUDIT_REPORT = 'RADIOLOGY_DOWNLOAD_AUDIT_REPORT';
  40. public const MEDICAL_RECORD_DOWNLOAD = 'MEDICAL_RECORD_DOWNLOAD';
  41. public const DELETION_REPORT_DOWNLOAD = 'DELETION_REPORT_DOWNLOAD';
  42. public const INTERNAL_USER_ACCESS_REPORT_DOWNLOAD = 'INTERNAL_USER_ACCESS_REPORT_DOWNLOAD';
  43. public const CHRONOLOGY_ADMINISTRATION = 'CHRONOLOGY_ADMINISTRATION';
  44. // This permission determines if a user sees an inactive notice message
  45. // when an inactive Project is accessed.
  46. public const BYPASS_INACTIVE_NOTICE = 'BYPASS_INACTIVE_NOTICE';
  47. // This permission determines if a user can view a closed project
  48. public const BYPASS_CLOSED_NOTICE = 'BYPASS_CLOSED_NOTICE';
  49. // Keep these permissions on a Project, as creating any of these
  50. // directly affects a Project.
  51. public const CREATE_BATCH_REQUEST = 'CREATE_BATCH_REQUEST';
  52. public const CREATE_BATCH_REQUEST_SIMPLE = 'CREATE_BATCH_REQUEST_SIMPLE';
  53. public const CREATE_CHRONOLOGY_REQUEST = 'CREATE_CHRONOLOGY_REQUEST';
  54. public const CREATE_ADDITIONAL_REQUEST = 'CREATE_ADDITIONAL_REQUEST';
  55. // Sorting Session
  56. public const SORTING_SESSION_LIST = 'SORTING_SESSION_LIST';
  57. public const CREATE_SORTING_SESSION = 'CREATE_SORTING_SESSION';
  58. public const CREATE_SORTING_SESSION_SIMPLE = 'CREATE_SORTING_SESSION_SIMPLE';
  59. // Creating a matter note
  60. public const CREATE_MATTER_NOTE = 'CREATE_MATTER_NOTE';
  61. // Allow list of matter notes
  62. public const LIST_MATTER_NOTES = 'LIST_MATTER_NOTES';
  63. // Allow view of matter communications
  64. public const VIEW_MATTER_COMMUNICATIONS = 'VIEW_MATTER_COMMUNICATIONS';
  65. // Disclosure permissions
  66. public const MEDICAL_RECORDS_DISCLOSE = 'MEDICAL_RECORDS_DISCLOSE';
  67. public const DISCLOSE_DISC = 'DISCLOSE_DISC';
  68. public const BYPASS_AUTHENTICATION = 'BYPASS_AUTHENTICATION';
  69. // Allows changing the account value of a Matter
  70. public const CHANGE_ACCOUNT = 'CHANGE_ACCOUNT';
  71. // Allows user to create a record request letter
  72. public const MANAGE_REQUEST_LETTERS = 'MANAGE_REQUEST_LETTERS';
  73. // Allows a user to see the 'Unsorted' records for a Project
  74. public const VIEW_UNSORTED_RECORDS = 'VIEW_UNSORTED_RECORDS';
  75. // Project Closure Permissions
  76. public const CREATE_PROJECT_CLOSURE = 'CREATE_PROJECT_CLOSURE';
  77. public const DOWNLOAD_ALL_PROJECT_FILES = 'DOWNLOAD_ALL_PROJECT_FILES';
  78. public const DOWNLOAD_PROJECT_CLOSURE_REPORT = 'DOWNLOAD_PROJECT_CLOSURE_REPORT';
  79. // Allows the user to see a modal showing important notes on the matter, if any.
  80. public const VIEW_IMPORTANT_NOTES = 'VIEW_IMPORTANT_NOTES';
  81. // Allows the user to see the service request requirement banners on the matter dashboard.
  82. public const VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS = 'VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS';
  83. // Inter-party Disclosure
  84. public const CREATE_INTERPARTY_DISCLOSURE = 'CREATE_INTERPARTY_DISCLOSURE';
  85. public const LIST_INTERPARTY_DISCLOSURE = 'LIST_INTERPARTY_DISCLOSURE';
  86. // Allows by passing the disabled state of service requests when a matter/project is closed or in the process of being closed.
  87. public const BYPASS_SERVICE_REQUEST_DISABLED = 'BYPASS_SERVICE_REQUEST_DISABLED';
  88. // Allows the user to download the 'user download medical records viewed report'
  89. public const VIEW_THIRD_PARTY_ACCESS_REPORT = 'VIEW_THIRD_PARTY_ACCESS_REPORT';
  90. public function __construct(private AuthorizationCheckerInterface $authorizationChecker, private UserHelper $userHelper)
  91. {
  92. }
  93. /**
  94. * Whether or not this User is allowed to perform specific actions on this Entity
  95. *
  96. * @param mixed $attribute
  97. */
  98. public function supportsAttribute(mixed $attribute): bool
  99. {
  100. return in_array($attribute, [
  101. self::CREATE,
  102. self::READ,
  103. self::UPDATE,
  104. self::DELETE,
  105. self::ADMINISTRATION,
  106. self::MEDICAL_RECORDS_ADMINISTRATION,
  107. self::RADIOLOGY_ADMINISTRATION,
  108. self::USER_ADMINISTRATION,
  109. self::VIEW_DASHBOARD,
  110. self::TOGGLE_STATUS,
  111. self::PROJECT_USER_LIST,
  112. self::RADIOLOGY_DOWNLOAD,
  113. self::RADIOLOGY_DOWNLOAD_AUDIT_REPORT,
  114. self::MEDICAL_RECORD_DOWNLOAD,
  115. self::DELETION_REPORT_DOWNLOAD,
  116. self::INTERNAL_USER_ACCESS_REPORT_DOWNLOAD,
  117. self::CHRONOLOGY_ADMINISTRATION,
  118. self::ARCHIVE,
  119. self::CANCEL_DELETE,
  120. self::BYPASS_INACTIVE_NOTICE,
  121. self::BYPASS_CLOSED_NOTICE,
  122. self::CREATE_BATCH_REQUEST,
  123. self::CREATE_BATCH_REQUEST_SIMPLE,
  124. self::CREATE_CHRONOLOGY_REQUEST,
  125. self::CREATE_ADDITIONAL_REQUEST,
  126. self::SORTING_SESSION_LIST,
  127. self::CREATE_SORTING_SESSION,
  128. self::CREATE_SORTING_SESSION_SIMPLE,
  129. self::CREATE_MATTER_NOTE,
  130. self::LIST_MATTER_NOTES,
  131. self::VIEW_MATTER_COMMUNICATIONS,
  132. self::MEDICAL_RECORDS_DISCLOSE,
  133. self::DISCLOSE_DISC,
  134. self::BYPASS_AUTHENTICATION,
  135. self::CHANGE_ACCOUNT,
  136. self::MANAGE_REQUEST_LETTERS,
  137. self::VIEW_UNSORTED_RECORDS,
  138. self::CREATE_PROJECT_CLOSURE,
  139. self::DOWNLOAD_ALL_PROJECT_FILES,
  140. self::DOWNLOAD_PROJECT_CLOSURE_REPORT,
  141. self::VIEW_IMPORTANT_NOTES,
  142. self::VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS,
  143. self::CREATE_INTERPARTY_DISCLOSURE,
  144. self::LIST_INTERPARTY_DISCLOSURE,
  145. self::BYPASS_SERVICE_REQUEST_DISABLED,
  146. self::VIEW_THIRD_PARTY_ACCESS_REPORT,
  147. self::CLINICAL_SUMMARY_PROJECT_ADMINISTRATION,
  148. self::VIEW_FILE_DETAILS,
  149. ]);
  150. }
  151. /**
  152. * Whether or not this is a supported Class
  153. *
  154. * @param string $class
  155. */
  156. public function supportsClass($class): bool
  157. {
  158. $supportedClass = Project::class;
  159. return $supportedClass === $class || is_subclass_of($class, $supportedClass);
  160. }
  161. /**
  162. * @param Project $entity
  163. *
  164. * @return int
  165. */
  166. #[Override]
  167. public function vote(TokenInterface $token, $entity, array $attributes)
  168. {
  169. /**
  170. * START: This is common code for all Voter::vote() methods
  171. */
  172. // check if class of this object is supported by this voter
  173. if (!$this->supportsClass($entity && !is_array($entity) ? $entity::class : '')) {
  174. return VoterInterface::ACCESS_ABSTAIN;
  175. }
  176. // check if the voter is used correct, only allow one attribute
  177. // this isn't a requirement, it's just one easy way for you to
  178. // design your voter
  179. if (1 !== count($attributes)) {
  180. throw new InvalidArgumentException(
  181. 'Only one attribute is allowed for medbrief Voters.'
  182. );
  183. }
  184. // set the attribute to check against
  185. $attribute = $attributes[0];
  186. // check if the given attribute is covered by this voter
  187. if (!$this->supportsAttribute($attribute)) {
  188. return VoterInterface::ACCESS_ABSTAIN;
  189. }
  190. // get current logged in user
  191. /** @var User $user */
  192. $user = $token->getUser();
  193. // make sure there is a user object (i.e. that the user is logged in)
  194. if (!$user instanceof UserInterface) {
  195. return VoterInterface::ACCESS_DENIED;
  196. }
  197. // Only allow Super Admins and Admins to change accounts
  198. if ($attribute === self::CHANGE_ACCOUNT && !$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  199. return VoterInterface::ACCESS_DENIED;
  200. }
  201. // Only allow Super Admins to delete a project
  202. if ($attribute === self::DELETE && !$this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN')) {
  203. return VoterInterface::ACCESS_DENIED;
  204. }
  205. // Only super admins can update service requests when the project is in a closed or closing state
  206. if ($attribute === self::BYPASS_SERVICE_REQUEST_DISABLED) {
  207. if ($this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN') === true) {
  208. return VoterInterface::ACCESS_GRANTED;
  209. }
  210. return VoterInterface::ACCESS_DENIED;
  211. }
  212. /**
  213. * Clinical Summary Access Control with project entity passed in as the subject
  214. *
  215. * We need to put this before we grant admin users rights to everything otherwise the
  216. * isCloseInProgressOrComplete check has no effect
  217. */
  218. if ($attribute === self::CLINICAL_SUMMARY_PROJECT_ADMINISTRATION) {
  219. if ($this->canAccessClinicalSummaryWizard($entity)) {
  220. return VoterInterface::ACCESS_GRANTED;
  221. }
  222. return VoterInterface::ACCESS_DENIED;
  223. }
  224. // Admin users can do everything
  225. if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  226. return VoterInterface::ACCESS_GRANTED;
  227. }
  228. /**
  229. * END: Common code for all Voter:vote() methods. Put custom logic below.
  230. */
  231. /**
  232. * API (Firm) Access Control
  233. */
  234. if ($user instanceof Firm) {
  235. // If the account that belongs to the project is allocated to the firm's client areas, allow everything.
  236. if ($entity->getAccount() instanceof Account && $user->getClientAreas()->contains($entity->getAccount()) === true) {
  237. return self::ACCESS_GRANTED;
  238. }
  239. return self::ACCESS_DENIED;
  240. }
  241. /**
  242. * Disclosure matter access control
  243. */
  244. // Grab all project levels roles related to this project.
  245. $allProjectRoles = RoleParserService::getAllRolesForProject($entity->getId());
  246. // Users that have been directly invited to the Disclosure will have permission granted
  247. $isDirectlyInvitedToDisclosureMatter = array_filter($allProjectRoles, fn ($role) => $this->authorizationChecker->isGranted($role)) !== [];
  248. // Check if the project is a disclosure, and exclude anyone who has been directly invited to the disclosure matter (i.e. those that were
  249. // added when creating the disclosure). Project level project managers of the original project will not have a project role on the disclosure target project.
  250. if ($entity->isTypeDisclosure() && $isDirectlyInvitedToDisclosureMatter === false) {
  251. $allowedAttributes = [
  252. self::READ,
  253. self::RADIOLOGY_DOWNLOAD,
  254. self::MEDICAL_RECORD_DOWNLOAD,
  255. self::BYPASS_INACTIVE_NOTICE,
  256. self::VIEW_THIRD_PARTY_ACCESS_REPORT,
  257. ];
  258. // Disclosure matters only allow certain actions for the those who can VIEW the source disclosure entity
  259. if (in_array($attribute, $allowedAttributes) && $entity->getDisclosureSources()->count() > 0) {
  260. // Grant access if the user has access to VIEW the original source disclosure (we take the latest one in the chain of sources)
  261. /** @var InterpartyDisclosure $disclosure */
  262. $disclosure = $entity->getDisclosureSources()->last();
  263. if ($this->authorizationChecker->isGranted(InterpartyDisclosureVoter::VIEW, $disclosure)) {
  264. return self::ACCESS_GRANTED;
  265. }
  266. }
  267. return self::ACCESS_DENIED;
  268. }
  269. //Checks if user can download radiology audit report
  270. if ($attribute === self::RADIOLOGY_DOWNLOAD_AUDIT_REPORT) {
  271. return $this->canRadiologyDownloadAuditReport($entity);
  272. }
  273. $this->userHelper->setUser($user);
  274. $denyAccess = [
  275. self::CREATE_SORTING_SESSION,
  276. self::LIST_MATTER_NOTES,
  277. self::CREATE_MATTER_NOTE,
  278. self::MEDICAL_RECORDS_DISCLOSE,
  279. self::DISCLOSE_DISC,
  280. self::VIEW_MATTER_COMMUNICATIONS,
  281. self::DELETION_REPORT_DOWNLOAD,
  282. self::INTERNAL_USER_ACCESS_REPORT_DOWNLOAD,
  283. self::MANAGE_REQUEST_LETTERS,
  284. self::DELETE,
  285. self::VIEW_IMPORTANT_NOTES,
  286. self::VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS,
  287. ];
  288. // Deny all other roles these permissions
  289. if (in_array($attribute, $denyAccess)) {
  290. return VoterInterface::ACCESS_DENIED;
  291. }
  292. // Permissions related to the creation and management of sorting sessions and batches.
  293. $attributeGroup = [
  294. self::CREATE_BATCH_REQUEST_SIMPLE,
  295. self::SORTING_SESSION_LIST,
  296. self::CREATE_SORTING_SESSION_SIMPLE,
  297. ];
  298. if (in_array($attribute, $attributeGroup)) {
  299. if ($this->hasClientSessionAccess($entity, $user)) {
  300. return VoterInterface::ACCESS_GRANTED;
  301. };
  302. return VoterInterface::ACCESS_DENIED;
  303. }
  304. // Deny all other roles from creating these ServiceRequests
  305. $serviceRequestCreateAttributes = [
  306. self::CREATE_BATCH_REQUEST,
  307. self::CREATE_CHRONOLOGY_REQUEST,
  308. self::CREATE_ADDITIONAL_REQUEST,
  309. ];
  310. if (in_array($attribute, $serviceRequestCreateAttributes)) {
  311. return VoterInterface::ACCESS_DENIED;
  312. }
  313. if ($attribute === self::VIEW_DASHBOARD && $user->getMatterDashboardEnabled()) {
  314. // then they have access to do anything
  315. return VoterInterface::ACCESS_GRANTED;
  316. }
  317. // if this user is a Super Administrator for the Account for which this Project belongs
  318. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_SUPERADMINISTRATOR')) {
  319. // then they have access to do anything, except delete.
  320. return VoterInterface::ACCESS_GRANTED;
  321. }
  322. // Otherwise if this user is a Client Administrator for the Account then they can
  323. // do everything else except for User Administration and Deletion.
  324. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_ADMINISTRATOR')) {
  325. // Commenting this out for now because Kennedy's actually need
  326. // regular Client Administrators to still have this access for now. - RR
  327. //if ($attribute != self::USER_ADMINISTRATION) {
  328. // then they have access
  329. return VoterInterface::ACCESS_GRANTED;
  330. //}
  331. }
  332. // if this user is a Sorter for the Account for which this Project belongs
  333. // if we are looking for access other than delete, full administration and user management abilities
  334. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_SORTER') && ($attribute != self::DELETE
  335. && $attribute != self::ADMINISTRATION
  336. && $attribute != self::PROJECT_USER_LIST
  337. && $attribute != self::USER_ADMINISTRATION
  338. && $attribute != self::CREATE_PROJECT_CLOSURE
  339. && $attribute != self::CANCEL_DELETE
  340. && $attribute != self::ARCHIVE
  341. && $attribute != self::DOWNLOAD_ALL_PROJECT_FILES
  342. && $attribute != self::DOWNLOAD_PROJECT_CLOSURE_REPORT
  343. && $attribute != self::CREATE_INTERPARTY_DISCLOSURE
  344. && $attribute != self::LIST_INTERPARTY_DISCLOSURE)) {
  345. // then account level sorters have this access
  346. return VoterInterface::ACCESS_GRANTED;
  347. }
  348. // if we are looking for any access other than delete and full administration.
  349. // Note: Project managers ARE allowed closure-related permissions (CREATE_PROJECT_CLOSURE,
  350. // CANCEL_DELETE, ARCHIVE, DOWNLOAD_ALL_PROJECT_FILES, DOWNLOAD_PROJECT_CLOSURE_REPORT)
  351. // to match client admin + super admin access. See MSR-5782.
  352. if ($attribute != self::DELETE
  353. && $attribute != self::ADMINISTRATION
  354. ) {
  355. // then project managers may do this
  356. if ($this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_PROJECTMANAGER')) {
  357. return VoterInterface::ACCESS_GRANTED;
  358. }
  359. // Grant project manager access to a Project's manager, which will likely be a
  360. // ACCOUNT_PROJECT_MANAGER
  361. if ($entity->getManager() && $entity->getManager()->getId() === $user->getId()) {
  362. return VoterInterface::ACCESS_GRANTED;
  363. }
  364. }
  365. // if we are looking for the medical records administration or radiology administration attribute
  366. if ($attribute == self::MEDICAL_RECORDS_ADMINISTRATION || $attribute == self::RADIOLOGY_ADMINISTRATION || $attribute === self::VIEW_UNSORTED_RECORDS) {
  367. // any of the following roles will grant access
  368. $allowedRoles = [
  369. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  370. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  371. 'ROLE_PROJECT_' . $entity->getId() . '_PROJECTMANAGER',
  372. ];
  373. // so if the user has any one of these
  374. foreach ($allowedRoles as $role) {
  375. if ($this->authorizationChecker->isGranted($role)) {
  376. // then they have access
  377. return VoterInterface::ACCESS_GRANTED;
  378. }
  379. }
  380. }
  381. // If the project allows experts to see the unsorted records, and the user has an export role on the project.
  382. if ($attribute === self::VIEW_UNSORTED_RECORDS && ($entity->getAllowExpertViewUnsortedRecords() === true
  383. && ($this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_EXPERT') || $this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_EXPERTVIEWER')))) {
  384. return VoterInterface::ACCESS_GRANTED;
  385. }
  386. // Certain roles will allow you to bypass the inactive notice on an inactive Project's related controller.
  387. if ($attribute == self::BYPASS_INACTIVE_NOTICE) {
  388. // any of the following roles will grant access
  389. $allowedRoles = [
  390. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  391. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  392. 'ROLE_PROJECT_' . $entity->getId() . '_PROJECTMANAGER',
  393. ];
  394. // so if the user has any one of these
  395. foreach ($allowedRoles as $role) {
  396. if ($this->authorizationChecker->isGranted($role)) {
  397. // then they have access
  398. return VoterInterface::ACCESS_GRANTED;
  399. }
  400. }
  401. }
  402. // Certain roles will allow you to bypass the closed notice on a closed Project's related controller.
  403. if ($attribute == self::BYPASS_CLOSED_NOTICE) {
  404. // any of the following roles will grant access
  405. $allowedRoles = [
  406. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  407. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  408. 'ROLE_PROJECT_' . $entity->getId() . '_PROJECTMANAGER',
  409. ];
  410. // so if the user has any one of these
  411. foreach ($allowedRoles as $role) {
  412. if ($this->authorizationChecker->isGranted($role)) {
  413. // then they have access
  414. return VoterInterface::ACCESS_GRANTED;
  415. }
  416. }
  417. }
  418. if ($attribute == self::RADIOLOGY_DOWNLOAD || $attribute == self::MEDICAL_RECORD_DOWNLOAD) {
  419. // Experts may do this, but EXPERTVIEWER's may not
  420. if ($this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_EXPERT')) {
  421. return VoterInterface::ACCESS_GRANTED;
  422. }
  423. // Scanner - Download Enabled may do this, but Scanner's may not
  424. if ($attribute == self::MEDICAL_RECORD_DOWNLOAD && $this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD')) {
  425. return VoterInterface::ACCESS_GRANTED;
  426. }
  427. // Certain roles may have access to Radiology
  428. if ($attribute == self::RADIOLOGY_DOWNLOAD) {
  429. // Array of permitted/allowed roles
  430. $allowedRoles = [
  431. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  432. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  433. ];
  434. // Iterate through them and...
  435. foreach ($allowedRoles as $role) {
  436. // ... if they have the role...
  437. if ($this->authorizationChecker->isGranted($role)) {
  438. // SHAZAM!
  439. return VoterInterface::ACCESS_GRANTED;
  440. }
  441. }
  442. }
  443. }
  444. // These project-level roles must not view the "File details" panel.
  445. // Any user reaching this block without one of these roles is granted access.
  446. if ($attribute === self::VIEW_FILE_DETAILS) {
  447. $excludedRoles = [
  448. 'ROLE_PROJECT_' . $entity->getId() . '_EXPERT',
  449. 'ROLE_PROJECT_' . $entity->getId() . '_EXPERTVIEWER',
  450. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  451. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  452. ];
  453. foreach ($excludedRoles as $role) {
  454. if ($this->authorizationChecker->isGranted($role)) {
  455. return VoterInterface::ACCESS_DENIED;
  456. }
  457. }
  458. return VoterInterface::ACCESS_GRANTED;
  459. }
  460. // if the user is wanting to read information about this Project
  461. if ($attribute == self::READ) {
  462. // if the user is an expert agency administrator let them pass.
  463. // this should probably be done in a better way, tying permissions
  464. // to an entity in one place somehow....
  465. if ($user->isExpertAgencyAdministrator()) {
  466. return VoterInterface::ACCESS_GRANTED;
  467. }
  468. // if the user has any role related to this project
  469. if ($this->userHelper->hasProjectRole($entity)) {
  470. // then they have access
  471. return VoterInterface::ACCESS_GRANTED;
  472. }
  473. }
  474. // if we are looking for updating a project
  475. // if the user is a project manager
  476. if ($attribute == self::UPDATE && $this->authorizationChecker->isGranted('ROLE_PROJECT_' . $entity->getId() . '_PROJECTMANAGER')) {
  477. // then they have access
  478. return VoterInterface::ACCESS_GRANTED;
  479. }
  480. // if we are checking to see if we can bypass authentication
  481. if ($attribute == self::BYPASS_AUTHENTICATION && $this->authorizationChecker->isGranted('USER_ADMINISTRATION', $entity)) {
  482. return VoterInterface::ACCESS_GRANTED;
  483. }
  484. // If we get to the end of this function, then no decisions have been
  485. // made so we deny access
  486. return VoterInterface::ACCESS_DENIED;
  487. }
  488. /**
  489. * Checks whether user has administrative rights for a clinical summary
  490. *
  491. *
  492. *
  493. * @param Project $entity
  494. *
  495. * @return int
  496. */
  497. private function canAccessClinicalSummaryWizard(Project $entity)
  498. {
  499. // Deny access if the project is in the process of being closed or is closed
  500. if ($entity->isCloseInProgressOrComplete()) {
  501. return false;
  502. }
  503. // Allow access if the user has the ROLE_ADMIN or ROLE_SUPER_ADMIN role
  504. return $this->authorizationChecker->isGranted('ROLE_ADMIN');
  505. }
  506. /**
  507. * Checks whether user can download radiology audit report
  508. *
  509. * @todo: Not type hinting this method now as this may change later
  510. *
  511. * @param Project $entity
  512. */
  513. private function canRadiologyDownloadAuditReport(Project $entity): int
  514. {
  515. $deniedRoles = [
  516. 'ROLE_PROJECT_' . $entity->getId() . '_EXPERT',
  517. 'ROLE_PROJECT_' . $entity->getId() . '_EXPERTVIEWER',
  518. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNER',
  519. 'ROLE_PROJECT_' . $entity->getId() . '_SCANNERDOWNLOAD',
  520. ];
  521. foreach ($deniedRoles as $role) {
  522. if ($this->authorizationChecker->isGranted($role)) {
  523. return VoterInterface::ACCESS_DENIED;
  524. }
  525. }
  526. return VoterInterface::ACCESS_GRANTED;
  527. }
  528. }