src/CoreBundle/Security/ProblemVoter.php line 14

Open in your IDE?
  1. <?php
  2. namespace CoreBundle\Security;
  3. use AdminBundle\Service\EasyAdminService;
  4. use CoreBundle\Entity\Mathproblem;
  5. use CoreBundle\Entity\Quiz;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Symfony\Component\HttpFoundation\RequestStack;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  10. use Symfony\Component\Security\Core\Security;
  11. class ProblemVoter extends Voter
  12. {
  13. const PERMISSION = 'problemEntityPermission';
  14. const INDEX_ACTION = 'problemIndexAction';
  15. const NEW_ACTION = 'problemNewAction';
  16. const EDIT_ACTION = 'problemEditAction';
  17. const DELETE_ACTION = 'problemDeleteAction';
  18. private Security $security;
  19. private EntityManagerInterface $em;
  20. private EasyAdminService $easyAdminService;
  21. private RequestStack $requestStack;
  22. public function __construct(Security $security, EntityManagerInterface $em, EasyAdminService $easyAdminService, RequestStack $requestStack)
  23. {
  24. $this->security = $security;
  25. $this->em = $em;
  26. $this->easyAdminService = $easyAdminService;
  27. $this->requestStack = $requestStack;
  28. }
  29. protected function supports(string $attribute, $subject): bool
  30. {
  31. // For index and new, $subject will always be null. For permission, it will be null when trying to create a new entity.
  32. if (in_array($attribute, [self::INDEX_ACTION, self::NEW_ACTION, self::PERMISSION])) {
  33. return true;
  34. }
  35. if (in_array($attribute, [self::EDIT_ACTION, self::DELETE_ACTION])) {
  36. return $subject instanceof Mathproblem;
  37. }
  38. return false;
  39. }
  40. protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
  41. {
  42. if ($attribute === self::INDEX_ACTION) {
  43. // Allow everyone to list - the entity permissions will still apply and hide entities you are not allowed
  44. // to access.
  45. return true;
  46. }
  47. if ($attribute === self::NEW_ACTION || $attribute === self::PERMISSION && $subject === null) {
  48. // Anyone with cms access should be able to create new problems
  49. return true;
  50. }
  51. if (!$subject instanceof Mathproblem) {
  52. throw new \LogicException("Invalid type for voter and attribute.");
  53. }
  54. return $this->checkEntityPermissions($subject, $attribute);
  55. }
  56. public function checkEntityPermissions(Mathproblem $subject): bool
  57. {
  58. // ROLE_SUPER_ADMIN inherits ROLE_ADMIN, and will also be included here.
  59. if ($this->security->isGranted('ROLE_ADMIN')) {
  60. return true;
  61. }
  62. if ($subject->getId() === null) {
  63. // Creating a new problem via MathproblemFromQuizCrudController
  64. try {
  65. $quiz = $this->easyAdminService->getQuiz($this->requestStack->getCurrentRequest());
  66. return $this->checkPermissionByQuiz($quiz);
  67. } catch (\Exception) {
  68. return false;
  69. }
  70. }
  71. return $this->checkPermissionByProblem($subject);
  72. }
  73. private function checkPermissionByProblem(Mathproblem $problem): bool
  74. {
  75. $dql = <<<DQL
  76. SELECT p.id
  77. FROM CoreBundle\Entity\RelationQuizMathproblem rel
  78. JOIN rel.quiz q
  79. JOIN q.publication pc
  80. JOIN pc.publisher ps
  81. JOIN CoreBundle\Entity\PublisherPermission p WITH p.publisher = ps
  82. WHERE p.user = ?1
  83. AND rel.mathproblem = ?2
  84. DQL;
  85. return $this->runQuery($dql, $problem);
  86. }
  87. private function checkPermissionByQuiz(Quiz $quiz): bool
  88. {
  89. $dql = <<<DQL
  90. SELECT p.id
  91. FROM CoreBundle\Entity\Quiz q
  92. JOIN q.publication pc
  93. JOIN pc.publisher ps
  94. JOIN CoreBundle\Entity\PublisherPermission p WITH p.publisher = ps
  95. WHERE p.user = ?1
  96. AND q = ?2
  97. DQL;
  98. return $this->runQuery($dql, $quiz);
  99. }
  100. private function runQuery(string $dql, Mathproblem|Quiz $parameter): bool
  101. {
  102. if ($this->security->isGranted('ROLE_EDITOR'))
  103. $dql .= PHP_EOL . 'AND (p.editorPermission = true OR p.publication = pc)';
  104. else if ($this->security->isGranted('ROLE_AUTHOR'))
  105. $dql .= PHP_EOL . 'AND p.publication = pc';
  106. else
  107. $dql .= PHP_EOL . 'AND 0 = 1';
  108. $query = $this->em->createQuery($dql);
  109. $query->setParameter(1, $this->security->getUser());
  110. $query->setParameter(2, $parameter);
  111. $result = $query->getResult();
  112. return !empty($result);
  113. }
  114. }