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

Contents of /contributions/modules/aclfield/aclfield.module

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


Revision 1.5 - (show annotations) (download) (as text)
Tue Apr 17 02:26:32 2007 UTC (2 years, 7 months ago) by mfredrickson
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +37 -4 lines
File MIME type: text/x-php
added a formatter for the field to display what the perms are
1 <?php
2 // $Id: aclfield.module,v 1.4 2007/02/13 19:18:23 mfredrickson Exp $
3
4 /**
5 * @file
6 * Defines simple text field types.
7 */
8
9 /**
10 * Implementation of hook_field_info().
11 */
12 function aclfield_field_info() {
13 return array(
14 'aclfield' => array('label' => 'ACL Field'),
15 );
16 }
17
18 /**
19 * Implementation of hook_field_settings().
20 */
21 function aclfield_field_settings($op, $field) {
22 switch ($op) {
23 case 'form':
24 return;
25
26 case 'save':
27 return;
28
29 case 'database columns':
30 $columns = array(
31 'realm' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
32 'grants' => array('type' => 'int', 'not null' => FALSE, 'default' => NULL, 'sortable' => TRUE),
33 'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
34 'data' => array('type' => 'longtext', 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
35 );
36
37 return $columns;
38
39 case 'filters':
40 // TODO a filter such as "nodes where XXX grant can YYY priviledge"
41 // example: Group Administrators can Read, Edit, Delete
42
43 /*
44 return array(
45 'default' => array(
46 'list' => $allowed_values,
47 'list-type' => 'list',
48 'operator' => 'views_handler_operator_or',
49 'value-type' => 'array',
50 ),
51 );
52 */
53 break;
54 }
55 }
56
57 /**
58 * Implementation of hook_field().
59 */
60 function aclfield_field($op, &$node, $field, &$items, $teaser, $page) {
61 switch ($op) {
62 case 'load':
63 // TODO make cck respect my load directives!
64 break;
65 }
66 }
67
68 /**
69 * Implementation of hook_field_formatter_info().
70 */
71 function aclfield_field_formatter_info() {
72 return array(
73 'default' => array(
74 'label' => 'Default',
75 'field types' => array('aclfield'),
76 ),
77 );
78 }
79
80 /**
81 * Implementation of hook_field_formatter().
82 *
83 * The $node argument is necessary so that filter access can be checked on
84 * node preview.
85 */
86 function aclfield_field_formatter($field, $item, $formatter, $node) {
87 $data = unserialize($item['data']);
88 $perms = array (
89 0 => t('No permissions'),
90 1 => t('View'),
91 2 => t('View & Edit'),
92 3 => t('View, Edit & Delete'),
93 );
94
95 $processed = call_user_func($item['module'] . '_node_grants_display', $item['realm'], $data);
96 switch ($formatter) {
97
98 default:
99
100 return theme('aclfield_content_permissions', $item['module'], $item['realm'], $processed, $perms[$item['grants']], $data);
101 }
102 }
103
104 function theme_aclfield_content_permissions($module, $realm, $processed, $grants, $data) {
105 $module_html = "<span class = \"aclfield-who aclfield-who-$module aclfield-who-$module-$realm\">$processed</span>";
106 $may = "<span class = \"aclfield-may aclfield-may-$module aclfield-may-$module-$realm\">" . t('may') . "</span>";
107 $grants_html = "<span class = \"aclfield-grants aclfield-grants-$module aclfield-grants-$module-$realm\">$grants</span>";
108 return "$module_html $may $grants_html";
109 }
110
111 /**
112 * Implementation of hook_widget_info().
113 */
114 function aclfield_widget_info() {
115 return array(
116 'aclfield_standard' => array(
117 'label' => 'Standard',
118 'field types' => array('aclfield'),
119 ),
120 'aclfield_hidden' => array(
121 'label' => 'Hidden from Non-Administrators',
122 'field types' => array('aclfield'),
123 ),
124 );
125 }
126
127 /**
128 * Implementation of hook_widget_settings().
129 */
130 function aclfield_widget_settings($op, $widget) {
131
132 switch ($op) {
133 case 'form':
134 // the add button was being saved for some reason...
135 unset($widget['default_perms']['add_button']);
136 // the delete button is also being saved
137 if (is_array($widget['default_perms']['perms'])) {
138 foreach(array_keys($widget['default_perms']['perms']) as $key) {
139 unset($widget['default_perms']['perms'][$key]['delete']);
140 }
141 }
142
143 $form = array();
144 $form['default_perms'] = array (
145 '#type' => 'aclfield',
146 '#title' => t('Defaults'),
147 '#default_value' => $widget['default_perms'],
148 '#multiple' => true, // TODO should tie to field...
149 );
150 $form['collapsed'] = array (
151 '#type' => 'checkbox',
152 '#title' => t('Collapse?'),
153 '#default_value' => $widget['collapsed'],
154 '#description' => t('You may hide the body of this field in a collapsible fieldset. This is useful to combine with default values so that users are not presented with information they need not change.'),
155 );
156 return $form;
157
158 case 'save':
159 return array('default_perms', 'collapsed');
160 }
161 }
162
163
164 /**
165 * Implementation of hook_widget().
166 */
167 function aclfield_widget($op, &$node, $field, &$items) {
168
169 switch ($op) {
170 case 'prepare form values':
171 // only override the items w/ the defaults if this is a new node
172 if (is_array($field['widget']['default_perms']['perms']) && !isset($node->nid)) {
173 $items = $field['widget']['default_perms']['perms'];
174 }
175 // unserailzed the data from the items
176 foreach(array_keys($items) as $key) {
177 // TODO move this to the field level?
178 // we have to check if a string, in case it came from defaults
179 if (is_string($items[$key]['data'])) {
180 $items[$key]['data'] = unserialize($items[$key]['data']);
181 }
182 // remove the deleted button if it is saved as part of the defaults
183 unset($items[$key]['delete']);
184 }
185
186 break;
187 case 'form':
188
189 switch($field['widget']['type']) {
190
191 case 'aclfield_hidden':
192 // if the user doesn't have admin nodes, give back a value instead of a form
193 if (!user_access('administer nodes')) {
194 $form[$field['field_name']] = array('#tree' => TRUE);
195 $form[$field['field_name']][]['perms'] = array(
196 '#type' => 'value',
197 '#value' => $items,
198 );
199 return $form;
200 }
201 // if the user does have administer nodes, he/she gets to see the form
202 case 'aclfield_standard':
203 $widget = array(
204 '#type' => 'aclfield',
205 '#title' => $field['widget']['label'],
206 '#multiple' => $field['multiple'],
207 '#default_value' => array(
208 'perms' => $items,
209 ),
210 '#collapsible' => true,
211 '#collapsed' => $field['widget']['collapsed'],
212 '#description' => $field['widget']['description'],
213 );
214 break;
215 }
216
217 $form[$field['field_name']] = array('#tree' => TRUE);
218 $form[$field['field_name']][] = $widget;
219 return $form;
220
221 case 'validate':
222 // TODO check for required
223 break;
224
225 case 'process form values':
226 $perms = array();
227 if(is_array($items[0]['perms'])) {
228 $perms = $items[0]['perms'];
229 }
230 $items = array();
231 foreach($perms as $perm) {
232 $items[] = array (
233 'realm' => $perm['realm'],
234 'grants' => $perm['grants'],
235 'module' => _aclfield_map_grant_to_module($perm['realm']),
236 'data' => serialize($perm['data']), // TODO move this to the field level?
237 );
238 }
239
240 break;
241 }
242 }
243
244 function _aclfield_get_grant_types() {
245 static $types;
246 if ($types) return $types;
247
248 $types = array();
249 $modules = module_implements('node_grants_info');
250 foreach($modules as $module) {
251 $res = module_invoke($module, 'node_grants_info');
252 $types[$module] = $res;
253 }
254
255 return $types;
256 }
257
258 function _aclfield_map_grant_to_module($grant) {
259 $grants = _aclfield_get_grant_types();
260 foreach($grants as $module => $mod_grants) {
261 foreach($mod_grants as $realm => $label) {
262 if ($realm == $grant) { return $module; }
263 }
264 }
265 }
266
267 function aclfield_elements() {
268 $type['aclfield'] = array(
269 '#input' => TRUE,
270 '#process' => array('aclfield_process_element' => array()),
271 );
272
273 return $type;
274 }
275
276 function aclfield_process_element($element) {
277 // TODO delete button
278 //dprint_r($element['#value']);
279
280 $perms = array();
281 $grant_types = _aclfield_get_grant_types();
282 $element['#tree'] = true;
283
284 if(is_array($element['#value']['perms'])) {
285 foreach($element['#value']['perms'] as $key => $perm) {
286 if ($element['#value']['perms'][$key]['delete']) {
287 // uncollapse the form
288 $element['#collapsed'] = false;
289 continue; // skip deleted items
290 }
291 $perms[$key] = array (
292 'realm' => $perm['realm'],
293 'grants' => $perm['grants'],
294 'module' => $module,
295 'data' => $perm['data'],
296 'module' => _aclfield_map_grant_to_module($perm['realm']),
297 );
298 }
299
300 unset($element['#value']['perms']);
301 }
302
303 // add button was pressed
304 if ($element['#value']['add_button']) {
305 $grant = $element['#value']['grant_type'];
306 if ($module = _aclfield_map_grant_to_module($grant)) {
307 //dprint_r($module);
308 if (!$element['#multiple']) {
309 $perms = array();
310 }
311 $perms[] = array (
312 'realm' => $grant,
313 'grants' => 1, // todo sync to default? or is view always good?
314 'module' => $module,
315 'data' => NULL,
316 );
317 }
318
319 // uncollapse the form
320 $element['#collapsed'] = false;
321 }
322
323 if (count($perms) < 1) {
324 $perms[] = array(
325 'realm' => 'user_all',
326 'grants' => 1,
327 'module' => 'user',
328 'data' => NULL,
329 );
330 }
331 foreach($perms as $key => $perm) {
332
333 // include some hidden information to retrieve on load
334 $element['perms'][$key]['name'] = array (
335 '#type' => 'hidden',
336 '#value' => $grant_types[$perm['module']][$perm['realm']],
337 );
338 $element['perms'][$key]['realm'] = array (
339 '#type' => 'hidden',
340 '#value' => $perm['realm'],
341 );
342
343 $module_form = call_user_func($perm['module'] . '_grant_form', $perm['realm'], $perm['data']);
344 $element['perms'][$key]['data'] = $module_form;
345 $element['perms'][$key]['data']['#parents'] = array_merge($element['#parents'], array('perms', $key, 'data'));
346
347
348 $element['perms'][$key]['grants'] = array (
349 '#type' => 'select',
350 '#title' => t('may'),
351 '#options' => array (
352 0 => t('No permissions'),
353 1 => t('View'),
354 2 => t('View & Edit'),
355 3 => t('View, Edit & Delete'),
356 ),
357 '#default_value' => $perm['grants'],
358 );
359
360 $element['perms'][$key]['delete'] = array(
361 '#type' => 'button',
362 '#value' => t('Remove'),
363 '#name' => $element['#name'] . '[perms][' . $key . '][delete]',
364 '#parents' => array_merge($element['#parents'], array('perms', $key, 'delete'))
365 );
366
367 if (!$element['#multiple']) { break; } // safety check - single fields only get 1 item
368 }
369
370 if (count($element['perms']) == 1) { // show the implied grant
371 //dprint_r($element['perms']);
372 $key = array_pop(array_keys($element['perms']));
373 // give at least 1 grant, no no perms is not an option
374 unset($element['perms'][$key]['grants']['#options'][0]);
375 // change the value to 1 if it was something else
376 $element['perms'][$key]['grants']['#value'] = 1;
377
378 // remove the delete option
379 $element['perms'][$key]['delete'] = array (
380 '#type' => 'markup',
381 '#value' => t('You may not delete this entry until you add another.')
382 );
383 }
384
385 $element['perms']['#theme'] = 'aclfield_permissions';
386
387 /* This part of the form adds a new access perm to the list */
388 if ($element['#multiple']) {
389 $select_text = t('Select a new grant priviledge');
390 } else {
391 $select_text = t('Change the grant privilege on this content to');
392 }
393 $element['grant_type'] = array (
394 '#type' => 'select',
395 '#title' => $select_text,
396 '#options' => $grant_types,
397 '#description' => t('Choose a new privilege to add to this content\'s access control list.'),
398 //'#name' => $element['#name'] . '[grant_type]',
399 );
400
401 $element['add_button'] = array(
402 '#type' => 'button',
403 '#value' => t('Add'),
404 '#name' => $element['#name'] . '[add_button]',
405
406 );
407
408 return $element;
409
410 }
411
412
413 /*** Node Access Components ***/
414
415 function aclfield_node_access_records($node) {
416 $acl_fields = _aclfield_acls_in_node($node);
417 $grants = array();
418
419 foreach($acl_fields as $field) {
420 $instance = $node->$field['field_name'];
421 foreach($instance as $item) {
422 $gids = call_user_func($item['module'] . '_grant_process_node', $item['realm'], $node, unserialize($item['data']));
423 if(is_array($gids)) {
424 foreach($gids as $gid) {
425 // check if this nid-realm-gid triple is already set
426 // TODO how to handle multiple fields and grants?
427 if ($grants[$node->nid . '-' . $item['realm'] . '-' . $gid]) {
428 // give the user the max perm possible
429 $old_grant_level = 0;
430 $old_grant_level .= $grants[$node->nid . '-' . $item['realm'] . '-' . $gid]['grant_view'] +
431 $grants[$node->nid . '-' . $item['realm'] . '-' . $gid]['grant_update'] +
432 $grants[$node->nid . '-' . $item['realm'] . '-' . $gid]['grant_delete'];
433
434 // YUCK! i do not like this
435 $items['grants'] = max($items['grants'], $old_grant_level);
436 }
437
438 $grants[$node->nid . '-' . $item['realm'] . '-' . $gid] = array(
439 'realm' => $item['realm'],
440 'gid' => $gid,
441 // TODO turn these into DEFINED values
442 'grant_view' => $item['grants'] > 0,
443 'grant_update' => $item['grants'] > 1,
444 'grant_delete' => $item['grants'] > 2,
445 'priority' => 0,
446 );
447 }
448 }
449 }
450 }
451 //dprint_r("About to return grants");
452 //dprint_r($grants);
453
454 // TODO need to uniquify the grants such that if two grants have the same nid-realm-gid id, they don't clash.
455
456 return $grants;
457 }
458
459 function _aclfield_acls_in_node(&$node) {
460 $content_fields = content_fields();
461 $accum = array();
462 foreach($content_fields as $name => $field) {
463 if ($field['type'] == 'aclfield' && array_key_exists($field['field_name'], $node)) {
464 $accum[] = $field;
465 }
466 }
467
468 return $accum;
469 }
470
471 /*** Theming ***/
472
473 function theme_aclfield_permissions($form) {
474
475 $kids = element_children($form);
476 if (count($kids) < 1) {
477 return drupal_render($form);
478 }
479 // start setting up a table of perms
480 $rows = array();
481 foreach($kids as $kid) {
482 // remove the titles from the check boxes so they don't get put in each cell
483
484 $column_1 = '<h5 class = "aclfield-permission-title">' . $form[$kid]['name']['#value'] . '</h5>';
485 $column_1 .= drupal_render($form[$kid]['data']);
486
487 $column_2 = $form[$kid]['grants']['#title'];
488 unset($form[$kid]['grants']['#title']);
489
490 $rows[] = array (
491 $column_1,
492 $column_2,
493 drupal_render($form[$kid]['grants']),
494 drupal_render($form[$kid]['delete'])
495 );
496 }
497
498 // no header needed, really
499 $output = theme('table', NULL, $rows);
500
501 $output .= drupal_render($form);
502 return $output;
503 }
504
505 function theme_aclfield($element) {
506 unset($element['#value']);
507 return theme('fieldset', $element);
508 }
509
510 /***** Some Helper Functions *****/
511
512 function aclfield_array_to_text($list, $join = 'and') {
513 switch(count($list)) {
514 case 0:
515 return t('none');
516 case 1:
517 return array_pop($list);
518 default:
519 $last = array_pop($list);
520 $rest = implode(', ', $list);
521 if ($join == 'and') {
522 return $rest . ' '. t('and') . " $last";
523 } else {
524 return $rest . ' '. t('or') . " $last";
525 }
526 }
527 }
528
529 // include hooks for other modules
530 // these should be submitted to module maintainers and incorporated
531 // into the appropriate module code.
532
533 require_once dirname(__FILE__) . '/aclfield.inc';

  ViewVC Help
Powered by ViewVC 1.1.2