5886d9859907ce04adc3c9174b02781d6f174349
[yaffs-website] / web / modules / contrib / permissions_by_term / permissions_by_term.module
1 <?php
2
3 /**
4  * @file
5  * Allows access to terms in a vocabulary to be limited by user or role.
6  */
7
8 use Drupal\Core\Access\AccessResult;
9 use Drupal\Core\Form\FormState;
10 use Drupal\permissions_by_term\Controller\PermissionsByTermController;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\node\NodeInterface;
13 use Drupal\Core\Session\AccountInterface;
14 use Drupal\taxonomy\Entity\Term;
15 use Drupal\Core\Routing\RouteMatchInterface;
16 use Drupal\Core\Cache\Cache;
17
18 /**
19  * Implements hook_help().
20  */
21 function permissions_by_term_help($route_name, RouteMatchInterface $arg) {
22   switch ($route_name) {
23     case 'help.page.permissions_by_term':
24       $output = '';
25       $output .= '<h3>' . t('About') . '</h3>';
26       $output .= '<p>' . t('The "Permissions by Term" (PbT) module allows taxonomy administrators the
27         ability to restrict setting individual terms on nodes by user
28         or role. If a user is unable to set any terms for a required
29         vocabulary, they are blocked from adding or editing content with
30         that vocabulary. For more information, see the online documentation for <a href=":PbT-documentation" target="_blan" title="Online Documentation">Permissions by Term</a>.', [':PbT-documentation' => 'https://www.drupal.org/project/permissions_by_term']) . '</p>';
31       $output .= '<h3>' . t('Uses') . '</h3>';
32       $output .= '<dl>';
33       $output .= '<dt>' . t('General') . '</dt>';
34       $output .= '<dd>' . t('Use Permissions by Term to easily build access-restricted content areas on your websites.') . '</dd>';
35       $output .= '<dt>' . t('Lightweight Access Control') . '</dt>';
36       $output .= '<dd>' . 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.') . '</dd>';
37       $output .= '<dt>' . t('Example use cases') . '</dt>';
38       $output .= '<dd>' . t('A club or service site with premium- or member-only content.') . '</dd>';
39       $output .= '<dd>' . t('School websites with content intended for teachers only and content aimed at individual classes within the school.') . '</dd>';
40       $output .= '<dd>' . t('Company intranets with sensitive or proprietary content alongside non-restricted content.') . '</dd>';
41       $output .= '</dl>';
42
43       return $output;
44   }
45 }
46
47 /**
48  * Validation handler for permissions_by_term_form_alter().
49  */
50 function permissions_by_term_validate($form, FormState $oFormState) {
51   foreach ($form as $field) {
52     if (!is_object($field) && !empty($field['widget']['target_id']['#target_type']) && $field['widget']['target_id']['#target_type'] == 'taxonomy_term') {
53       $field_name = $field['widget']['#field_name'];
54       $terms = $oFormState->getValues()[$field_name]['target_id'];
55       $not_allowed_term_names = [];
56       if (!empty($terms)) {
57         foreach ($terms as $term) {
58           $term_id = $term['target_id'];
59           /* @var \Drupal\permissions_by_term\AccessCheck $access_check_service */
60           $access_check_service = \Drupal::service('permissions_by_term.access_check');
61           if (!$access_check_service->isAccessAllowedByDatabase($term_id)) {
62             $term = Term::load($term_id);
63             $not_allowed_term_names[] = $term->getName();
64           }
65         }
66       }
67     }
68   }
69   if (!empty($not_allowed_term_names)) {
70     if (count($not_allowed_term_names) > 1) {
71       $term_names = implode(', ', $not_allowed_term_names);
72     }
73     else {
74       $term_names = $not_allowed_term_names['0'];
75     }
76     $oFormState->setErrorByName('field_tags', t('You are not allowed to use specific taxonomy terms like the following: "term-names". Remove the restricted taxonomy terms from the form field and try again.',
77       ['term-names' => $term_names]));
78   }
79 }
80
81 /**
82  * Submit handler for permissions_by_term_form_alter().
83  */
84 function permissions_by_term_submit($form, FormState $formState) {
85   $termId = $formState->getFormObject()->getEntity()->id();
86   /* @var \Drupal\permissions_by_term\AccessStorage $access_storage */
87   $access_storage = \Drupal::service('permissions_by_term.access_storage');
88   $access_storage->saveTermPermissions($formState, $termId);
89   /**
90    * @var \Drupal\permissions_by_term\NodeAccess $nodeAccess
91    */
92   $nodeAccess = \Drupal::service('permissions_by_term.node_access');
93   $nodeAccess->rebuildByTid($termId, $formState);
94   Cache::invalidateTags(['search_index:node_search']);
95 }
96
97 /**
98  * Implements hook_form_alter().
99  */
100 function permissions_by_term_form_taxonomy_term_form_alter(&$form, FormStateInterface $oFormState, $form_id) {
101   if (\Drupal::currentUser()->hasPermission('show term permission form on term page')) {
102     $iTermId = $oFormState->getFormObject()->getEntity()->id();
103
104     /* @var \Drupal\permissions_by_term\AccessStorage $access_storage */
105     $access_storage = \Drupal::service('permissions_by_term.access_storage');
106
107     $form['access'] = [
108       '#type' => 'fieldset',
109       '#title' => t('Permissions'),
110       '#description' => t('To limit access to this term by user or roles,
111       add users or roles to the following lists. Leave empty to allow
112       node access by single node view, node listing in views and taxonomy
113       term selection by all users.'),
114       '#collapsible' => TRUE,
115       '#collapsed' => TRUE,
116       '#attributes' => ['id' => 'fieldset_term_access'],
117       '#weight' => -5,
118       '#tree' => TRUE,
119     ];
120
121     $aAllowedUsers = $access_storage->getAllowedUserIds($iTermId);
122     if (!empty($aAllowedUsers)) {
123       $aAllowedUsers = user_load_multiple($aAllowedUsers);
124       $sUserFormValue = $access_storage->getUserFormValue($aAllowedUsers);
125     }
126     else {
127       $sUserFormValue = NULL;
128     }
129
130     // Note that the autocomplete widget will only enable for users with the
131     // 'access profiles' permission. Other users will have to specify the name
132     // manually.
133     $form['access']['user'] = [
134       '#type' => 'entity_autocomplete',
135       '#target_type' => 'user',
136       '#title' => t('Allowed users'),
137       '#description' => t('Enter a comma-seperated list of user names to give') . ' ' .
138       t('them permission to use this term and access related nodes in single node view
139       and views listings.'),
140       '#value' => $sUserFormValue,
141       '#size' => 60,
142       '#autocomplete_route_name' => 'permissions_by_term.autocomplete_multiple',
143       '#weight' => -10,
144     ];
145
146     $aAllowedRoles = $access_storage->getExistingRoleTermPermissionsByTid($iTermId);
147
148     // Firstly fetch all translated allowed role names.
149     $aTranslatedAllowedRoleNames = [];
150     foreach ($aAllowedRoles as $role) {
151       $aTranslatedAllowedRoleNames[] = $role;
152     }
153
154     // Get all roles for the complete form and translate them.
155     $aTranslatedUserRoles = [];
156     $array_key_counter = 1;
157     foreach (user_roles() as $user_role_id => $user_role_name) {
158       $aTranslatedUserRoles[$user_role_id] = $user_role_name->label();
159       $array_key_counter++;
160     }
161
162     // Generate the default values for the form.
163     $aSetRoles = [];
164     if (!empty($aTranslatedAllowedRoleNames)) {
165       foreach ($aTranslatedAllowedRoleNames as $role_name) {
166         $aSetRoles[] = $role_name;
167       }
168     }
169
170     // Now, lets do the Roles table.
171     $form['access']['role'] = [
172       '#type' => 'checkboxes',
173       '#title' => t('Allowed roles'),
174       '#description' => t('Select a role to allow all members of this role to
175         use this term and access related nodes in single node view and views
176         listings.'),
177       '#default_value' => $aSetRoles,
178       '#options' => $aTranslatedUserRoles,
179       '#multiple' => FALSE,
180       '#weight' => 5,
181     ];
182
183     $form['#validate'][] = 'permissions_by_term_validate';
184     $form['actions']['submit']['#submit'][] = 'permissions_by_term_submit';
185   }
186 }
187
188 /**
189  * Implements hook_form_alter().
190  */
191 function permissions_by_term_form_alter(&$form, FormStateInterface $oFormState, $form_id) {
192   $form['#validate'][] = 'permissions_by_term_validate';
193 }
194
195 /**
196  * Implements hook_node_access().
197  *
198  * Forwards user by drupal_access_denied(); to an access denied page, if a
199  * single restricted node is called.
200  *
201  * This hook is not fired if admin is logged in. Users with the
202  * "bypass node access" permission may always view and edit content
203  * through the administrative interface.
204  */
205 function permissions_by_term_node_access(NodeInterface $node, $op, AccountInterface $account) {
206   if (method_exists($node, 'id') && $op == 'view') {
207     if (!$node->isPublished() && !$account->hasPermission('Bypass content access control', $account)) {
208       return AccessResult::forbidden();
209     }
210
211     /* @var \Drupal\permissions_by_term\AccessCheck $access_check_service */
212     $access_check_service = \Drupal::service('permissions_by_term.access_check');
213     $oPermissionsByTermController = new PermissionsByTermController($access_check_service);
214
215     return $oPermissionsByTermController->handleNode($node->id());
216   }
217 }
218
219 /**
220  * Implements hook_node_grants().
221  */
222 function permissions_by_term_node_grants(\Drupal\Core\Session\AccountInterface $account, $op)
223 {
224     if ($op == 'view') {
225       /**
226        * @var \Drupal\permissions_by_term\AccessStorage $accessStorage
227        */
228       $accessStorage = \Drupal::service('permissions_by_term.access_storage');
229       $grants = $accessStorage->getGidsByRealm('permissions_by_term__uid_' . \Drupal::currentUser()->id());
230
231       return $grants;
232     }
233 }
234
235 /**
236  * Implements hook_node_access_records().
237  *
238  * Permissions can be rebuild at /admin/reports/status/rebuild.
239  */
240 function permissions_by_term_node_access_records(\Drupal\node\NodeInterface $node) {
241   /**
242    * @var \Drupal\permissions_by_term\NodeAccess $nodeAccess
243    */
244   $nodeAccess = \Drupal::service('permissions_by_term.node_access');
245   $grantsForThisNode = $nodeAccess->createGrants($node->id());
246
247   $grants = [];
248   if (!empty($grantsForThisNode)) {
249     foreach ($grantsForThisNode as $grantObject) {
250       $grants[] = [
251         'realm' => $grantObject->realm,
252         'gid' => $grantObject->gid,
253         'grant_view' => $grantObject->grant_view,
254         'grant_update' => $grantObject->grant_update,
255         'grant_delete' => $grantObject->grant_delete,
256         'langcode' => $grantObject->langcode,
257         'fallback' => 1,
258         'nid' => $node->id(),
259       ];
260     }
261   }
262
263   return $grants;
264 }
265
266 /**
267  * Implements hook_user_insert().
268  */
269 function permissions_by_term_user_insert($user) {
270   /**
271    * @var \Drupal\permissions_by_term\NodeAccess $nodeAccess
272    */
273   $nodeAccess = \Drupal::service('permissions_by_term.node_access');
274   $nodeAccess->rebuildByUid($user->id(), TRUE);
275   Cache::invalidateTags(['search_index:node_search']);
276 }
277
278 /**
279  * Implements hook_user_update().
280  */
281 function permissions_by_term_user_update($user) {
282   /**
283    * @var \Drupal\permissions_by_term\NodeAccess $nodeAccess
284    */
285   $nodeAccess = \Drupal::service('permissions_by_term.node_access');
286   $nodeAccess->rebuildByUid($user->id());
287   Cache::invalidateTags(['search_index:node_search']);
288 }
289
290 /**
291  * Implements hook_node_insert().
292  */
293 function permissions_by_term_node_insert($node) {
294   /**
295    * @var \Drupal\permissions_by_term\NodeAccess $nodeAccess
296    */
297   $nodeAccess = \Drupal::service('permissions_by_term.node_access');
298   $nodeAccess->rebuildByNid($node->id());
299   Cache::invalidateTags(['search_index:node_search']);
300 }