Projet

Général

Profil

Paste
Télécharger (10,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / acl / acl.module @ 651307cd

1
<?php
2

    
3
/**
4
 * @file
5
 * An API module providing by-user access control lists.
6
 *
7
 * This module handles ACLs on behalf of other modules. The two main reasons
8
 * to do this are so that modules using ACLs can share them with each
9
 * other without having to actually know much about them, and so that
10
 * ACLs can easily co-exist with the existing node_access system.
11
 */
12

    
13
/**
14
 * Create a new ACL.
15
 *
16
 * The client module will have to keep track of the ACL. For that it can
17
 * assign either a $name or a $number to this ACL.
18
 *
19
 * @param $module
20
 *   The name of the client module.
21
 * @param $name
22
 *   An arbitrary name for this ACL, freely defined by the client module.
23
 * @param $number
24
 *   An arbitrary number for this ACL, freely defined by the client module.
25
 * @return
26
 *   The ID of the newly created ACL.
27
 */
28
function acl_create_acl($module, $name = NULL, $number = NULL) {
29
  $acl = array(
30
    'module' => $module,
31
    'name' => $name,
32
    'number' => $number
33
  );
34
  drupal_write_record('acl', $acl);
35
  return $acl['acl_id'];
36
}
37

    
38
/**
39
 * Create a new ACL (obsolete).
40
 *
41
 * @see acl_create_acl()
42
 */
43
function acl_create_new_acl($module, $name = NULL, $number = NULL) {
44
  return acl_create_acl($module, $name, $number);
45
}
46

    
47
/**
48
 * Delete an existing ACL.
49
 */
50
function acl_delete_acl($acl_id) {
51
  db_delete('acl')
52
    ->condition('acl_id', $acl_id)
53
    ->execute();
54
  db_delete('acl_user')
55
    ->condition('acl_id', $acl_id)
56
    ->execute();
57
  db_delete('acl_node')
58
    ->condition('acl_id', $acl_id)
59
    ->execute();
60
}
61

    
62
/**
63
 * Add the specified UID to an ACL.
64
 */
65
function acl_add_user($acl_id, $uid) {
66
  $test_uid = db_query("SELECT uid FROM {acl_user} WHERE acl_id = :acl_id AND uid = :uid", array(
67
    'acl_id' => $acl_id,
68
    'uid' => $uid,
69
  ))->fetchField();
70
  if (!$test_uid) {
71
    db_insert('acl_user')
72
    ->fields(array(
73
      'acl_id' => $acl_id,
74
      'uid' => $uid,
75
    ))
76
    ->execute();
77
  }
78
}
79

    
80
/**
81
 * Remove the specified UID from an ACL.
82
 */
83
function acl_remove_user($acl_id, $uid) {
84
  db_delete('acl_user')
85
    ->condition('acl_id', $acl_id)
86
    ->condition('uid', $uid)
87
    ->execute();
88
}
89

    
90
/**
91
 * Provide a form to edit the ACL that can be embedded in other forms.
92
 *
93
 * Pass $new_acl=TRUE if you have no ACL yet, but do supply a string
94
 * like 'my_module_new_acl' as $acl_id anyway; create the ACL and set
95
 * $form['acl_id'] before calling acl_save_form().
96
 */
97
function acl_edit_form(&$form_state, $acl_id, $label = NULL, $new_acl = FALSE) {
98
  $form_state['build_info']['files'][] = _acl_module_load_include('admin.inc');
99
  return _acl_edit_form($acl_id, $label, $new_acl);
100
}
101

    
102
/**
103
 * Provide access control to all nodes selected by a subquery, based upon an ACL id.
104
 */
105
function acl_add_nodes($subselect, $acl_id, $view, $update, $delete, $priority = 0) {
106
  db_delete('acl_node')
107
    ->condition('acl_id', $acl_id)
108
    ->condition('nid', $subselect, 'IN')
109
    ->execute();
110
  $subselect->addExpression($acl_id, 'acl_id');
111
  $subselect->addExpression((int) $view, 'grant_view');
112
  $subselect->addExpression((int) $update, 'grant_update');
113
  $subselect->addExpression((int) $delete, 'grant_delete');
114
  $subselect->addExpression($priority, 'priority');
115
  db_insert('acl_node')
116
    ->from($subselect)
117
    ->execute();
118
}
119

    
120
/**
121
 * Provide access control to a node based upon an ACL id.
122
 */
123
function acl_node_add_acl($nid, $acl_id, $view, $update, $delete, $priority = 0) {
124
  acl_node_add_acl_record(array(
125
    'acl_id'       => $acl_id,
126
    'nid'          => $nid,
127
    'grant_view'   => (int) $view,
128
    'grant_update' => (int) $update,
129
    'grant_delete' => (int) $delete,
130
    'priority'     => $priority,
131
  ));
132
}
133

    
134
/**
135
 * Provide access control to a node based upon an ACL id.
136
 */
137
function acl_node_add_acl_record(array $record) {
138
  db_delete('acl_node')
139
    ->condition('acl_id', $record['acl_id'])
140
    ->condition('nid', $record['nid'])
141
    ->execute();
142
  db_insert('acl_node')
143
    ->fields($record)
144
    ->execute();
145
}
146

    
147
/**
148
 * Remove an ACL completely from a node.
149
 */
150
function acl_node_remove_acl($nid, $acl_id) {
151
  db_delete('acl_node')
152
    ->condition('acl_id', $acl_id)
153
    ->condition('nid', $nid)
154
    ->execute();
155
}
156

    
157
/**
158
 * Clear all of a module's ACLs from a node.
159
 */
160
function acl_node_clear_acls($nid, $module) {
161
  $select = db_select('acl', 'a')
162
    ->fields('a', array('acl_id'))
163
    ->condition('a.module', $module);
164
  db_delete('acl_node')
165
    ->condition('nid', $nid)
166
    ->condition('acl_id', $select, 'IN')
167
    ->execute();
168
}
169

    
170
/**
171
 * Get the id of an ACL by name (+ optionally number).
172
 */
173
function acl_get_id_by_name($module, $name, $number = NULL) {
174
  $query = db_select('acl', 'a')
175
    ->fields('a', array('acl_id'))
176
    ->condition('a.module', $module)
177
    ->condition('a.name', $name);
178
  if (isset($number)) {
179
    $query->condition('a.number', $number);
180
  }
181
  return $query->execute()->fetchField();
182
}
183

    
184
/**
185
 * Get the id of an ACL by number.
186
 */
187
function acl_get_id_by_number($module, $number) {
188
  $query = db_select('acl', 'a')
189
    ->fields('a', array('acl_id'))
190
    ->condition('a.module', $module)
191
    ->condition('a.number', $number);
192
  return $query->execute()->fetchField();
193
}
194

    
195
/**
196
 * Determine whether an ACL has some assigned users.
197
 */
198
function acl_has_users($acl_id) {
199
  return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id", array(
200
    'acl_id' => $acl_id,
201
  ))->fetchField();
