' . t('About') . '';
$output .= '
' . t('The "Permissions by Term" (PbT) module allows taxonomy administrators the
ability to restrict setting individual terms on nodes by user
or role. If a user is unable to set any terms for a required
vocabulary, they are blocked from adding or editing content with
that vocabulary. For more information, see the online documentation for Permissions by Term.', [':PbT-documentation' => 'https://www.drupal.org/docs/8/modules/permissions-by-term']) . '
';
$output .= '' . t('Uses') . '
';
$output .= '';
$output .= '- ' . t('General') . '
';
$output .= '- ' . t('Use Permissions by Term to easily build access-restricted content areas on your websites.') . '
';
$output .= '- ' . t('Lightweight Access Control') . '
';
$output .= '- ' . t('Permissions by Term restricts user access to specified Drupal nodes based on taxonomy terms - a core part of Drupal’s functionality. PbT lets you restrict content access while relying on very little contributed code.') . '
';
$output .= '- ' . t('Example use cases') . '
';
$output .= '- ' . t('A club or service site with premium- or member-only content.') . '
';
$output .= '- ' . t('School websites with content intended for teachers only and content aimed at individual classes within the school.') . '
';
$output .= '- ' . t('Company intranets with sensitive or proprietary content alongside non-restricted content.') . '
';
$output .= '
';
return $output;
}
}
/**
* Validation handler for permissions_by_term_form_alter().
*/
function permissions_by_term_validate($form, FormState $oFormState) {
foreach ($form as $field) {
if (!is_object($field) && !empty($field['widget']['target_id']['#target_type']) && $field['widget']['target_id']['#target_type'] == 'taxonomy_term') {
$field_name = $field['widget']['#field_name'];
$terms = $oFormState->getValues()[$field_name]['target_id'];
$not_allowed_term_names = [];
if (!empty($terms)) {
foreach ($terms as $term) {
if (!empty($term['target_id'])) {
$term_id = $term['target_id'];
/* @var \Drupal\permissions_by_term\Service\AccessCheck $access_check_service */
$access_check_service = \Drupal::service('permissions_by_term.access_check');
if (!$access_check_service->isAccessAllowedByDatabase($term_id)) {
$term = Term::load($term_id);
$not_allowed_term_names[] = $term->getName();
}
}
}
}
}
}
if (!empty($not_allowed_term_names)) {
if (count($not_allowed_term_names) > 1) {
$term_names = implode(', ', $not_allowed_term_names);
}
else {
$term_names = $not_allowed_term_names['0'];
}
$oFormState->setErrorByName('field_tags', t('You are not allowed to use taxonomy terms like: "@termNames". Remove the restricted taxonomy terms from the form field and try again.',
['@termNames' => $term_names]));
}
}
/**
* Submit handler for permissions_by_term_form_alter().
*/
function permissions_by_term_submit($form, FormState $formState) {
$termId = $formState->getFormObject()->getEntity()->id();
/* @var \Drupal\permissions_by_term\Service\AccessStorage $access_storage */
$access_storage = \Drupal::service('permissions_by_term.access_storage');
$access_update = $access_storage->saveTermPermissions($formState, $termId);
// Check if we need to rebuild node_access by term id
$invalidate_cache_tag = false;
// Has anything has changed?
foreach($access_update as $values) {
if(!empty($values)) {
$invalidate_cache_tag = true;
break;
}
}
// Do we need to flush the cache?
if($invalidate_cache_tag === true) {
Cache::invalidateTags(['search_index:node_search']);
}
}
/**
* Implements hook_form_alter().
*/
function permissions_by_term_form_taxonomy_term_form_alter(&$form, FormStateInterface $oFormState, $form_id) {
if (\Drupal::currentUser()->hasPermission('show term permission form on term page')) {
$iTermId = $oFormState->getFormObject()->getEntity()->id();
/* @var \Drupal\permissions_by_term\Service\AccessStorage $access_storage */
$access_storage = \Drupal::service('permissions_by_term.access_storage');
$description = << 'fieldset',
'#title' => t('Permissions'),
'#description' => t($description),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => ['id' => 'fieldset_term_access'],
'#weight' => -5,
'#tree' => TRUE,
];
$aAllowedUsers = $access_storage->getAllowedUserIds($iTermId);
if (!empty($aAllowedUsers)) {
$aAllowedUsers = user_load_multiple($aAllowedUsers);
$sUserFormValue = $access_storage->getUserFormValue($aAllowedUsers);
}
else {
$sUserFormValue = NULL;
}
$description = << 'entity_autocomplete',
'#target_type' => 'user',
'#title' => t('Allowed users'),
'#description' => t($description),
'#value' => $sUserFormValue,
'#size' => 60,
'#autocomplete_route_name' => 'permissions_by_term.autocomplete_multiple',
'#weight' => -10,
];
$aAllowedRoles = $access_storage->getRoleTermPermissionsByTid($iTermId);
// Firstly fetch all translated allowed role names.
$aTranslatedAllowedRoleNames = [];
foreach ($aAllowedRoles as $role) {
$aTranslatedAllowedRoleNames[] = $role;
}
// Get all roles for the complete form and translate them.
$aTranslatedUserRoles = [];
$array_key_counter = 1;
foreach (user_roles() as $user_role_id => $user_role_name) {
$aTranslatedUserRoles[$user_role_id] = $user_role_name->label();
$array_key_counter++;
}
// Generate the default values for the form.
$aSetRoles = [];
if (!empty($aTranslatedAllowedRoleNames)) {
foreach ($aTranslatedAllowedRoleNames as $role_name) {
$aSetRoles[] = $role_name;
}
}
$description = << 'checkboxes',
'#title' => t('Allowed roles'),
'#description' => t($description),
'#default_value' => $aSetRoles,
'#options' => $aTranslatedUserRoles,
'#multiple' => FALSE,
'#weight' => 5,
];
$form['#validate'][] = 'permissions_by_term_validate';
$form['actions']['submit']['#submit'][] = 'permissions_by_term_submit';
}
}
/**
* Implements hook_form_alter().
*/
function permissions_by_term_form_alter(&$form, FormStateInterface $oFormState, $form_id) {
$form['#validate'][] = 'permissions_by_term_validate';
if (isNodeEditForm()) {
$form['permissions_by_term_info'] = [
'#type' => 'details',
'#group' => 'advanced',
'#title' => t('Permissions by Term'),
'#access' => \Drupal::currentUser()->hasPermission('show term permissions on node edit page'),
];
$nid = null;
if (!empty($node = \Drupal::routeMatch()->getParameter('node'))) {
$nid = $node->id();
}
$viewFilePath = drupal_get_path('module', 'permissions_by_term') . '/src/View/node-details.html.twig';
/**
* @var \Drupal\permissions_by_term\Service\NodeEntityBundleInfo $nodeEntityBundleInfo
*/
$nodeEntityBundleInfo = \Drupal::service('permissions_by_term.node_entity_bundle_info');
$form['permissions_by_term_info']['revision'] = array(
'#type' => 'item',
'#markup' => $nodeEntityBundleInfo->renderNodeDetails($viewFilePath, $nid),
);
$form['#attached']['library'][] = 'permissions_by_term/nodeForm';
}
}
function isNodeEditForm() {
$currentPath = \Drupal::service('path.current')->getPath();
if (is_numeric(strpos($currentPath, '/node/'))
&& (is_numeric(strpos($currentPath, '/edit')) || is_numeric(strpos($currentPath, '/add')))) {
return TRUE;
}
return FALSE;
}
/**
* Implements hook_node_access().
*
* Forwards user by drupal_access_denied(); to an access denied page, if a
* single restricted node is called.
*
* This hook is not fired if admin is logged in. Users with the
* "bypass node access" permission may always view and edit content
* through the administrative interface.
*/
function permissions_by_term_node_access(NodeInterface $node, $op, AccountInterface $account) {
/* @var \Drupal\permissions_by_term\Service\AccessCheck $accessCheck */
$accessCheck = \Drupal::service('permissions_by_term.access_check');
return $accessCheck->handleNode($node->id(), $node->language()->getId());
}
/**
* Implements hook_node_grants().
*/
function permissions_by_term_node_grants(\Drupal\Core\Session\AccountInterface $account, $op)
{
if ($op == 'view') {
/**
* @var \Drupal\permissions_by_term\Service\AccessStorage $accessStorage
*/
$accessStorage = \Drupal::service('permissions_by_term.access_storage');
$grants = $accessStorage->getGids(\Drupal::currentUser());
return $grants;
}
}
/**
* Implements hook_node_access_records().
*
* Permissions can be rebuild at /admin/reports/status/rebuild.
*/
function permissions_by_term_node_access_records(\Drupal\node\NodeInterface $node) {
// Do not return any grants for nodes that this module doesn't manage.
if (!$node->isPublished()) {
return;
}
$has_term_access_restrictions = FALSE;
/* @var \Drupal\permissions_by_term\Service\AccessStorage $access_storage */
$access_storage = \Drupal::service('permissions_by_term.access_storage');
foreach ($access_storage->getTidsByNid($node->id()) as $tid) {
/* @var \Drupal\permissions_by_term\Service\AccessCheck $access_check_service */
$access_check_service = \Drupal::service('permissions_by_term.access_check');
if ($access_check_service->isAnyPermissionSetForTerm($tid, $node->language()->getId())) {
$has_term_access_restrictions = TRUE;
break;
}
}
if (!$has_term_access_restrictions) {
return;
}
/**
* @var \Drupal\permissions_by_term\Service\NodeAccess $nodeAccess
*/
$nodeAccess = \Drupal::service('permissions_by_term.node_access');
$grantObject = $nodeAccess->createGrant($node->id(), $node->id());
$grants[] = [
'realm' => $grantObject->realm,
'gid' => $grantObject->gid,
'grant_view' => $grantObject->grant_view,
'grant_update' => $grantObject->grant_update,
'grant_delete' => $grantObject->grant_delete,
'nid' => $node->id(),
];
return $grants;
}
/**
* Implements hook_user_insert().
*/
function permissions_by_term_user_insert($user) {
Cache::invalidateTags(['search_index:node_search']);
}
/**
* Implements hook_user_update().
*/
function permissions_by_term_user_update($user) {
if (\Drupal::currentUser()->hasPermission('administer permissions')) {
Cache::invalidateTags(['search_index:node_search']);
}
}
/**
* Implements hook_node_insert().
*/
function permissions_by_term_node_insert($node) {
Cache::invalidateTags(['search_index:node_search']);
}
/**
* Implements hook_options_list_alter().
*/
function permissions_by_term_options_list_alter(array &$options, array $context) {
$fieldDefinitionSettings = $context['fieldDefinition']->getFieldStorageDefinition()->getSettings();
if (!empty($fieldDefinitionSettings['target_type']) && $fieldDefinitionSettings['target_type'] == 'taxonomy_term') {
foreach ($options as $id => $names) {
if ($id !== '_none') {
/**
* @var \Drupal\permissions_by_term\Service\AccessCheck $accessCheck
*/
$accessCheck = \Drupal::service('permissions_by_term.access_check');
if (is_array($names)) {
foreach ($names as $group_id => $name) {
if (!$accessCheck->isAccessAllowedByDatabase($group_id)) {
unset($options[$id]);
}
}
} elseif(is_string($names)) {
if (!$accessCheck->isAccessAllowedByDatabase($id)) {
unset($options[$id]);
}
}
}
}
}
}
/**
* Implements hook_user_cancel().
*
* Deletes all term permissions for a user when their account is cancelled.
*/
function permissions_by_term_user_cancel($edit, $account, $method) {
$deleted_user_id = $account->id();
/* @var \Drupal\permissions_by_term\Service\AccessStorage $access_storage */
$access_storage = \Drupal::service('permissions_by_term.access_storage');
$access_storage->deleteAllTermPermissionsByUserId($deleted_user_id);
}
/**
* Implements hook_ENTITY_TYPE_delete().
*
* Deletes all term permissions from storage when a term is deleted.
*/
function permissions_by_term_taxonomy_term_delete(EntityInterface $entity) {
/* @var \Drupal\permissions_by_term\Service\AccessStorage $access_storage */
$access_storage = \Drupal::service('permissions_by_term.access_storage');
$access_storage->deleteAllTermPermissionsByTid($entity->id());
}