diff --git a/embargo.module b/embargo.module index c5b35dc..24b2881 100644 --- a/embargo.module +++ b/embargo.module @@ -7,6 +7,8 @@ use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Session\AccountInterface; use Drupal\embargo\EmbargoStorage; @@ -97,3 +99,32 @@ function embargo_theme($existing, $type, $theme, $path) { ], ]; } + +/** + * Add exempt_roles field. + */ +function embargo_update_9101(&$sandbox) { + $exempt_roles = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('List of exempt roles')) + ->setDescription(t('These roles will be able to bypass the embargo.')) + ->setTranslatable(FALSE) + ->setRevisionable(FALSE) + ->setRequired(FALSE) + ->setDisplayConfigurable('view', FALSE) + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) + ->setDisplayOptions('form', [ + 'type' => 'entity_reference_autocomplete', + ]) + ->setDisplayOptions('view', [ + 'type' => 'entity_reference_label', + 'label' => 'hidden', + ]) + ->setSettings([ + 'target_type' => 'user_role', + 'handler_settings' => [ + 'include_anonymous' => FALSE, + ], + ]); + \Drupal::entityDefinitionUpdateManager()->installFieldStorageDefinition( + 'exempt_roles', 'embargo', 'embargo', $exempt_roles); +} diff --git a/src/Access/EmbargoAccessCheck.php b/src/Access/EmbargoAccessCheck.php index e643958..7b80b6a 100644 --- a/src/Access/EmbargoAccessCheck.php +++ b/src/Access/EmbargoAccessCheck.php @@ -31,7 +31,7 @@ class EmbargoAccessCheck implements EmbargoAccessCheckInterface { protected $request; /** - * Th current user. + * The current user. * * @var \Drupal\Core\Session\AccountInterface */ diff --git a/src/Access/QueryTagger.php b/src/Access/QueryTagger.php index 81f9c58..70d099a 100644 --- a/src/Access/QueryTagger.php +++ b/src/Access/QueryTagger.php @@ -192,6 +192,10 @@ protected function buildAccessibleEmbargoesQuery($type) : SelectInterface { $user_alias = $query->leftJoin('embargo__exempt_users', 'u', 'e.id = %alias.entity_id'); $group->condition("{$user_alias}.exempt_users_target_id", $this->user->id()); + // ... the user has a role that is exempted from the embargo. + $role_alias = $query->leftJoin('embargo__exempt_roles', 'r', 'e.id = %alias.entity_id'); + $group->condition("{$role_alias}.exempt_roles_target_id", $this->user->getRoles(), 'IN'); + $query->condition($group); return $query; diff --git a/src/EmbargoInterface.php b/src/EmbargoInterface.php index 62003e2..558ac5e 100644 --- a/src/EmbargoInterface.php +++ b/src/EmbargoInterface.php @@ -178,6 +178,24 @@ public function getExemptUsers(): array; */ public function setExemptUsers(array $users): EmbargoInterface; + /** + * Gets the list of exempt roles. + * + * @return \Drupal\user\RoleInterface[] + * A list of roles exempt from the embargo. + */ + public function getExemptRoles(): array; + + /** + * Sets the list of roles exempt from this embargo. + * + * @param array $roles + * A list of role entities to exempt from this embargo. + * + * @return $this + */ + public function setExemptRoles(array $roles): EmbargoInterface; + /** * Retrieves the node being embargoed. * @@ -238,6 +256,17 @@ public function expiresBefore(int $date): bool; */ public function isUserExempt(AccountInterface $user): bool; + /** + * Checks if any of the user's roles is exempt from this embargo. + * + * @param \Drupal\Core\Session\AccountInterface $user + * The user to check. + * + * @return bool + * TRUE if the user is exempt otherwise FALSE. + */ + public function isUserRoleExempt(AccountInterface $user): bool; + /** * Checks if the given IP address is exempt from this embargo. * diff --git a/src/EmbargoStorage.php b/src/EmbargoStorage.php index 9221119..bd1a902 100644 --- a/src/EmbargoStorage.php +++ b/src/EmbargoStorage.php @@ -109,8 +109,9 @@ public function getApplicableNonExemptNonExpiredEmbargoes(EntityInterface $entit $inactive = $embargo->expiresBefore($timestamp); $type_exempt = ($entity instanceof NodeInterface && $embargo->getEmbargoType() !== EmbargoInterface::EMBARGO_TYPE_NODE); $user_exempt = $embargo->isUserExempt($user); + $user_role_exempt = $embargo->isUserRoleExempt($user); $ip_exempt = $embargo->ipIsExempt($ip); - return !($inactive || $type_exempt || $user_exempt || $ip_exempt); + return !($inactive || $type_exempt || $user_exempt || $user_role_exempt|| $ip_exempt); }); } diff --git a/src/Entity/Embargo.php b/src/Entity/Embargo.php index 03f8b57..3c3d73d 100644 --- a/src/Entity/Embargo.php +++ b/src/Entity/Embargo.php @@ -14,6 +14,7 @@ use Drupal\embargo\EmbargoInterface; use Drupal\embargo\IpRangeInterface; use Drupal\node\NodeInterface; +use Drupal\user\RoleInterface; use Drupal\user\UserInterface; /** @@ -174,6 +175,28 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ], ]); + $fields['exempt_roles'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('List of exempt roles')) + ->setDescription(t('These roles will be able to bypass the embargo.')) + ->setTranslatable(FALSE) + ->setRevisionable(FALSE) + ->setRequired(FALSE) + ->setDisplayConfigurable('view', FALSE) + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) + ->setDisplayOptions('form', [ + 'type' => 'entity_reference_autocomplete', + ]) + ->setDisplayOptions('view', [ + 'type' => 'entity_reference_label', + 'label' => 'hidden', + ]) + ->setSettings([ + 'target_type' => 'user_role', + 'handler_settings' => [ + 'include_anonymous' => FALSE, + ], + ]); + $fields['additional_emails'] = BaseFieldDefinition::create('email') ->setLabel(t('Additional Emails')) ->setDescription(t('For contact changes to this embargo.')) @@ -342,6 +365,23 @@ public function setExemptUsers(array $users): EmbargoInterface { return $this; } + /** + * {@inheritdoc} + */ + public function getExemptRoles(): array { + /** @var \Drupal\Core\Field\EntityReferenceFieldItemList $exempt_roles */ + $exempt_roles = $this->get('exempt_roles'); + return $exempt_roles->referencedEntities(); + } + + /** + * {@inheritdoc} + */ + public function setExemptRoles(array $roles): EmbargoInterface { + $this->set('exempt_roles', $roles); + return $this; + } + /** * {@inheritdoc} */ @@ -426,6 +466,16 @@ public function isUserExempt(AccountInterface $user): bool { }, $exempt_users)); } + /** + * {@inheritdoc} + */ + public function isUserRoleExempt(AccountInterface $user): bool { + $exempt_role_ids = array_map(function (RoleInterface $role) { + return $role->id(); + }, $this->getExemptRoles()); + return count(array_intersect($exempt_role_ids, $user->getRoles())) > 0; + } + /** * {@inheritdoc} */