202
}
203

    
204
/**
205
 * Determine whether an ACL has a specific assigned user.
206
 */
207
function acl_has_user($acl_id, $uid) {
208
  return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id AND uid = :uid", array(
209
    'acl_id' => $acl_id,
210
    'uid' => $uid,
211
  ))->fetchField();
212
}
213

    
214
/**
215
 * Get an array of acl_ids held by a user.
216
 */
217
function acl_get_ids_by_user($module, $uid, $name = NULL, $number = NULL) {
218
  $query = db_select('acl', 'a');
219
  $query->join('acl_user', 'au', 'a.acl_id = au.acl_id');
220
  $query
221
    ->fields('a', array('acl_id'))
222
    ->condition('a.module', $module)
223
    ->condition('au.uid', $uid);
224
  if (isset($name)) {
225
    $query->condition('a.name', $name);
226
  }
227
  if (isset($number)) {
228
    $query->condition('a.number', $number);
229
  }
230
  $acl_ids = $query->execute()->fetchCol();
231
  return $acl_ids;
232
}
233

    
234
/**
235
 * Get the uids of an ACL.
236
 */
237
function acl_get_uids($acl_id) {
238
  $uids = db_query("SELECT uid FROM {acl_user} WHERE acl_id = :acl_id", array(
239
    'acl_id' => $acl_id,
240
  ))->fetchCol();
241
  return $uids;
242
}
243

    
244
/**
245
 * Implements hook_node_access_records().
246
 */
