Projet

Général

Profil

Paste
Télécharger (24,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / forum_access / forum_access.module @ 87dbc3bf

1
<?php
2

    
3
/**
4
 * @file
5
 * forum_access.module
6
 *
7
 * This module uses form_alter to add permissions and moderator settings to
8
 * forums.
9
 *
10
 */
11

    
12
/**
13
 * Implements hook_requirements().
14
 *
15
 * Remind the user to upgrade to Chain Menu Access API 2.x.
16
 */
17
function forum_access_requirements($phase) {
18
  $result = array();
19
  switch ( $phase ) {
20
    case 'update':
21
    case 'runtime':
22
      $t = get_t();
23
      $path = drupal_get_filename('module', 'chain_menu_access');
24
      $path = substr($path, 0, strlen($path) - 7) . '.info';
25
      $info = drupal_parse_info_file($path);
26
      $version = (isset($info['version']) ? $info['version'] : $t('Unknown'));
27
      $found = preg_match('/7\.x-([0-9]*)\./', $version, $matches);
28
      if ($found && $matches[1] == 1 || !$found) {
29
        $cma = 'Chain Menu Access API';
30
        $variables = array('@Chain_Menu_Access_API' => $cma, '@module' => url('admin/modules'));
31
        $result[] = array(
32
          'title'       => $t('@Chain_Menu_Access_API module', $variables),
33
          'value'       => $version,
34
          'description' => $t('Version 1.x is obsolete. Upgrade to version 2.x as soon as <em>all</em> installed client modules support that version.') . '<br />' .
35
                           $t('Check the <a href="@module">module administration page</a> to find out which of your modules depend on @Chain_Menu_Access_API.', $variables),
36
          'severity'    => REQUIREMENT_WARNING,
37
        );
38
      }
39
  }
40
  return $result;
41
}
42

    
43
/**
44
 * Implements hook_menu_alter().
45
 *
46
 * Remove the 'Forum' menu item if no forums are visible.
47
 */
48
function forum_access_menu_alter(&$items) {
49
  $requirements = forum_access_requirements('runtime');
50
  if (!empty($requirements) && $requirements[0]['value'] != t('Unknown')) {
51
    // Fall back to obsolete Chain Menu Access API version 7.x-1.x,
52
    // because that's what's installed.
53
    chain_menu_access_chain($items['forum'],                 'forum_access_view_any_forum', array());
54
    chain_menu_access_chain($items['node/%node'],            '_forum_access_node_access_callback', array(1, 'view'));
55
    chain_menu_access_chain($items['comment/%comment/edit'], '_forum_access_comment_edit_callback', array(1));
56
    chain_menu_access_chain($items['comment/%comment/edit'], '_forum_access_comment_access_callback', array(1, 2), TRUE);
57
    chain_menu_access_chain($items['comment/%/delete'],      '_forum_access_comment_access_callback', array(1, 2), TRUE);
58
    chain_menu_access_chain($items['comment/%/approve'],     '_forum_access_comment_access_callback', array(1, 2), TRUE);
59
    chain_menu_access_chain($items['comment/reply/%node'],   '_forum_access_comment_access_callback', array(2, 1));
60
  }
61
  else {
62
    chain_menu_access_chain($items, 'forum',                 'forum_access_view_any_forum');
63
    chain_menu_access_chain($items, 'node/%node',            '_forum_access_node_access_callback', array(1, 'view'));
64
    chain_menu_access_chain($items, 'comment/%comment/edit', '_forum_access_comment_edit_callback', array(1));
65
    chain_menu_access_chain($items, 'comment/%comment/edit', '_forum_access_comment_access_callback', array(1, 2), TRUE);
66
    chain_menu_access_chain($items, 'comment/%/delete',      '_forum_access_comment_access_callback', array(1, 2), TRUE);
67
    chain_menu_access_chain($items, 'comment/%/approve',     '_forum_access_comment_access_callback', array(1, 2), TRUE);
68
    chain_menu_access_chain($items, 'comment/reply/%node',   '_forum_access_comment_access_callback', array(2, 1));
69
  }
70
}
71

    
72
function _forum_access_node_access_callback($node, $op) {
73
  global $user;
74

    
75
  if ($op == 'view' && ($tid = _forum_access_get_tid($node))) {
76
    if (forum_access_access('update', $tid) || forum_access_access('delete', $tid)) {
77
      // Add the 'administer comments' permission to the user so that he can
78
      // see unpublished comments.
79
      forum_access_enable_moderator();
80
    }
81
    // The 'view' access check will be done by core.
82
  }
83
  return TRUE;
84
}
85

    
86
function _forum_access_comment_edit_callback($comment) {
87
  global $user;
88

    
89
  // This callback is governed by AND, return TRUE by default.
90
  $node = node_load($comment->nid);
91
  if ($tid = _forum_access_get_tid($node)) {
92
    if (!forum_access_is_moderator($user, $tid) && !forum_access_access('update', $tid, $user) && !user_access('administer comments') && !($user->uid == $comment->uid && user_access('edit own forum content'))) {
93
      return FALSE;
94
    }
95
  }
96
  return TRUE;
97
}
98

    
99
function _forum_access_comment_access_callback($comment, $op) {
100
  global $user;
101

    
102
  if ($op == 'reply') {
103
    // 'reply' is governed by AND, return TRUE by default.
104
    $node = $comment;
105
    if ($tid = _forum_access_get_tid($node)) {
106
      return forum_access_access('create', $tid);
107
    }
108
    return TRUE;
109
  }
110

    
111
  if (is_numeric($comment)) {
112
    $comment = comment_load($comment);
113
  }
114
  $node = node_load($comment->nid);
115

    
116
  // The remaining $ops are governed by OR, return FALSE by default.
117
  if ($tid = _forum_access_get_tid($node)) {
118
    if ($op == 'approve') {
119
      return $user->uid == 1 || forum_access_is_moderator($user, $tid);
120
    }
121
    if (!user_access('administer comments')) {
122
      if ($op == 'edit' && (forum_access_access('update', $tid) || user_access('edit any forum content') || ($user->uid == $comment->uid && user_access('edit own forum content')))) {
123
        forum_access_enable_moderator();
124
        return TRUE;
125
      }
126
      if ($op == 'delete' && (forum_access_access('delete', $tid) || user_access('delete any forum content') || ($user->uid == $comment->uid && user_access('delete own forum content')))) {
127
        return TRUE;
128
      }
129
    }
130
  }
131
  return FALSE;
132
}
133

    
134
/**
135
 * Access callback for the 'forum' menu item.
136
 *
137
 * Returns 1 if the user has at least one role that can access
138
 * at least one forum, 2 if the user is moderator in at least one forum,
139
 * FALSE otherwise.
140
 */
141
function forum_access_view_any_forum($account = NULL) {
142
  global $user;
143
  $returns = &drupal_static(__FUNCTION__, array());
144

    
145
  if (!isset($account)) {
146
    $account = $user;
147
  }
148

    
149
  if (!isset($returns[$account->uid])) {
150
    if (user_access('bypass node access', $account)) {
151
      return $returns[$account->uid] = 1;
152
    }
153
    if (!user_access('access content')) {
154
      return $returns[$account->uid] = FALSE;
155
    }
156
    $rids = variable_get('forum_access_rids', NULL);
157
    if (!isset($rids)) {
158
      $rids = db_query("SELECT fa.rid FROM {forum_access} fa WHERE fa.grant_view > 0 GROUP BY fa.rid")->fetchCol();
159
      variable_set('forum_access_rids', $rids);
160
    }
161
    foreach ($rids as $rid) {
162
      if (isset($account->roles[$rid])) {
163
        return $returns[$account->uid] = 1;
164
      }
165
    }
166
    // Check moderator, too.
167
    $query = db_select('acl', 'acl');
168
    $query->join('acl_user', 'aclu', "acl.acl_id = aclu.acl_id");
169
    $count = $query
170
      ->fields('acl', array('number'))
171
      ->condition('acl.module', 'forum_access')
172
      ->condition('aclu.uid', $account->uid)
173
      ->countQuery()
174
      ->execute()
175
      ->fetchField();
176
    $returns[$account->uid] = ($count > 0 ? 2 : FALSE);
177
  }
178
  return $returns[$account->uid];
179
}
180

    
181
/**
182
 * Implements hook_node_grants().
183
 *
184
 * This function supplies the forum access grants. forum_access simply uses
185
 * roles as ACLs, so rids translate directly to gids.
186
 */
187
function forum_access_node_grants($user, $op) {
188
  $grants['forum_access'] = array_keys($user->roles);
189
  return $grants;
190
}
191

    
192
/**
193
 * Implements hook_node_access_records().
194
 *
195
 * Returns a list of grant records for the passed in node object.
196
 * Checks to see if maybe we're being disabled.
197
 */
198
function forum_access_node_access_records($node) {
199
  if (!forum_access_enabled()) {
200
    return;
201
  }
202

    
203
  static $seers;
204

    
205
  $grants = &drupal_static(__FUNCTION__, array());
206
  $seers = &drupal_static(__FUNCTION__ . '__seers');
207
  $tid = _forum_access_get_tid($node);
208

    
209
  // Set proper grants for nodecomment comment nodes.
210
  //if (isset($node->comment_target_nid)) {
211
  //  if ($changed_tid = _forum_access_changed_tid()) {
212
  //    $tid = $changed_tid; // the topic node hasn't been saved yet!
213
  //  }
214
  //  else {
215
  //    $node = node_load($node->comment_target_nid);
216
  //    $tid = _forum_access_get_tid($node);
217
  //  }
218
  //}
219

    
220
  if ($tid) {
221
    if (!isset($grants[$tid])) {
222
      if (!isset($seers)) {
223
        $seers = user_roles(FALSE, 'bypass node access');
224
      }
225
      $result = db_query('SELECT * FROM {forum_access} WHERE tid = :tid', array(
226
        ':tid' => $tid
227
      ));
228
      foreach ($result as $grant) {
229
        if (isset($seers[$grant->rid])) {
230
          continue; // Don't provide any useless grants!
231
        }
232
        $grants[$tid][] = array(
233
          'realm'        => 'forum_access',
234
          'gid'          => $grant->rid,
235
          'grant_view'   => $grant->grant_view,
236
          'grant_update' => $grant->grant_update,
237
          'grant_delete' => $grant->grant_delete,
238
          'priority'     => $grant->priority,
239
        );
240
      }
241
      //dsm("forum_access_node_access_records($node->nid) (tid=$tid) returns ". var_export($grants[$tid], TRUE), 'status');
242
    }
243
    if (isset($grants[$tid])) {
244
      return $grants[$tid];
245
    }
246
  }
247
}
248

    
249
/**
250
 * Implements hook_form_alter().
251
 *
252
 * Alter the node/comment create/edit forms and various admin forms.
253
 */
254
function forum_access_form_alter(&$form, &$form_state, $form_id) {
255
  //dpm($form, "form_id($form_id)");
256
  if ($form_id == 'forum_node_form' && !empty($form['#node_edit_form'])) {
257
    _forum_access_module_load_include('node.inc');
258
    _forum_access_node_form($form, $form_state);
259
  }
260
  elseif ($form['#id'] == 'comment-form') {
261
    _forum_access_module_load_include('node.inc');
262
    _forum_access_comment_form($form, $form_state);
263
  }
264
  elseif ($form_id == 'forum_overview') {
265
    _forum_access_module_load_include('admin.inc');
266
    _forum_access_forum_overview($form, $form_state);
267
  }
268
  elseif ($form_id == 'forum_form_container') {
269
    _forum_access_module_load_include('admin.inc');
270
    _forum_access_forum_form($form, $form_state, TRUE);
271
  }
272
  elseif ($form_id == 'forum_form_forum') {
273
    _forum_access_module_load_include('admin.inc');
274
    _forum_access_forum_form($form, $form_state, FALSE);
275
  }
276
  elseif ($form_id == 'content_access_admin_settings' && empty($_POST)) {
277
    _forum_access_module_load_include('admin.inc');
278
    _forum_access_content_access_admin_form();
279
  }
280
}
281

    
282
/**
283
 * Implements hook_comment_load().
284
 */
285
function forum_access_comment_load($comments) {
286
  //TODO: Investigate usefulness of this hook.
287
  return;
288
}
289

    
290
/**
291
 * Implements hook_query_alter().
292
 */
293
function forum_access_query_alter($p1, $p2, $p3) {
294
  //TODO: Investigate usefulness of this hook.
295
  return;
296
}
297

    
298
function forum_access_query_term_access_alter(QueryAlterableInterface $query) {
299
  global $user;
300

    
301
  // Read meta-data from query, if provided.
302
  if (!$account = $query->getMetaData('account')) {
303
    $account = $user;
304
  }
305
  if (!$op = $query->getMetaData('op')) {
306
    $op = 'view';
307
  }
308

    
309
  // If $account can bypass node access, or there are no node access
310
  // modules, we don't need to alter the query.
311
  if (user_access('bypass node access', $account)) {
312
    return;
313
  }
314

    
315
  // Prevent duplicate records.
316
  $query->distinct();
317

    
318
  // Find all instances of the {taxonomy_term_data} table being joined --
319
  // could appear more than once in the query, and could be aliased.
320
  // Join each one to the forum_access table.
321

    
322
  $tables = $query->getTables();
323
  $rids = array_keys($account->roles);
324
  foreach ($tables as $talias => $tableinfo) {
325
    $table = $tableinfo['table'];
326
    if (!($table instanceof SelectQueryInterface) && $table == 'taxonomy_term_data') {
327
      // The node_access table has the access grants for any given node.
328
      $access_alias = $query->leftJoin('forum_access', 'fa', '%alias.tid = ' . $talias . '.tid');
329
      $acl_alias = $query->leftJoin('acl', 'acl', "%alias.number = $talias.tid AND %alias.module = 'forum_access'");
330
      $aclu_alias = $query->leftJoin('acl_user', 'aclu', "%alias.acl_id = $acl_alias.acl_id AND %alias.uid = $account->uid");
331
      $query->condition(db_or()
332
        ->isNull("$access_alias.rid")
333
        ->condition(db_and()
334
          ->condition("$access_alias.rid", $rids, 'IN')
335
          ->condition("$access_alias.grant_$op", 1, '>='))
336
        ->condition("$aclu_alias.uid", $account->uid));
337
    }
338
  }
339
}
340

    
341
/**
342
 * Implements hook_node_presave().
343
 */
344
function forum_access_node_presave($node, $return_old_tid = FALSE) {
345
  $old_tid = &drupal_static('forum_access_node_presave');
346
  if (_forum_node_check_node_type($node)) {
347
    $old_tid = db_query('SELECT tid FROM {forum} WHERE nid = :nid', array(
348
      ':nid' => $node->nid,
349
    ))->fetchField();
350
  }
351
}
352

    
353
/**
354
 * Implements hook_node_update().
355
 */
356
function forum_access_node_update($node) {
357
  $old_tid = &drupal_static('forum_access_node_presave');
358
  if (_forum_node_check_node_type($node)) {
359
    $tid = _forum_access_get_tid($node);
360
    if (isset($old_tid)) {
361
      if ($tid == $old_tid) {
362
        return;
363
      }
364
      acl_node_clear_acls($node->nid, 'forum_access');
365

    
366
      /*
367
      if (module_exists('nodecomment')) {
368
        _forum_access_changed_tid($tid);
369
        $result = db_query('SELECT cid FROM {node_comments} WHERE nid = :nid', array(
370
          ':nid' => $node->nid,
371
        ));
372
        foreach ($result as $row) {
373
          acl_node_clear_acls($row->cid, 'forum_access');
374
        }
375
      }
376
      */
377
    }
378
    // For changed and for previously unassigned terms we need to fake an insert.
379
    forum_access_node_insert($node);
380
  }
381
}
382

    
383
/**
384
 * Implements hook_node_insert().
385
 */
386
function forum_access_node_insert($node) {
387
  $old_tid = &drupal_static('forum_access_node_presave');
388
  if (_forum_node_check_node_type($node)) {
389
    if ($tid = _forum_access_get_tid($node)) {
390
      $acl_id = _forum_access_get_acl($tid);
391
      acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
392

    
393
      /*
394
      if (isset($old_tid) && module_exists('nodecomment')) {
395
        $result = db_query('SELECT cid FROM {node_comments} WHERE nid = :nid', array(
396
          ':nid' => $node->nid,
397
        ));
398
        foreach ($result as $row) {
399
          acl_node_add_acl($row->cid, $acl_id, 1, 1, 1);
400
          node_access_acquire_grants(node_load($row->cid)); //TODO use node_load_multiple() here
401
        }
402
      }
403
      */
404
    }
405
    $old_tid = NULL;
406
  }
407
  /*
408
  elseif (isset($node->comment_target_nid)) {
409
    // Set moderator on nodecomment.
410
    $topic_node = node_load($node->comment_target_nid);
411
    if (_forum_node_check_node_type($topic_node) && $topic_tid = _forum_access_get_tid($topic_node)) {
412
      $acl_id = _forum_access_get_acl($topic_tid);
413
      acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
414
    }
415
  }
416
  */
417
}
418

    
419
function forum_access_enable_moderator($enable = TRUE) {
420
  global $user;
421

    
422
  if (!$enable || $enable && !user_access('administer comments')) {
423
    $perm = &drupal_static('user_access');
424
    if ($enable) {
425
      $perm[$user->uid]['administer comments'] = $enable;
426
      $user->_forum_access_moderator = $enable;
427
    }
428
    else {
429
      unset($perm[$user->uid]['administer comments']);
430
      unset($user->_forum_access_moderator);
431
    }
432
  }
433
}
434

    
435
/**
436
 * Get an array of moderator UIDs or NULL.
437
 */
438
function forum_access_get_moderator_uids($tid) {
439
  $acl_id = _forum_access_get_acl($tid);
440
  if ($uids = acl_get_uids($acl_id)) {
441
    return $uids;
442
  }
443
}
444

    
445
/**
446
 * Implements hook_custom_theme().
447
 */
448
function forum_access_custom_theme() {
449
}
450

    
451
/**
452
 * Implements hook_menu_get_item_alter().
453
 *
454
 * Saves the tid on the forum-specific pages.
455
 */
456
function forum_access_menu_get_item_alter(&$router_item, $path, $original_map) {
457
  switch ($original_map[0]) {
458

    
459
    case 'forum':
460
      if (empty($original_map[1])) {
461
        forum_access_current_tid(0);
462
      }
463
      elseif (is_numeric($original_map[1])) {
464
        forum_access_current_tid($original_map[1]);
465
      }
466
      break;
467

    
468
    case 'node':
469
      if (isset($original_map[1]) && is_numeric($nid = $original_map[1]) && ($node = node_load($nid)) && ($tid = _forum_access_get_tid($node))) {
470
        forum_access_current_tid($tid);
471
      }
472
      break;
473
  }
474
}
475

    
476
/**
477
 * Saves and returns the forum TID, if we're on a forum-specific page.
478
 */
479
function forum_access_current_tid($tid = NULL) {
480
  static $saved_tid = 0;
481
  if (isset($tid)) {
482
    $saved_tid = $tid;
483
  }
484
  return $saved_tid;
485
}
486

    
487
/**
488
 * Implements $modulename_preprocess_$hook() for forum_list.
489
 *
490
 * Add forum_access_moderators to each forum,
491
 * containing a list of user objects.
492
 *
493
 * Note: On a site with many moderators, this function is expensive,
494
 * and thus it is disabled by default. Set the variable to TRUE to enable.
495
 */
496
function forum_access_preprocess_forum_list(&$variables) {
497
  if (variable_get('forum_access_provide_moderators_template_variable', FALSE)) {
498
    foreach ($variables['forums'] as $tid => $forum) {
499
      $forum->forum_access_moderators = NULL;
500
      if ($uids = forum_access_get_moderator_uids($tid)) {
501
        $forum->forum_access_moderators = user_load_multiple(uids);
502
      }
503
    }
504
  }
505
}
506

    
507
/**
508
 * Implements hook_node_view_alter().
509
 *
510
 * Remove 'Add new comment' link if it shouldn't be there.
511
 */
512
function forum_access_node_view_alter(&$build) {
513
  if ($tid = _forum_access_get_tid($build['#node'])) {
514
    _forum_access_module_load_include('node.inc');
515
    _forum_access_node_view_alter($build, $tid);
516
  }
517
}
518

    
519
/**
520
 * Implements hook_comment_view_alter().
521
 */
522
function forum_access_comment_view_alter(&$build) {
523
  if ($tid = _forum_access_get_tid($build['#node'])) {
524
    _forum_access_module_load_include('node.inc');
525
    _forum_access_comment_view_alter($build, $tid);
526
  }
527
}
528

    
529
/**
530
 * Implements $modulename_preprocess_$hook() for comment.
531
 *
532
 * Recreate comment links (they've already been themed), and
533
 * remove those that aren't accessible to the user.
534
 */
535
function forum_access_preprocess_comment(&$variables) {
536
  if (isset($variables['node']->tid)) {
537
    _forum_access_module_load_include('node.inc');
538
    _forum_access_preprocess_comment($variables);
539
  }
540
}
541

    
542
/**
543
 * This is also required by ACL module.
544
 */
545
function forum_access_enabled($set = NULL) {
546
  static $enabled = TRUE; // not drupal_static!
547
  if ($set !== NULL) {
548
    $enabled = $set;
549
  }
550
  return $enabled;
551
}
552

    
553
/**
554
 * Implements hook_node_access().
555
 */
556
function forum_access_node_access($node, $op, $account) {
557
  $cache = &drupal_static(__FUNCTION__, array());
558

    
559
  $type = is_string($node) ? $node : $node->type;
560
  if ($op == 'create') {
561
    if ($type == 'forum') {
562
      $tid = forum_access_current_tid();
563
      if (isset($cache[$account->uid][$op][$tid])) {
564
        return $cache[$account->uid][$op][$tid];
565
      }
566
      if (!forum_access_access('create', $tid, $account)) {
567
        return $cache[$account->uid][$op][$tid] = NODE_ACCESS_DENY;
568
      }
569
      return $cache[$account->uid][$op][$tid] = NODE_ACCESS_IGNORE;
570
    }
571
  }
572
  else {
573
    $nid = $node->nid;
574
    if (!isset($cache[$account->uid][$op][$nid])) {
575
      if ($tid = _forum_access_get_tid($node)) {
576
        if (!forum_access_access('view', $tid, $account)) {
577
          return $cache[$account->uid][$op][$nid] = NODE_ACCESS_DENY;
578
        }
579
        if ($op == 'update' && (user_access('edit any forum content', $account) || ($node->uid == $account->uid && user_access('edit own forum content', $account)))
580
          || $op == 'delete' && (user_access('delete any forum content', $account) || ($node->uid == $account->uid && user_access('delete own forum content', $account)))) {
581
          return $cache[$account->uid][$op][$nid] = forum_access_node_access($node, 'view', $account);
582
        }
583
        $access = forum_access_access($op, $tid, $account);
584
        if ($op == 'view' && $access == 1 && !$node->status) {
585
          if (user_access('view own unpublished content', $account) && $account->uid && $account->uid == $node->uid) {
586
            // Allow access to own unpublished node.
587
          }
588
          elseif (forum_access_is_moderator($account, $tid)) {
589
            // Allow access to moderator.
590
          }
591
          else {
592
            $access = FALSE;
593
          }
594
        }
595
        return $cache[$account->uid][$op][$nid] = ($access ? NODE_ACCESS_IGNORE : NODE_ACCESS_DENY);
596
      }
597
      else {
598
        return $cache[$account->uid][$op][$nid] = NODE_ACCESS_IGNORE;
599
      }
600
    }
601
    return $cache[$account->uid][$op][$nid];
602
  }
603
  return NODE_ACCESS_IGNORE;
604
}
605

    
606
/**
607
 * Implements access checking.
608
 *
609
 * $op -- view, update, delete or create
610
 * $tid -- the tid of the forum
611
 * $account -- the account to test for; if NULL use current user
612
 * $administer_nodes_sees_everything -- pass FALSE to ignore the 'administer nodes' permission
613
 *
614
 * Return:
615
 *   FALSE - access not granted
616
 *   1     - access granted
617
 *   2     - access granted for forum moderator
618
 */
619
function forum_access_access($op, $tid, $account = NULL, $administer_nodes_sees_everything = TRUE) {
620
  $cache = &drupal_static(__FUNCTION__, array());
621
  if (!$account) {
622
    global $user;
623
    $account = $user;
624
  }
625

    
626
  if (user_access('bypass node access', $account)) {
627
//TODO revise (including comment above)
628
//      $administer_nodes_sees_everything && user_access('administer nodes', $account) && array_search($type, array('view', 'update', 'delete')) !== FALSE) {
629
    return 1;
630
  }
631

    
632
  if ($op == 'delete' && user_access('delete any forum content', $account)) {
633
    return 1;
634
  }
635

    
636
  if ($op == 'update' && user_access('edit any forum content', $account)) {
637
    return 1;
638
  }
639

    
640
  if (!isset($cache[$account->uid][$tid][$op])) {
641
    $query = db_select('forum_access', 'fa')
642
      ->fields('fa', array('tid'))
643
      ->condition("fa.grant_$op", 1, '>=')
644
      ->condition('fa.rid', array_keys($account->roles), 'IN');
645
    if ($tid != 0) {
646
      $query = $query
647
        ->condition('fa.tid', $tid, '=');
648
    }
649
    $result = $query
650
      ->execute()
651
      ->fetchField();
652

    
653
    if ($result) {
654
      $cache[$account->uid][$tid][$op] = 1;
655
    }
656
    else {
657
      // check our moderators too
658
      $result = forum_access_is_moderator($account, $tid);
659
      $cache[$account->uid][$tid][$op] = ($result ? 2 : FALSE);
660
    }
661
  }
662
  return $cache[$account->uid][$tid][$op];
663
}
664

    
665
/**
666
 * Implements hook_taxonomy_term_delete().
667
 *
668
 * Delete {forum_access} records when forums are deleted.
669
 */
670
function forum_access_taxonomy_term_delete($term) {
671
  //dpm($array, "hook_taxonomy_term_delete($term->tid)");
672
  if ($term->vid == _forum_access_get_vid()) {
673
    db_delete('forum_access')
674
      ->condition('tid', $term->tid)
675
      ->execute();
676
    variable_del('forum_access_rids'); // clear cache
677
  }
678
}
679

    
680
/**
681
 * Implements hook_user_role_delete().
682
 */
683
function forum_access_user_role_delete($role) {
684
  db_delete('forum_access')
685
    ->condition('rid', $role->rid)
686
    ->execute();
687
  db_delete('node_access')
688
    ->condition('gid', $role->rid)
689
    ->condition('realm', 'forum_access')
690
    ->execute();
691
}
692

    
693
/**
694
 * Check whether the given user is a moderator.
695
 *
696
 * @param $account
697
 *   The user or user ID to check.
698
 * @param $tid
699
 *   ID of the forum to check or NULL to check whether the user is moderator
700
 *   in any forum at all.
701
 */
702
function forum_access_is_moderator($account, $tid = NULL) {
703
  $uid = (is_object($account) ? $account->uid : $account);
704
  return (bool) acl_get_ids_by_user('forum_access', $uid, NULL, ($tid ? $tid : NULL));
705
}
706

    
707
/**
708
 * Return forum.module's forum vocabulary ID.
709
 */
710
function _forum_access_get_vid() {
711
  return variable_get('forum_nav_vocabulary', '');
712
}
713

    
714
/**
715
 * Returns the forum tid or FALSE.
716
 */
717
function _forum_access_get_tid($node) {
718
  return (isset($node->forum_tid) ? $node->forum_tid : FALSE);
719
}
720

    
721
/**
722
 * Saves and returns the $tid.
723
 */
724
function _forum_access_changed_tid($tid = NULL) {
725
  $saved_tid = &drupal_static(__FUNCTION__);
726
  if (!empty($tid)) {
727
    $saved_tid = $tid;
728
  }
729
  return $saved_tid;
730
}
731

    
732
/**
733
 * Returns the ACL ID of the forum.
734
 */
735
function _forum_access_get_acl($tid) {
736
  $acl_id = acl_get_id_by_number('forum_access', $tid);
737
  if (!$acl_id) { // create one
738
    $acl_id = acl_create_new_acl('forum_access', NULL, $tid);
739
    $subselect = db_select('taxonomy_index', 'n');
740
    $subselect
741
      ->fields('n', array('nid'))
742
      ->condition('n.tid', $tid);
743
    acl_add_nodes($subselect, $acl_id, 1, 1, 1);
744
  }
745
  return $acl_id;
746
}
747

    
748
function _forum_access_module_load_include($type) {
749
  static $loaded = array();
750

    
751
  if (!isset($loaded[$type])) {
752
    $path = module_load_include($type, 'forum_access');
753
    $loaded[$type] = drupal_get_path('module', 'forum_access') . "/forum_access.$type";
754
  }
755
  return $loaded[$type];
756
}
757

    
758
/**
759
 * Implements hook_theme().
760
 */
761
function forum_access_theme() {
762
  return array(
763
    'forum_access_table' => array(
764
      'render element' => 'form',
765
      'file' => 'forum_access.admin.inc',
766
    ),
767
  );
768
}
769

    
770
/**
771
 * Implements hook_node_access_explain().
772
 */
773
function forum_access_node_access_explain($row) {
774
  $roles = &drupal_static(__FUNCTION__);
775
  if ($row->realm == 'forum_access') {
776
    if (!isset($roles)) {
777
      $roles = user_roles();
778
    }
779
    if (isset($roles[$row->gid])) {
780
      return array($roles[$row->gid]);
781
    }
782
    return array('(unknown gid)');
783
  }
784
}
785

    
786
/**
787
 * Implements hook_acl_explain().
788
 */
789
function forum_access_acl_explain($acl_id, $name, $number, $users = NULL) {
790
  if (empty($users)) {
791
    return "ACL (id=$acl_id) would grant access to nodes in forum/$number.";
792
  }
793
  return "ACL (id=$acl_id) grants access to nodes in forum/$number to the listed user(s).";
794
}
795