/[drupal]/contributions/modules/tac_lite/tac_lite.module
ViewVC logotype

Contents of /contributions/modules/tac_lite/tac_lite.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.9 - (show annotations) (download) (as text)
Tue Jul 22 15:55:23 2008 UTC (16 months ago) by yogadex
Branch: MAIN
CVS Tags: DRUPAL-6--1-2, HEAD
Branch point for: DRUPAL-6--1
Changes since 1.8: +5 -14 lines
File MIME type: text/x-php
Fixed menu item access permissions.
1 <?php
2 // $Id: tac_lite.module,v 1.8 2008/06/07 01:42:06 yogadex Exp $
3 /**
4 * @file
5 * Control access to site content based on taxonomy, roles and users.
6 *
7 *
8 */
9
10 /**
11 * Implementation of hook_help
12 */
13 function tac_lite_help($section) {
14 switch ($section) {
15 case 'admin/help#tac_lite':
16 $output .= '<p>'.t('This module allows you to restrict access to site content. It uses a simple scheme based on Taxonomy, Users and Roles. It uses the node_access table and other features built into Drupal to hide content from unauthorized users.')."</p>\n";
17 $output .= '<p>'.t('While this module has been designed to be as simple as possible to use, there are several steps required to set it up.')."</p>\n";
18 $output .= "<ol>\n";
19 $output.= '<li>'.t('Define one or more vocabularies whose terms will control which users have access. For example, you could define a vocabulary called \'Privacy\' with terms \'Public\' and \'Private\'.')."</li>\n";
20 $output .= '<li>'.t('Tell this module which vocabulary or vocabularies control privacy. (!link)', array('!link' => l(t('administer -> access control -> tac_lite'), 'admin/user/access/tac_lite')))."</li>\n";
21 $output .= '<li>'.t('Grant access to users based on their roles (!link), and/or...', array('!link' => l(t('administer -> access control -> tac_lite -> by role'), 'admin/user/access/tac_lite/roles')))."</li>\n";
22 $output .= '<li>'.t('Grant access to individual users. (See the tac_lite tab under user -> edit.)')."</li>\n";
23 $output .= '<li>'.t('Finally, if your site contains content, you will need to re-save all nodes. This ensures that Drupal\'s node_access table is up-to-date. Otherwise, content submitted before this module was configured will be hidden.')."</li>\n";
24 $output .= "</ol>\n";
25 $output .= '<p>'.t('Currently, this module works with view grants only (no update or delete grants).')."</p>\n";
26 return $output;
27 break;
28
29 }
30 }
31
32 /**
33 * Implementation of hook_perm().
34 */
35 function tac_lite_perm() {
36 return array('administer_tac_lite');
37 }
38
39 /**
40 * Implementation of hook_menu().
41 */
42 function tac_lite_menu() {
43 global $user;
44 $items = array();
45
46 $items['admin/user/access/tac_lite'] =
47 array('title' => t('Access control by taxonomy'),
48 'description' => "taxonomy-based permissions by tac_lite",
49 'page callback' => 'drupal_get_form',
50 'page arguments' => array('tac_lite_admin_settings'),
51 'type' => MENU_NORMAL_ITEM,
52 'weight' => 1, // after 'roles' tab
53 'access arguments' => array('administer_tac_lite'),
54 );
55
56 $items['admin/user/access/tac_lite/settings'] =
57 array('title' => t('Settings'),
58 'type' => MENU_DEFAULT_LOCAL_TASK,
59 'weight' => -1,
60 'access arguments' => array('administer_tac_lite'),
61 );
62
63 $schemes = variable_get('tac_lite_schemes', 1);
64 for ($i = 1; $i <= $schemes; $i++) {
65 $items['admin/user/access/tac_lite/scheme_' . $i] =
66 array('title' => t('Scheme !num', array('!num' => $i)),
67 'page callback' => 'tac_lite_admin_settings_scheme',
68 'page arguments' => array((string)$i),
69 'type' => MENU_LOCAL_TASK,
70 'access arguments' => array('administer_tac_lite'),
71 );
72 }
73
74 return $items;
75 }
76
77 /**
78 * Returns the settings form
79 */
80 function tac_lite_admin_settings() {
81 $vocabularies = taxonomy_get_vocabularies();
82
83 if (!count($vocabularies)) {
84 $form['body'] = array('#type' => 'markup',
85 '#value' => t('You must <a href="!url">create a vocabulary</a> before you can use tac_lite.',
86 array('!url' => url('admin/content/taxonomy/add/vocabulary'))),
87 );
88 return $form;
89 }
90 else {
91 $options = array();
92 foreach ($vocabularies as $vid => $vocab) {
93 $options[$vid] = $vocab->name;
94 }
95
96 $form['tac_lite_categories'] =
97 array('#type' => 'select',
98 '#title' => t('Vocabularies'),
99 '#default_value' => variable_get('tac_lite_categories', null),
100 '#options' => $options,
101 '#description' => t('Select one or more vocabularies to control privacy. Do not select free tagging vocabularies, they are not supported.'),
102 '#multiple' => TRUE,
103 '#required' => TRUE,
104 );
105 $scheme_options = array();
106 // Currently only view, edit, delete permissions possible, so 7
107 // permutations will be more than enough.
108 for ($i = 1; $i < 8; $i++)
109 $scheme_options[$i] = $i;
110 $form['tac_lite_schemes'] =
111 array('#type' => 'select',
112 '#title' => t('Schemes'),
113 '#description' => t('Each scheme allows for a different set of permissions. For example, use scheme 1 for read-only permission; scheme 2 for read and update; scheme 3 for delete; etc. Additional schemes increase the size of your node_access table, so use no more than you need. Also note that ff you use tac_lite to assign update permission, it is recommended that you give those users read permission on all terms of that vocabulary.'),
114 '#default_value' => variable_get('tac_lite_schemes', 1),
115 '#options' => $scheme_options,
116 '#required' => TRUE,
117 );
118
119 $ret = system_settings_form($form);
120 // Special handling is required when this form is submitted.
121 $ret['#submit'][] = '_tac_lite_admin_settings_submit';
122 return $ret;
123 }
124 }
125
126
127 /**
128 * This form submit callback ensures that the form values are saved, and also
129 * the node access database table is rebuilt.
130 * 2008 : Modified by Paulo to be compliant with drupal 6
131 */
132 function _tac_lite_admin_settings_submit($form, &$form_state) {
133 // First, save settings the default way.
134 system_settings_form_submit($form, $form_state);
135 // Next, rebuild the node_access table.
136 node_access_rebuild();
137 //drupal_set_message(t('The content access permissions have been rebuilt.'));
138 // And rebuild menus, in case the number of schemes has changed.
139 menu_rebuild();
140 }
141
142
143 function tac_lite_admin_settings_scheme($i) {
144 return drupal_get_form('tac_lite_admin_scheme_form', $i);
145 }
146
147 /**
148 * helper function
149 */
150 function _tac_lite_config($scheme) {
151 // different defaults for scheme 1
152 if ($scheme === 1)
153 $config = variable_get('tac_lite_config_scheme_' . $scheme,
154 array('name' => t('read'),
155 'perms' => array('grant_view')));
156 else
157 $config = variable_get('tac_lite_config_scheme_' . $scheme,
158 array('name' => NULL, 'perms' => array()));
159 // For backward compatability, use naming convention for scheme 1
160 if ($scheme == 1)
161 $config['realm'] = 'tac_lite';
162 else
163 $config['realm'] = 'tac_lite_scheme_' . $scheme;
164
165 return $config;
166 }
167
168 /**
169 * Returns the form for role-based privileges.
170 */
171 function tac_lite_admin_scheme_form($form_state, $i) {
172 $vids = variable_get('tac_lite_categories', null);
173 $roles = user_roles();
174
175 if (count($vids)) {
176 $config = _tac_lite_config($i);
177
178 $form['tac_lite_config_scheme_' . $i] =
179 array('#tree' => TRUE);
180 $form['tac_lite_config_scheme_' . $i]['name'] =
181 array('#type' => 'textfield',
182 '#title' => t('Scheme name'),
183 '#description' => t('A human-readable name for administrators to see. For example, \'read\' or \'read and write\'.'),
184 '#default_value' => $config['name'],
185 '#required' => TRUE,
186 );
187 // Currently, only view, update and delete are supported by node_access
188 $options = array('grant_view' => 'view',
189 'grant_update' => 'update',
190 'grant_delete' => 'delete');
191 $form['tac_lite_config_scheme_' . $i]['perms'] =
192 array('#type' => 'select',
193 '#title' => t('Permissions'),
194 '#multiple' => TRUE,
195 '#options' => $options,
196 '#default_value' => $config['perms'],
197 '#description' => t('Select which permissions are granted by this scheme.'),
198 '#required' => FALSE, /* disable scheme by selecting none */
199 );
200
201 $form['helptext'] = array('#type' => 'markup',
202 '#value' => t('You may grant these permissions by role, below. To grant permission to an individual user, visit the tac_lite tab on the user edit page.'));
203
204
205 $all_defaults = variable_get('tac_lite_grants_scheme_' . $i, array());
206 $form['tac_lite_grants_scheme_' . $i] =
207 array('#tree' => true);
208 foreach ($roles as $rid => $role_name) {
209 $form['tac_lite_grants_scheme_' . $i][$rid] =
210 array('#type' => 'fieldset',
211 '#tree' => true,
212 '#title' => t('Access for %role', array('%role' => $role_name)),
213 '#description' => t(''),
214 );
215 $defaults = $all_defaults[$rid];
216 foreach ($vids as $vid) {
217 $v = taxonomy_get_vocabularies($vid);
218 $form['tac_lite_grants_scheme_' . $i][$rid][$vid] =
219 _taxonomy_term_select($v->name,
220 null, // name no longer used in new form api
221 $defaults[$vid],
222 $vid,
223 '',
224 true,
225 '<'.t('none').'>');
226 }
227 }
228
229 return system_settings_form($form);
230 }
231 else {
232 return (array('body' => array('#type' => 'markup',
233 '#value' => t('First select vocabularies on the <a href=!url>settings page</a>.', array('!url' => url('admin/user/access/tac_lite'))))));
234 }
235 }
236 /**
237 * Implementation of hook_user().
238 */
239
240 function tac_lite_user($op, $edit, $account, $category = null) {
241 //drupal_set_message("tac_lite_user($op) called."); // debug
242
243 // only for administrators
244 global $user;
245 if (!user_access('administer_tac_lite'))
246 return;
247
248 switch ($op) {
249 case 'categories':
250 return array(array('name' => 'tac_lite',
251 'title' => 'Taxonomy-based access',
252 'access callback' => 'user_access',
253 'access arguments' => array('administer_tac_lite'),
254 'weight' => 5,
255 ),
256 );
257 break;
258
259 case 'form':
260 if ($category == 'tac_lite') {
261 $vids = variable_get('tac_lite_categories', null);
262 if (count($vids)) {
263 for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
264 $config = _tac_lite_config($i);
265 if ($config['name']) {
266 $form['tac_lite'][$config['realm']] =
267 array('#type' => 'fieldset',
268 '#title'=> $config['name'],
269 '#description' => t('This scheme includes permissions %perms',
270 array('%perms' => implode(' and ', $config['perms']))),
271 '#tree' => TRUE,
272 );
273 foreach ($vids as $vid) {
274 $v = taxonomy_get_vocabularies($vid);
275 $form['tac_lite'][$config['realm']][$vid] =
276 _taxonomy_term_select($v->name,
277 null, // name no longer used in new form api
278 $account->tac_lite[$vid],
279 $vid,
280 '',
281 true,
282 '<'.t('none').'>');
283 }
284 }
285 }
286 $form['tac_lite'][0] =
287 array('#type' => 'markup',
288 '#value' => '<p>' . t('You may grant this user access based on the schemes and terms below. These permissions are in addition to <a href="!url">role based grants on scheme settings pages</a>.',
289 array('!url' => url('admin/user/access/tac_lite/scheme_1'))) . "</p>\n",
290 '#weight' => -1);
291
292 return $form;
293 }
294 }
295 break;
296 case 'validate':
297 //print_r($edit);
298 //print_r($account);
299 break;
300 }
301 }
302
303 /**
304 * Implementation of hook_node_access_records
305 *
306 * We are given a node and we return records for the node_access table. In
307 * our case, we inpect the node's taxonomy and grant permissions based on the
308 * terms.
309 */
310 function tac_lite_node_access_records($node) {
311 // all terms from all vocabs
312 $all_tids = _tac_lite_get_terms($node);
313 // just the vocabs we're interested in
314 $vids = variable_get('tac_lite_categories', null);
315 // now find just the terms we're interested in.
316 $tids = array();
317 if (count($all_tids) && count($vids)) {
318 $result = db_query("SELECT DISTINCT td.tid FROM {term_data} td WHERE td.vid IN (%s) AND td.tid IN (%s)",
319 implode(',', $vids),
320 implode(',', $all_tids));
321 while ($term = db_fetch_object($result)) {
322 $tids[] = $term->tid;
323 }
324 }
325
326 if (!count($tids)) {
327 // no relevant terms found.
328
329 // in drupal 4-7 we had to write a row into the database. In drupal 5, it should be safe to do nothing.
330 }
331 else {
332 // if we're here, the node has terms associated with it which restrict
333 // access to the node.
334 $grants = array();
335 for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
336 $config = _tac_lite_config($i);
337 foreach ($tids as $tid) {
338 $grant = array('realm' => $config['realm'],
339 'gid' => $tid, // use term id as grant id
340 );
341 foreach($config['perms'] as $perm)
342 $grant[$perm] = TRUE;
343 $grants[] = $grant;
344 }
345 }
346 return $grants;
347 }
348 }
349
350
351 /*
352 Get terms from a newly udpated node.
353 Terms are placed in $node->taxonomy by the form.
354 */
355 function _tac_lite_get_terms(&$node) {
356 $tids = array();
357
358 // emulating code from taxonomy_node_save here.
359 // note that free tagging vocabs not currently supported
360 if (count($node->taxonomy)) {
361 foreach ($node->taxonomy as $term) {
362 if (is_array($term)) {
363 foreach ($term as $tid) {
364 if (is_numeric($tid)) {
365 $tids[$tid] = $tid;
366 }
367 else {
368 // non-numeric means free-tagging vocabulary.
369 // we do not support. Do nothing.
370 }
371 }
372 }
373 else if (is_object($term)) {
374 // in drupal 5 term is an object. Is this right?
375 $tids[$term->tid] = $term->tid;
376 }
377 else if (is_numeric($term)) {
378 // $term is a tid.
379 $tids[$term] = $term;
380 }
381 else if ($term) {
382 drupal_set_message(t('Unexpected term value "%term" in tac_lite.',
383 array('%term' => $term)),
384 'error');
385 }
386 }
387 }
388
389 return $tids;
390 }
391
392 function _tac_lite_get_terms_by_nid($nid) {
393 $tids = array();
394 $terms = taxonomy_node_get_terms($nid);
395
396 // terms is now an array of objects. We convert to a simple array of tids
397 foreach ($terms as $term) {
398 $tids[$term->tid] = $term->tid;
399 }
400 return $tids;
401 }
402
403 /**
404 * Return the term ids of terms this user is allowed to access.
405 *
406 * Users are granted access to terms either because of who they are,
407 * or because of the roles they have.
408 */
409 function _tac_lite_user_tids(&$account, $scheme) {
410 // grant id 0 is reserved for nodes which were not given a grant id when they were created. By adding 0 to the grant id, we let the user view those nodes.
411 $grants = array(0);
412 $config = _tac_lite_config($scheme);
413 if (count($account->$config['realm'])) {
414 // $account->$config['realm'] is array. Keys are vids, values are array of tids within that vocabulary, to which the user has access
415 foreach ($account->$config['realm'] as $tids) {
416 if (count($tids)) {
417 $grants = array_merge($grants, $tids);
418 }
419 }
420 }
421
422 // add per-role grants in addition to per-user grants
423 $defaults = variable_get('tac_lite_grants_scheme_' . $scheme, array());
424 foreach ($account->roles as $rid => $role_name) {
425 if (count($defaults[$rid])) {
426 foreach ($defaults[$rid] as $tids) {
427 if (count($tids)) {
428 $grants = array_merge($grants, $tids);
429 }
430 }
431 }
432 }
433
434 // Because of some flakyness in the form API and the form we insert under
435 // user settings, we may have a bogus entry with vid set
436 // to ''. Here we make sure not to return that.
437 unset($grants['']);
438
439 return $grants;
440 }
441
442 /**
443 * Implementation of hook_node_grants
444 *
445 * Returns any grants which may give the user permission to perform the
446 * requested op.
447 */
448 function tac_lite_node_grants(&$account, &$op) {
449 $grants = array();
450 for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
451 $config = _tac_lite_config($i);
452 if (in_array('grant_' . $op, $config['perms'])) {
453 $grants[$config['realm']] = _tac_lite_user_tids($account, $i);
454 }
455 }
456 if (count($grants))
457 return $grants;
458 }
459
460 function tac_lite_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
461 global $user;
462
463 // if administrator, give all access
464 if (user_access('administer_tac_lite')) {
465 return;
466 }
467
468 // the vocabularies containing protected info.
469 $vids = variable_get('tac_lite_categories', array(0));
470
471 // the terms this user is allowed to see
472 $tids = array();
473 for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
474 $config = _tac_lite_config($i);
475 if (in_array('grant_view', $config['perms'])) {
476 $tids = array_merge($tids, _tac_lite_user_tids($user, $i));
477 }
478 }
479
480 // Note that if tac_lite is configured, but no schemes support grant_view,
481 // we assume everyone can view all terms.
482
483 if (count($tids) && is_array($vids) && count($vids)) {
484 switch ($primary_field) {
485 case 'tid':
486 // prevent users from seeing terms they do not have permission to read.
487 $join = "LEFT JOIN {term_data} tac_td ON $primary_table.tid = tac_td.tid";
488 $where = "$primary_table.tid IN (". implode(', ', $tids) .") OR tac_td.vid NOT IN (". implode(',', $vids) .")";
489
490 return array('join' => $join, 'where' => $where);
491 break;
492 case 'vid':
493
494 break;
495 }
496 }
497 }

  ViewVC Help
Powered by ViewVC 1.1.2