Projet

Général

Profil

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

root / drupal7 / sites / all / modules / acl / acl.module @ cfceb792

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
 * Remove all users from an ACL.
92
 */
93
function acl_remove_all_users($acl_id) {
94
  db_delete('acl_user')
95
    ->condition('acl_id', $acl_id)
96
    ->execute();
97
}
98

    
99
/**
100
 * Provide a form to edit the ACL that can be embedded in other forms.
101
 *
102
 * Pass $new_acl=TRUE if you have no ACL yet, but do supply a string
103
 * like 'my_module_new_acl' as $acl_id anyway; create the ACL and set
104
 * $form['acl_id'] before calling acl_save_form().
105
 */
106
function acl_edit_form(&$form_state, $acl_id, $label = NULL, $new_acl = FALSE) {
107
  $form_state['build_info']['files'][] = _acl_module_load_include('admin.inc');
108
  return _acl_edit_form($acl_id, $label, $new_acl);
109
}
110

    
111
/**
112
 * Provide access control to all nodes selected by a subquery, based upon an ACL id.
113
 */
114
function acl_add_nodes($subselect, $acl_id, $view, $update, $delete, $priority = 0) {
115
  db_delete('acl_node')
116
    ->condition('acl_id', $acl_id)
117
    ->condition('nid', $subselect, 'IN')
118
    ->execute();
119
  $subselect->addExpression($acl_id, 'acl_id');
120
  $subselect->addExpression((int) $view, 'grant_view');
121
  $subselect->addExpression((int) $update, 'grant_update');
122
  $subselect->addExpression((int) $delete, 'grant_delete');
123
  $subselect->addExpression($priority, 'priority');
124
  $query = db_insert('acl_node')
125
    ->fields(array('nid', 'acl_id', 'grant_view', 'grant_update', 'grant_delete', 'priority'));
126
  foreach ($subselect->execute()->fetchAll(PDO::FETCH_ASSOC) as $record) {
127
    $query->values($record);
128
  }
129
  $query->execute();
130
}
131

    
132
/**
133
 * Provide access control to a node based upon an ACL id.
134
 */
135
function acl_node_add_acl($nid, $acl_id, $view, $update, $delete, $priority = 0) {
136
  acl_node_add_acl_record(array(
137
    'acl_id'       => $acl_id,
138
    'nid'          => $nid,
139
    'grant_view'   => (int) $view,
140
    'grant_update' => (int) $update,
141
    'grant_delete' => (int) $delete,
142
    'priority'     => $priority,
143
  ));
144
}
145

    
146
/**
147
 * Provide access control to a node based upon an ACL id.
148
 */
149
function acl_node_add_acl_record(array $record) {
150
  db_delete('acl_node')
151
    ->condition('acl_id', $record['acl_id'])
152
    ->condition('nid', $record['nid'])
153
    ->execute();
154
  db_insert('acl_node')
155
    ->fields($record)
156
    ->execute();
157
}
158

    
159
/**
160
 * Remove an ACL completely from a node.
161
 */
162
function acl_node_remove_acl($nid, $acl_id) {
163
  db_delete('acl_node')
164
    ->condition('acl_id', $acl_id)
165
    ->condition('nid', $nid)
166
    ->execute();
167
}
168

    
169
/**
170
 * Clear all of a module's ACLs from a node.
171
 */
172
function acl_node_clear_acls($nid, $module) {
173
  $select = db_select('acl', 'a')
174
    ->fields('a', array('acl_id'))
175
    ->condition('a.module', $module);
176
  db_delete('acl_node')
177
    ->condition('nid', $nid)
178
    ->condition('acl_id', $select, 'IN')
179
    ->execute();
180
}
181

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

    
196
/**
197
 * Get the id of an ACL by number.
198
 */
199
function acl_get_id_by_number($module, $number) {
200
  $query = db_select('acl', 'a')
201
    ->fields('a', array('acl_id'))
202
    ->condition('a.module', $module)
203
    ->condition('a.number', $number);
204
  return $query->execute()->fetchField();
205
}
206

    
207
/**
208
 * Determine whether an ACL has some assigned users.
209
 */
210
function acl_has_users($acl_id) {
211
  return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id", array(
212
    'acl_id' => $acl_id,
213
  ))->fetchField();
214
}
215

    
216
/**
217
 * Determine whether an ACL has a specific assigned user.
218
 */
219
function acl_has_user($acl_id, $uid) {
220
  return db_query("SELECT COUNT(uid) FROM {acl_user} WHERE acl_id = :acl_id AND uid = :uid", array(
221
    'acl_id' => $acl_id,
222
    'uid' => $uid,
223
  ))->fetchField();
224
}
225

    
226
/**
227
 * Get an array of acl_ids held by a user.
228
 */
229
function acl_get_ids_by_user($module, $uid, $name = NULL, $number = NULL) {
230
  $query = db_select('acl', 'a');
231
  $query->join('acl_user', 'au', 'a.acl_id = au.acl_id');
232
  $query
233
    ->fields('a', array('acl_id'))
234
    ->condition('a.module', $module)
235
    ->condition('au.uid', $uid);
236
  if (isset($name)) {
237
    $query->condition('a.name', $name);
238
  }
239
  if (isset($number)) {
240
    $query->condition('a.number', $number);
241
  }
242
  $acl_ids = $query->execute()->fetchCol();
243
  return $acl_ids;
244
}
245

    
246
/**
247
 * Get the uids of an ACL.
248
 */
