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. public function supportsAttribute(mixed $attribute): bool
  94. {
  95. return in_array($attribute, [
  96. self::CREATE,
  97. self::READ,
  98. self::UPDATE,
  99. self::DELETE,
  100. self::ADMINISTRATION,
  101. self::MEDICAL_RECORDS_ADMINISTRATION,
  102. self::RADIOLOGY_ADMINISTRATION,
  103. self::USER_ADMINISTRATION,
  104. self::VIEW_DASHBOARD,
  105. self::TOGGLE_STATUS,
  106. self::PROJECT_USER_LIST,
  107. self::RADIOLOGY_DOWNLOAD,
  108. self::RADIOLOGY_DOWNLOAD_AUDIT_REPORT,
  109. self::MEDICAL_RECORD_DOWNLOAD,
  110. self::DELETION_REPORT_DOWNLOAD,
  111. self::INTERNAL_USER_ACCESS_REPORT_DOWNLOAD,
  112. self::CHRONOLOGY_ADMINISTRATION,
  113. self::ARCHIVE,
  114. self::CANCEL_DELETE,
  115. self::BYPASS_INACTIVE_NOTICE,
  116. self::BYPASS_CLOSED_NOTICE,
  117. self::CREATE_BATCH_REQUEST,
  118. self::CREATE_BATCH_REQUEST_SIMPLE,
  119. self::CREATE_CHRONOLOGY_REQUEST,
  120. self::CREATE_ADDITIONAL_REQUEST,
  121. self::SORTING_SESSION_LIST,
  122. self::CREATE_SORTING_SESSION,
  123. self::CREATE_SORTING_SESSION_SIMPLE,
  124. self::CREATE_MATTER_NOTE,
  125. self::LIST_MATTER_NOTES,
  126. self::VIEW_MATTER_COMMUNICATIONS,
  127. self::MEDICAL_RECORDS_DISCLOSE,
  128. self::DISCLOSE_DISC,
  129. self::BYPASS_AUTHENTICATION,
  130. self::CHANGE_ACCOUNT,
  131. self::MANAGE_REQUEST_LETTERS,
  132. self::VIEW_UNSORTED_RECORDS,
  133. self::CREATE_PROJECT_CLOSURE,
  134. self::DOWNLOAD_ALL_PROJECT_FILES,
  135. self::DOWNLOAD_PROJECT_CLOSURE_REPORT,
  136. self::VIEW_IMPORTANT_NOTES,
  137. self::VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS,
  138. self::CREATE_INTERPARTY_DISCLOSURE,
  139. self::LIST_INTERPARTY_DISCLOSURE,
  140. self::BYPASS_SERVICE_REQUEST_DISABLED,
  141. self::VIEW_THIRD_PARTY_ACCESS_REPORT,
  142. self::CLINICAL_SUMMARY_PROJECT_ADMINISTRATION,
  143. ]);
  144. }
  145. /**
  146. * Whether or not this is a supported Class
  147. *
  148. * @param string $class
  149. */
  150. public function supportsClass($class): bool
  151. {
  152. $supportedClass = Project::class;
  153. return $supportedClass === $class || is_subclass_of($class, $supportedClass);
  154. }
  155. /**
  156. * @param Project $entity
  157. *
  158. * @return int
  159. */
  160. #[Override]
  161. public function vote(TokenInterface $token, $entity, array $attributes)
  162. {
  163. /**
  164. * START: This is common code for all Voter::vote() methods
  165. */
  166. // check if class of this object is supported by this voter
  167. if (!$this->supportsClass($entity && !is_array($entity) ? $entity::class : '')) {
  168. return VoterInterface::ACCESS_ABSTAIN;
  169. }
  170. // check if the voter is used correct, only allow one attribute
  171. // this isn't a requirement, it's just one easy way for you to
  172. // design your voter
  173. if (1 !== count($attributes)) {
  174. throw new InvalidArgumentException(
  175. 'Only one attribute is allowed for medbrief Voters.'
  176. );
  177. }
  178. // set the attribute to check against
  179. $attribute = $attributes[0];
  180. // check if the given attribute is covered by this voter
  181. if (!$this->supportsAttribute($attribute)) {
  182. return VoterInterface::ACCESS_ABSTAIN;
  183. }
  184. // get current logged in user
  185. /** @var User $user */
  186. $user = $token->getUser();
  187. // make sure there is a user object (i.e. that the user is logged in)
  188. if (!$user instanceof UserInterface) {
  189. return VoterInterface::ACCESS_DENIED;
  190. }
  191. // Only allow Super Admins and Admins to change accounts
  192. if ($attribute === self::CHANGE_ACCOUNT && !$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  193. return VoterInterface::ACCESS_DENIED;
  194. }
  195. // Only allow Super Admins to delete a project
  196. if ($attribute === self::DELETE && !$this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN')) {
  197. return VoterInterface::ACCESS_DENIED;
  198. }
  199. // Only super admins can update service requests when the project is in a closed or closing state
  200. if ($attribute === self::BYPASS_SERVICE_REQUEST_DISABLED) {
  201. if ($this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN') === true) {
  202. return VoterInterface::ACCESS_GRANTED;
  203. }
  204. return VoterInterface::ACCESS_DENIED;
  205. }
  206. /**
  207. * Clinical Summary Access Control with project entity passed in as the subject
  208. *
  209. * We need to put this before we grant admin users rights to everything otherwise the
  210. * isCloseInProgressOrComplete check has no effect
  211. */
  212. if ($attribute === self::CLINICAL_SUMMARY_PROJECT_ADMINISTRATION) {
  213. if ($this->canAccessClinicalSummaryWizard($entity)) {
  214. return VoterInterface::ACCESS_GRANTED;
  215. }
  216. return VoterInterface::ACCESS_DENIED;
  217. }
  218. // Admin users can do everything
  219. if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
  220. return VoterInterface::ACCESS_GRANTED;
  221. }
  222. /**
  223. * END: Common code for all Voter:vote() methods. Put custom logic below.
  224. */
  225. /**
  226. * API (Firm) Access Control
  227. */
  228. if ($user instanceof Firm) {
  229. // If the account that belongs to the project is allocated to the firm's client areas, allow everything.
  230. if ($entity->getAccount() instanceof Account && $user->getClientAreas()->contains($entity->getAccount()) === true) {
  231. return self::ACCESS_GRANTED;
  232. }
  233. return self::ACCESS_DENIED;
  234. }
  235. /**
  236. * Disclosure matter access control
  237. */
  238. // Grab all project levels roles related to this project.
  239. $allProjectRoles = RoleParserService::getAllRolesForProject($entity->getId());
  240. // Users that have been directly invited to the Disclosure will have permission granted
  241. $isDirectlyInvitedToDisclosureMatter = array_filter($allProjectRoles, fn ($role) => $this->authorizationChecker->isGranted($role)) !== [];
  242. // Check if the project is a disclosure, and exclude anyone who has been directly invited to the disclosure matter (i.e. those that were
  243. // added when creating the disclosure). Project level project managers of the original project will not have a project role on the disclosure target project.
  244. if ($entity->isTypeDisclosure() && $isDirectlyInvitedToDisclosureMatter === false) {
  245. $allowedAttributes = [
  246. self::READ,
  247. self::RADIOLOGY_DOWNLOAD,
  248. self::MEDICAL_RECORD_DOWNLOAD,
  249. self::BYPASS_INACTIVE_NOTICE,
  250. self::VIEW_THIRD_PARTY_ACCESS_REPORT,
  251. ];
  252. // Disclosure matters only allow certain actions for the those who can VIEW the source disclosure entity
  253. if (in_array($attribute, $allowedAttributes) && $entity->getDisclosureSources()->count() > 0) {
  254. // Grant access if the user has access to VIEW the original source disclosure (we take the latest one in the chain of sources)
  255. /** @var InterpartyDisclosure $disclosure */
  256. $disclosure = $entity->getDisclosureSources()->last();
  257. if ($this->authorizationChecker->isGranted(InterpartyDisclosureVoter::VIEW, $disclosure)) {
  258. return self::ACCESS_GRANTED;
  259. }
  260. }
  261. return self::ACCESS_DENIED;
  262. }
  263. //Checks if user can download radiology audit report
  264. if ($attribute === self::RADIOLOGY_DOWNLOAD_AUDIT_REPORT) {
  265. return $this->canRadiologyDownloadAuditReport($entity);
  266. }
  267. $this->userHelper->setUser($user);
  268. $denyAccess = [
  269. self::CREATE_SORTING_SESSION,
  270. self::LIST_MATTER_NOTES,
  271. self::CREATE_MATTER_NOTE,
  272. self::MEDICAL_RECORDS_DISCLOSE,
  273. self::DISCLOSE_DISC,
  274. self::VIEW_MATTER_COMMUNICATIONS,
  275. self::DELETION_REPORT_DOWNLOAD,
  276. self::INTERNAL_USER_ACCESS_REPORT_DOWNLOAD,
  277. self::MANAGE_REQUEST_LETTERS,
  278. self::DELETE,
  279. self::VIEW_IMPORTANT_NOTES,
  280. self::VIEW_SERVICE_REQUEST_REQUIREMENT_BANNERS,
  281. ];
  282. // Deny all other roles these permissions
  283. if (in_array($attribute, $denyAccess)) {
  284. return VoterInterface::ACCESS_DENIED;
  285. }
  286. // Permissions related to the creation and management of sorting sessions and batches.
  287. $attributeGroup = [
  288. self::CREATE_BATCH_REQUEST_SIMPLE,
  289. self::SORTING_SESSION_LIST,
  290. self::CREATE_SORTING_SESSION_SIMPLE,
  291. ];
  292. if (in_array($attribute, $attributeGroup)) {
  293. if ($this->hasClientSessionAccess($entity, $user)) {
  294. return VoterInterface::ACCESS_GRANTED;
  295. };
  296. return VoterInterface::ACCESS_DENIED;
  297. }
  298. // Deny all other roles from creating these ServiceRequests
  299. $serviceRequestCreateAttributes = [
  300. self::CREATE_BATCH_REQUEST,
  301. self::CREATE_CHRONOLOGY_REQUEST,
  302. self::CREATE_ADDITIONAL_REQUEST,
  303. ];
  304. if (in_array($attribute, $serviceRequestCreateAttributes)) {
  305. return VoterInterface::ACCESS_DENIED;
  306. }
  307. if ($attribute === self::VIEW_DASHBOARD && $user->getMatterDashboardEnabled()) {
  308. // then they have access to do anything
  309. return VoterInterface::ACCESS_GRANTED;
  310. }
  311. // if this user is a Super Administrator for the Account for which this Project belongs
  312. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_SUPERADMINISTRATOR')) {
  313. // then they have access to do anything, except delete.
  314. return VoterInterface::ACCESS_GRANTED;
  315. }
  316. // Otherwise if this user is a Client Administrator for the Account then they can
  317. // do everything else except for User Administration and Deletion.
  318. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_ADMINISTRATOR')) {
  319. // Commenting this out for now because Kennedy's actually need
  320. // regular Client Administrators to still have this access for now. - RR
  321. //if ($attribute != self::USER_ADMINISTRATION) {
  322. // then they have access
  323. return VoterInterface::ACCESS_GRANTED;
  324. //}
  325. }
  326. // if this user is a Sorter for the Account for which this Project belongs
  327. // if we are looking for access other than delete, full administration and user management abilities
  328. if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $entity->getAccount()->getId() . '_SORTER') && ($attribute != self::DELETE
  329. && $attribute != self::ADMINISTRATION
  330. && $attribute != self::PROJECT_USER_LIST
  331. && $attribute != self::USER_ADMINISTRATION
  332. && $attribute != self::CREATE_PROJECT_CLOSURE
  333. && $attribute != self::CANCEL_DELETE
  334. && $attribute != self::ARCHIVE
  335. && $attribute != self::DOWNLOAD_ALL_PROJECT_FILES
  336. && $attribute != self::DOWNLOAD_PROJECT_CLOSURE_REPORT
  337. && $attribute != self::CREATE_INTERPARTY_DISCLOSURE
  338. && $attribute != self::LIST_INTERPARTY_DISCLOSURE)) {
  339. // then account level sorters have this access
  340. return VoterInterface::ACCESS_GRANTED;
  341. }
  342. // if we are looking for any access other than delete and full administration and the Closure of matters.
  343. if ($attribute != self::DELETE
  344. && $attribute != self::ADMINISTRATION
  345. && $attribute != self::CREATE_PROJECT_CLOSURE
  346. && $attribute != self::CANCEL_DELETE
  347. && $attribute != self::ARCHIVE
  348. && $attribute != self::DOWNLOAD_ALL_PROJECT_FILES
  349. && $attribute != self::DOWNLOAD_PROJECT_CLOSURE_REPORT
  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. }