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