249
function acl_get_uids($acl_id) {
250
  $uids = db_query("SELECT uid FROM {acl_user} WHERE acl_id = :acl_id", array(
251
    'acl_id' => $acl_id,
252
  ))->fetchCol();
253
  return $uids;
254
}
255

    
256
/**
257
 * Get the user names of an ACL.
258
 */
259
function acl_get_usernames($acl_id) {
260
  _acl_module_load_include('admin.inc');
261
  return _acl_get_usernames($acl_id);
262
}
263

    
264
/**
265
 * Implements hook_node_access_records().
266
 */
267
function acl_node_access_records($node) {
268
  if (!$node->nid) {
269
    return;
270
  }
271
  $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(
272
    'nid' => $node->nid,
273
  ), array('fetch' => PDO::FETCH_ASSOC));
274
  $grants = array();
275
  foreach ($result as $grant) {
276
    if (module_invoke($grant['module'], 'enabled')) {
277
      if (acl_has_users($grant['gid'])) {
278
        $grants[] = $grant;
279
      }
280
      else {
281
        //just deny access
282
        $grants[] = array(
283
          'realm' => 'acl',
284
          'gid' => $grant['gid'],
285
          'grant_view' => 0,
286
          'grant_update' => 0,
287
          'grant_delete' => 0,
288
          'priority' => $grant['priority'],
289
        );
290
      }
291
    }
292
  }
293
  return $grants;
294
}
295

    
296
/**
297
 * Implements hook_node_grants().
298
 */
299
function acl_node_grants($account, $op) {
300
  $acl_ids = db_query("SELECT acl_id FROM {acl_user} WHERE uid = :uid", array(
301
    'uid' => $account->uid,
302
  ))->fetchCol();
303
  return (!empty($acl_ids) ? array('acl' => $acl_ids) : NULL);
304
}
305

    
306
/**
307
 * Implements hook_node_delete().
308
 */
309
function acl_node_delete($node) {
310
  db_delete('acl_node')
311
    ->condition('nid', $node->nid)
312
    ->execute();
313
}
314

    
315
/**
316
 * Implements hook_user_cancel().
317
 */
318
function acl_user_cancel($edit, $account, $method) {
319
  db_delete('acl_user')
320
    ->condition('uid', $account->uid)
321
    ->execute();
322
}
323

    
324
/**
325
 * Helper function to load include files.
326
 */
327
function _acl_module_load_include($type) {
328
  static $loaded = array();
329

    
330
  if (!isset($loaded[$type])) {
331
    module_load_include($type, 'acl');
332
    $loaded[$type] = drupal_get_path('module', 'acl') . "/acl.$type";
333
  }
334
  return $loaded[$type];
335
}
336

    
337
/**
338
 * Implements hook_node_access_explain().
339
 */
340
function acl_node_access_explain($row) {
341
  static $interpretations = array();
342
  if ($row->realm == 'acl') {
343
    if (!isset($interpretations[$row->gid])) {
344
      $acl = db_query("SELECT * FROM {acl} WHERE acl_id = :acl_id", array(
345
        'acl_id' => $row->gid,
346
      ))->fetchObject();
347
      $acl->tag = '?';
348
      if (!isset($acl->name)) {
349
        $acl->tag = $acl->number;
350
      }
351
      elseif (!isset($acl->number)) {
352
        $acl->tag = $acl->name;
353
      }
354
      else {
355
        $acl->tag = $acl->name . '-' . $acl->number;
356
      }
357
      foreach (user_load_multiple(acl_get_uids($row->gid)) as $account) {
358
        $usernames[] = _acl_format_username($account);
359
      }
360
      if (isset($usernames)) {
361
        $usernames = implode(', ', $usernames);
362
        $interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: $usernames", $acl->acl_id, $acl->module, $acl->name, $acl->number, $usernames);
363
      }
364
      elseif ($row->gid == 0) {
365
        $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(
366
          'nid' => $row->nid,
367
        ));
368
        foreach ($result as $acl) {
369
          $rows[] = _acl_get_explanation("$acl->acl_id:&nbsp;$acl->module/$acl->tag", $acl->acl_id, $acl->module, $acl->name, $acl->number);
370
        }
371
        if (!empty($rows)) {
372
          return implode('<br />', $rows);
373
        }
374
        return 'No access via ACL.';
375
      }
376
      else {
377
        $interpretations[$row->gid] = _acl_get_explanation("$acl->module/$acl->tag: no users!", $acl->acl_id, $acl->module, $acl->name, $acl->number);
378
      }
379
    }
380
    return $interpretations[$row->gid];
381
  }
382
}
383

    
384
/**
385
 * Helper function to ask the client for its interpretation of the given
386
 * grant record.
387
 */
388
function _acl_get_explanation($text, $acl_id, $module, $name, $number, $usernames = NULL) {
389
  $hook = $module . '_acl_explain';
390
  if (function_exists($hook)) {
391
    return '<span title="' . $hook($acl_id, $name, $number, $usernames) . '">' . $text . '</span>';
392
  }
393
  return $text;
394
}
395

    
396
/**
397
 * Helper function to format a user name.
398
 */
399
function _acl_format_username($account) {
400
  return check_plain(format_username($account));
401
}
402