Project

General

Profile

Paste
Download (12.6 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / content_access / content_access_rules / content_access_rules.rules.inc @ ae34fb26

1
<?php
2

    
3
/**
4
 * @file
5
 * Rules specific functions that expose content_access' API.
6
 *
7
 * @todo
8
 * A way to enable per-node settings when a rule created, otherwise no effects
9
 *   will be noticed.
10
 * Clean-up function names.
11
 */
12

    
13
/**
14
 * Implements hook_rules_event_info().
15
 *
16
 * @ingroup rules
17
 */
18
function content_access_rules_rules_event_info() {
19
  $events['content_access_content_type'] = array('label' => t('Content type access control was changed'));
20
  $events['content_access_per_node'] = array(
21
    'label' => t('Per node access control was changed'),
22
    'variables' => array(
23
      'node' => array('type' => 'node', 'label' => 'Content with updated content access'),
24
    ),
25
  );
26

    
27
  if (module_exists('acl')) {
28
    $events['content_access_user_acl'] = array('label' => t('User was added to ACL'));
29
  }
30

    
31
  $items = array();
32
  foreach ($events as $name => $event) {
33
    $items[$name] = $event + array(
34
      'group' => t('Content Access'),
35
    );
36
  }
37

    
38
  return $items;
39
}
40

    
41
/**
42
 * Implementation of hook_rules_action_info().
43
 *
44
 * @ingroup rules
45
 */
46
function content_access_rules_rules_action_info() {
47
  $role_actions = array(
48
    'content_access_action_grant_node_permissions' => array(
49
      'label' => t('Grant access by role'),
50
      'description' => t('Grant access to the following content'),
51
    ),
52
    'content_access_action_revoke_node_permissions' => array(
53
      'label' => t('Revoke access by role'),
54
      'description' => t('Revoke access to the following content'),
55
    ),
56
  );
57

    
58
  $reset_actions = array(
59
    'content_access_action_reset_node_permissions' => array(
60
      'label' => t('Reset access to content type defaults'),
61
      'description' => t('Reset node permissions to default permissions'),
62
    ),
63
  );
64

    
65
  $user_actions = array(
66
    'content_access_action_user_grant' => array(
67
      'label' => t('Grant access by user'),
68
      'operation' => t('Grant'),
69
      'description' => t('Grant access to the following content'),
70
    ),
71
    'content_access_action_user_revoke' => array(
72
      'label' => t('Revoke access by user'),
73
      'operation' => t('Revoke'),
74
      'description' => t('Revoke access to the following content'),
75
    ),
76
  );
77

    
78
  $items = array();
79
  foreach ($role_actions as $name => $action) {
80
    $items[$name] = array(
81
      'label' => $action['label'],
82
      'parameter' => array(
83
        'node' => array(
84
          'type' => 'node',
85
          'label' => t('Content'),
86
          'description' => $action['description'],
87
        ),
88
        'permissions' => array(
89
          'type' => 'list<text>',
90
          'label' => t('Role-based access control settings'),
91
          'optional' => TRUE,
92
          'options list' => 'content_access_action_roles_permissions_list',
93
          'restriction' => 'input',
94
        ),
95
      ),
96
      'group' => t('Content Access'),
97
      'callbacks' => array(
98
        'form_alter' => 'content_access_rules_action_form_alter',
99
      ),
100
    );
101
  }
102

    
103
  foreach ($reset_actions as $name => $action) {
104
    $items[$name] = array(
105
      'label' => $action['label'],
106
      'parameter' => array(
107
        'node' => array(
108
          'type' => 'node',
109
          'label' => t('Content'),
110
          'description' => $action['description'],
111
        ),
112
      ),
113
      'group' => t('Content Access'),
114
    );
115
  }
116

    
117
  if (module_exists('acl')) {
118
    foreach ($user_actions as $name => $action) {
119
      $items[$name] = array(
120
        'label' => $action['label'],
121
        'named parameter' => TRUE,
122
        'parameter' => array(
123
          'node' => array(
124
            'type' => 'node',
125
            'label' => t('Content'),
126
            'description' => $action['description'],
127
          ),
128
          'content_access_user_view' => array(
129
            'type' => 'user',
130
            'label' => t('@action view access', array('@action' => $action['operation'])),
131
            'optional' => TRUE,
132
            'description' => t('@action view access to the following user.', array('@action' => $action['operation'])),
133
          ),
134
          'content_access_user_update' => array(
135
            'type' => 'user',
136
            'label' => t('@action update access', array('@action' => $action['operation'])),
137
            'optional' => TRUE,
138
            'description' => t('@action edit access to the following user.', array('@action' => $action['operation'])),
139
          ),
140
          'content_access_user_delete' => array(
141
            'type' => 'user',
142
            'label' => t('@action delete access', array('@action' => $action['operation'])),
143
            'optional' => TRUE,
144
            'description' => t('@action delete access to the following user.', array('@action' => $action['operation'])),
145
          ),
146
        ),
147
        'group' => t('Content Access User'),
148
      );
149
    }
150
  }
151

    
152
  return $items;
153
}
154

    
155
/**
156
 * Returns an options list array for the content access permission parameter.
157
 */
158
function content_access_action_roles_permissions_list() {
159
  $options = array();
160
  $roles = array_map('filter_xss_admin', user_roles());
161

    
162
  foreach (_content_access_get_operations() as $op => $label) {
163
    foreach ($roles as $rid => $role) {
164
      $options[$op][$op . ':' . $rid] = $op . ' ' . $role;
165
    }
166
  }
167
  return $options;
168
}
169

    
170
/**
171
 * Alter the settings form to render the text<list> as checkboxes.
172
 */
173
function content_access_rules_action_form_alter(&$form, &$form_state) {
174
  // Per node access control should be enabled for this type of action to be
175
  // effective.
176
  drupal_set_message(t('Access control settings will not be executed for the affected node unless you enabled \'%per_node\' from the Access Control tab on content type page of the node', array('%per_node' => 'Per content node access control settings')), 'warning');
177

    
178
  // Alter the text<list> to make it into checkboxes groups
179
  $elements =& $form['parameter']['permissions']['settings']['permissions'];
180
  $elements = content_access_rules_checkboxes_form((array) $elements['#default_value']);
181

    
182
  // Add our own after build callback for fixing the form value afterwards.
183
  $elements['#after_build'][] = 'content_access_rules_action_form_after_build';
184

    
185
  // Make sure our include file is loaded when FAPI processes the form.
186
  form_load_include($form_state, 'inc', 'content_access_rules', 'content_access_rules.rules');
187
}
188

    
189
/**
190
 * Form after build callback.
191
 *
192
 * Get the form settings as checkboxes, convert them back to list<text>.
193
 */
194
function content_access_rules_action_form_after_build($element, &$form_state) {
195
  if ($form_state['process_input']) {
196
    $form_value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
197
    $value = content_access_rules_transform_to_rule_value($form_value);
198
    form_set_value($element, $value, $form_state);
199
  }
200
  return $element;
201
}
202

    
203
/**
204
 * Returns the form elements for configuring content access per-role permissions.
205
 */
206
function content_access_rules_checkboxes_form($value) {
207
  $form = array();
208
  $roles = array_map('filter_xss_admin', user_roles());
209
  $defaults = content_access_rules_transform_rules_value($value);
210

    
211
  foreach (_content_access_get_operations() as $op => $label) {
212
    $form[$op] = array(
213
      '#type' => 'checkboxes',
214
      '#prefix' => '<div class="content_access-div">',
215
      '#suffix' => '</div>',
216
      '#options' => $roles,
217
      '#title' => $label,
218
      '#default_value' => isset($defaults[$op]) ? $defaults[$op] : array(),
219
      '#process' => array('form_process_checkboxes', 'content_access_disable_checkboxes'),
220
    );
221
  }
222
  $form['clearer'] = array(
223
    '#value' => '<br clear="all" />',
224
  );
225
  drupal_add_css(drupal_get_path('module', 'content_access') . '/content_access.css');
226

    
227
  return $form;
228
}
229

    
230
/**
231
 * Transforms the array of text values used by Rules to an array keyed by $op and $rid.
232
 *
233
 * @see content_access_rules_transform_to_rule_value()
234
 */
235
function content_access_rules_transform_rules_value($value) {
236
  $array = array();
237
  foreach ($value as $op_role) {
238
    $parts = explode(':', $op_role);
239
    // The first item is $op and the second $rid.
240
    $array[$parts[0]][] = $parts[1];
241
  }
242
  return $array;
243
}
244

    
245
/**
246
 * Transform the form values array keyed by $op and $rid to an array of text values as used by Rules.
247
 *
248
 * @see content_access_rules_transform_rules_value()
249
 */
250
function content_access_rules_transform_to_rule_value($form_values) {
251
  $value = array();
252
  foreach ($form_values as $op => $array) {
253
    foreach (array_filter($array) as $rid => $data) {
254
      $value[] = $op . ':' . $rid;
255
    }
256
  }
257
  return $value;
258
}
259

    
260
/**
261
 * Action implementation: Grant permissions for a node.
262
 */
263
function content_access_action_grant_node_permissions($node, $permissions) {
264
  if (!empty($node->nid) && _content_access_rules_check_setting($node)) {
265
    // Transform the value to the content-access format.
266
    $settings = content_access_rules_transform_rules_value($permissions);
267
    $ca_settings = array();
268
    foreach (_content_access_get_operations() as $op => $label) {
269
      // Merge in the array of role-ids for each operation.
270
      $settings += array($op => array());
271
      $ca_settings[$op] = array_keys(array_flip(content_access_per_node_setting($op, $node)) + array_flip($settings[$op]));
272
    }
273
    content_access_save_per_node_settings($node, $ca_settings);
274
    content_access_action_aquire_grants($node);
275
  }
276
}
277

    
278
/**
279
 * Action implementation: Revoke permissions for a node.
280
 */
281
function content_access_action_revoke_node_permissions($node, $permissions) {
282
  if (!empty($node->nid) && _content_access_rules_check_setting($node)) {
283
    // Transform the value to the content-access format.
284
    $settings = content_access_rules_transform_rules_value($permissions);
285

    
286
    $ca_settings = array();
287
    foreach (_content_access_get_operations() as $op => $label) {
288
      $settings += array($op => array());
289
      $ca_settings[$op] = array_diff(content_access_per_node_setting($op, $node), $settings[$op]);
290
    }
291
    content_access_save_per_node_settings($node, $ca_settings);
292
    content_access_action_aquire_grants($node);
293
  }
294
}
295

    
296
/**
297
 * Action implementation: Reset permissions for a node.
298
 */
299
function content_access_action_reset_node_permissions($node) {
300
  content_access_delete_per_node_settings($node);
301
  content_access_action_aquire_grants($node);
302
}
303

    
304
/**
305
 * Verifies that per content settings are activated for the given node.
306
 */
307
function _content_access_rules_check_setting($node) {
308
  $type = $node->type;
309
  $settings = variable_get('content_access_' . $type, array());
310

    
311
  if (isset($settings['per_node']) && $settings['per_node']) {
312
    return TRUE;
313
  }
314

    
315
  // If we didn't find any settings in content access for this type return
316
  // false as we don't want to process it.
317
  rules_log("Can't set per content permissions for content type @type. Make sure to have per content settings activated for content types you want to alter access control for.", array('@type' => $node->type), RulesLog::WARN);
318
  return FALSE;
319
}
320

    
321
/**
322
 * Split the settings string into array.
323
 */
324
function content_access_action_settings($action_settings = array()) {
325
  $roles_ids = array_flip(user_roles());
326

    
327
  foreach (_content_access_get_operations() as $op => $label) {
328
    $settings[$op] = array();
329
  }
330

    
331
  foreach ($action_settings as $op_role => $role) {
332
    $op = substr($op_role, 0, strpos($op_role, ':'));
333
    $rid = $roles_ids[$role];
334
    $settings[$op][] = $rid;
335
  }
336

    
337
  return $settings;
338
}
339

    
340
/**
341
 * Action implementation: Grant user access.
342
 */
343
function content_access_action_user_grant($params) {
344
  content_access_action_user($params, 'grant');
345
}
346

    
347
/**
348
 * Action implementation: Revoke user access.
349
 */
350
function content_access_action_user_revoke($params) {
351
  content_access_action_user($params, 'revoke');
352
}
353

    
354
/**
355
 * Process Rule's param, and grant by the passed operation.
356
 */
357
function content_access_action_user($params, $type) {
358
  $ops = array('view', 'update', 'delete');
359
  $settings = array();
360
  $node = $params['node'];
361

    
362
  foreach ($ops as $op) {
363
    if ($params['content_access_user_' . $op]) {
364
      $settings[$op] = $params['content_access_user_' . $op]->uid;
365
    }
366
  }
367

    
368
  foreach ($settings as $op => $uid) {
369
    $acl_id = content_access_get_acl_id($node, $op);
370
    acl_node_add_acl($node->nid, $acl_id, (int) ($op == 'view'), (int) ($op == 'update'), (int) ($op == 'delete'), content_access_get_settings('priority', $node->type));
371

    
372
    db_delete('acl_user')
373
      ->condition('acl_id', $acl_id)
374
      ->condition('uid', $uid)
375
      ->execute();
376

    
377
    if ($type == 'grant') {
378
      db_insert('acl_user')
379
        ->fields(array(
380
          'acl_id' => $acl_id,
381
          'uid' => $uid,
382
        ))
383
        ->execute();
384
    }
385
  }
386

    
387
  content_access_action_aquire_grants($node);
388
}
389

    
390
/**
391
 * Apply the new grants to the affected node.
392
 */
393
function content_access_action_aquire_grants($node) {
394
  // node_save() does implement node_access_acquire_grants() so we don't want
395
  // to execute it again or we'll get a duplicated key exception
396
  if (!isset($node->op) ||
397
      (isset($node->op) && $node->op != t('Save'))) {
398
    node_access_acquire_grants($node);
399
  }
400
}