247
function acl_node_access_records($node) {
248
  if (!$node->nid) {
249
    return;
250
  }
251
  $result = db_query("SELECT n.*, 'acl' AS realm, n.acl_id AS gid, a.module FROM {acl_node} n INNER JOIN {acl} a ON n.acl_id = a.acl_id WHERE nid = :nid", array(
252
    'nid' => $node->nid,
253
  ), array('fetch' => PDO::FETCH_ASSOC));
254
  $grants = array();
255
  foreach ($result as $grant) {
256
    if (module_invoke($grant['module'], 'enabled')) {
257
      if (acl_has_users($grant['gid'])) {
258
        $grants[] = $grant;
259
      }
260
      else {
261
        //just deny access
262
        $grants[] = array(
263
          'realm' => 'acl',
264
          'gid' => $grant['gid'],
265
          'grant_view' => 0,
266
          'grant_update' => 0,
267
          'grant_delete' => 0,
268
          'priority' => $grant['priority'],
269
        );
270
      }
271
    }
272
  }
273
  return $grants;
274
}
275

    
276
/**
277
 * Implements hook_node_grants().
278
 */
279
function acl_node_grants($account, $op) {
280
  $acl_ids = db_query("SELECT acl_id FROM {acl_user} WHERE uid = :uid", array(
281
    'uid' => $account->uid,
282
  ))->fetchCol();
283
  return (!empty($acl_ids) ? array('acl' => $acl_ids) : NULL);
284
}
285

    
286
/**
287
 * Implements hook_node_delete().
288
 */
289
function acl_node_delete($node) {
290
  db_delete('acl_node')
291
    ->condition('nid', $node->nid)
292
    ->execute();
293
}
294

    
295
/**
296
 * Implements hook_user_cancel().
297
 */
298
function acl_user_cancel($edit, $account, $method) {
299
  db_delete('acl_user')
300
    ->condition('uid', $account->uid)
301
    ->execute();
302
}
303

    
304
/**
305
 * Helper function to load include files.
306
 */
307
function _acl_module_load_include($type) {
308
  static $loaded = array();
309

    
310
  if (!isset($loaded[$type])) {
311
    $path = module_load_include($type, 'acl');
312
    $loaded[$type] = drupal_get_path('module', 'acl') . "/acl.$type";
313
  }
314
  return $loaded[$type];
315
}
316

    
317
/**
318
 * Implements hook_node_access_explain().
319
 */
320
function acl_node_access_explain($row) {
321
  static $interpretations = array();
322
  if ($row->realm == 'acl') {
323
    if (!isset($interpretations[$row->gid])) {
324
      $acl = db_query("SELECT * FROM {acl} WHERE acl_id = :acl_id", array(
325
        'acl_id' => $row->gid,
326
      ))->fetchObject();
327
      $acl->tag = '?';
328
      if (!isset($acl->name)) {
329
        $acl->tag = $acl->number;
330
      }
331
      elseif (!isset($acl->number)) {
332
        $acl->tag = $acl->name;
333
      }
334
      else {
335
        $acl->tag = $acl->name . '-' . $acl->number;
336
      }
337
      foreach (user_load_multiple(acl_get_uids($row->gid)) as $account) {
338
        $usernames[] = theme('username', array('account' => $account));
339
      }
340
      if (isset($usernames)) {
341
        $usernames = implode(', ', $usernames);
342
        $interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: $usernames", $acl->acl_id, $acl->module, $acl->name, $acl->number, $usernames);
343
      }
344
      elseif ($row->gid == 0) {
345
        $result = db_query("SELECT an.acl_id, a.module, a.name FROM {acl_node} an JOIN {acl} a ON an.acl_id = a.acl_id LEFT JOIN {acl_user} au ON a.acl_id = au.acl_id WHERE an.nid = :nid AND au.uid IS NULL", array(
346
          'nid' => $row->nid,
347
        ));
348
        foreach ($result as $acl) {
349
          $rows[] = _acl_get_explanation("$acl->acl_id:&nbsp;$acl->module/$acl->tag", $acl->acl_id, $acl->module, $acl->name, $acl->number);
350
        }
351
        if (!empty($rows)) {
352
          return implode('<br />', $rows);
353
        }
354
        return 'No access via ACL.';
355
      }
356
      else {
357
        $interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: no users!", $acl->acl_id, $acl->module, $acl->name, $acl->number);
358
      }
359
    }
360
    return $interpretations[$row->gid];
361
  }
362
}
363

    
364
/**
365
 * Helper function to ask the client for its interpretation of the given
366
 * grant record.
367
 */
368
function _acl_get_explanation($text, $acl_id, $module, $name, $number, $usernames = NULL) {
369
  $hook = $module . '_acl_explain';
370
  if (function_exists($hook)) {
371
    return '<span title="' . $hook($acl_id, $name, $number, $usernames) . '">' . $text . '</span>';
372
  }
373
  return $text;
374
}
375