1 |
85ad3d82
|
Assos Assos
|
<?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 |
136a805a
|
Assos Assos
|
require_once DRUPAL_ROOT . '/includes/install.inc';
|
19 |
85ad3d82
|
Assos Assos
|
$result = array();
|
20 |
|
|
switch ( $phase ) {
|
21 |
|
|
case 'update':
|
22 |
|
|
case 'runtime':
|
23 |
|
|
$t = get_t();
|
24 |
|
|
$path = drupal_get_filename('module', 'chain_menu_access');
|
25 |
|
|
$path = substr($path, 0, strlen($path) - 7) . '.info';
|
26 |
|
|
$info = drupal_parse_info_file($path);
|
27 |
|
|
$version = (isset($info['version']) ? $info['version'] : $t('Unknown'));
|
28 |
|
|
$found = preg_match('/7\.x-([0-9]*)\./', $version, $matches);
|
29 |
e9734207
|
Assos Assos
|
if (($found && $matches[1] == 1) || !$found) {
|
30 |
85ad3d82
|
Assos Assos
|
$cma = 'Chain Menu Access API';
|
31 |
|
|
$variables = array('@Chain_Menu_Access_API' => $cma, '@module' => url('admin/modules'));
|
32 |
|
|
$result[] = array(
|
33 |
|
|
'title' => $t('@Chain_Menu_Access_API module', $variables),
|
34 |
|
|
'value' => $version,
|
35 |
|
|
'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 />' .
|
36 |
|
|
$t('Check the <a href="@module">module administration page</a> to find out which of your modules depend on @Chain_Menu_Access_API.', $variables),
|
37 |
|
|
'severity' => REQUIREMENT_WARNING,
|
38 |
|
|
);
|
39 |
|
|
}
|
40 |
|
|
}
|
41 |
|
|
return $result;
|
42 |
|
|
}
|
43 |
|
|
|
44 |
|
|
/**
|
45 |
|
|
* Implements hook_menu_alter().
|
46 |
|
|
*
|
47 |
|
|
* Remove the 'Forum' menu item if no forums are visible.
|
48 |
|
|
*/
|
49 |
|
|
function forum_access_menu_alter(&$items) {
|
50 |
|
|
$requirements = forum_access_requirements('runtime');
|
51 |
|
|
if (!empty($requirements) && $requirements[0]['value'] != t('Unknown')) {
|
52 |
|
|
// Fall back to obsolete Chain Menu Access API version 7.x-1.x,
|
53 |
|
|
// because that's what's installed.
|
54 |
|
|
chain_menu_access_chain($items['forum'], 'forum_access_view_any_forum', array());
|
55 |
|
|
chain_menu_access_chain($items['node/%node'], '_forum_access_node_access_callback', array(1, 'view'));
|
56 |
|
|
chain_menu_access_chain($items['comment/%comment/edit'], '_forum_access_comment_edit_callback', array(1));
|
57 |
|
|
chain_menu_access_chain($items['comment/%comment/edit'], '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
58 |
|
|
chain_menu_access_chain($items['comment/%/delete'], '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
59 |
|
|
chain_menu_access_chain($items['comment/%/approve'], '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
60 |
|
|
chain_menu_access_chain($items['comment/reply/%node'], '_forum_access_comment_access_callback', array(2, 1));
|
61 |
|
|
}
|
62 |
|
|
else {
|
63 |
|
|
chain_menu_access_chain($items, 'forum', 'forum_access_view_any_forum');
|
64 |
|
|
chain_menu_access_chain($items, 'node/%node', '_forum_access_node_access_callback', array(1, 'view'));
|
65 |
|
|
chain_menu_access_chain($items, 'comment/%comment/edit', '_forum_access_comment_edit_callback', array(1));
|
66 |
|
|
chain_menu_access_chain($items, 'comment/%comment/edit', '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
67 |
|
|
chain_menu_access_chain($items, 'comment/%/delete', '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
68 |
|
|
chain_menu_access_chain($items, 'comment/%/approve', '_forum_access_comment_access_callback', array(1, 2), TRUE);
|
69 |
|
|
chain_menu_access_chain($items, 'comment/reply/%node', '_forum_access_comment_access_callback', array(2, 1));
|
70 |
|
|
}
|
71 |
|
|
}
|
72 |
|
|
|
73 |
|
|
function _forum_access_node_access_callback($node, $op) {
|
74 |
|
|
global $user;
|
75 |
|
|
|
76 |
|
|
if ($op == 'view' && ($tid = _forum_access_get_tid($node))) {
|
77 |
|
|
if (forum_access_access('update', $tid) || forum_access_access('delete', $tid)) {
|
78 |
|
|
// Add the 'administer comments' permission to the user so that he can
|
79 |
|
|
// see unpublished comments.
|
80 |
|
|
forum_access_enable_moderator();
|
81 |
|
|
}
|
82 |
|
|
// The 'view' access check will be done by core.
|
83 |
|
|
}
|
84 |
|
|
return TRUE;
|
85 |
|
|
}
|
86 |
|
|
|
87 |
|
|
function _forum_access_comment_edit_callback($comment) {
|
88 |
|
|
global $user;
|
89 |
|
|
|
90 |
|
|
// This callback is governed by AND, return TRUE by default.
|
91 |
|
|
$node = node_load($comment->nid);
|
92 |
|
|
if ($tid = _forum_access_get_tid($node)) {
|
93 |
|
|
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'))) {
|
94 |
|
|
return FALSE;
|
95 |
|
|
}
|
96 |
|
|
}
|
97 |
|
|
return TRUE;
|
98 |
|
|
}
|
99 |
|
|
|
100 |
|
|
function _forum_access_comment_access_callback($comment, $op) {
|
101 |
|
|
global $user;
|
102 |
|
|
|
103 |
|
|
if ($op == 'reply') {
|
104 |
|
|
// 'reply' is governed by AND, return TRUE by default.
|
105 |
|
|
$node = $comment;
|
106 |
|
|
if ($tid = _forum_access_get_tid($node)) {
|
107 |
|
|
return forum_access_access('create', $tid);
|
108 |
|
|
}
|
109 |
|
|
return TRUE;
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
if (is_numeric($comment)) {
|
113 |
|
|
$comment = comment_load($comment);
|
114 |
136a805a
|
Assos Assos
|
if (empty($comment)) {
|
115 |
|
|
return FALSE;
|
116 |
|
|
}
|
117 |
85ad3d82
|
Assos Assos
|
}
|
118 |
e9734207
|
Assos Assos
|
elseif (is_string($comment)) {
|
119 |
|
|
return FALSE;
|
120 |
|
|
}
|
121 |
85ad3d82
|
Assos Assos
|
$node = node_load($comment->nid);
|
122 |
|
|
|
123 |
|
|
// The remaining $ops are governed by OR, return FALSE by default.
|
124 |
|
|
if ($tid = _forum_access_get_tid($node)) {
|
125 |
|
|
if ($op == 'approve') {
|
126 |
|
|
return $user->uid == 1 || forum_access_is_moderator($user, $tid);
|
127 |
|
|
}
|
128 |
|
|
if (!user_access('administer comments')) {
|
129 |
|
|
if ($op == 'edit' && (forum_access_access('update', $tid) || user_access('edit any forum content') || ($user->uid == $comment->uid && user_access('edit own forum content')))) {
|
130 |
|
|
forum_access_enable_moderator();
|
131 |
|
|
return TRUE;
|
132 |
|
|
}
|
133 |
|
|
if ($op == 'delete' && (forum_access_access('delete', $tid) || user_access('delete any forum content') || ($user->uid == $comment->uid && user_access('delete own forum content')))) {
|
134 |
|
|
return TRUE;
|
135 |
|
|
}
|
136 |
|
|
}
|
137 |
|
|
}
|
138 |
|
|
return FALSE;
|
139 |
|
|
}
|
140 |
|
|
|
141 |
|
|
/**
|
142 |
|
|
* Access callback for the 'forum' menu item.
|
143 |
|
|
*
|
144 |
|
|
* Returns 1 if the user has at least one role that can access
|
145 |
|
|
* at least one forum, 2 if the user is moderator in at least one forum,
|
146 |
|
|
* FALSE otherwise.
|
147 |
|
|
*/
|
148 |
|
|
function forum_access_view_any_forum($account = NULL) {
|
149 |
|
|
global $user;
|
150 |
|
|
$returns = &drupal_static(__FUNCTION__, array());
|
151 |
|
|
|
152 |
|
|
if (!isset($account)) {
|
153 |
|
|
$account = $user;
|
154 |
|
|
}
|
155 |
|
|
|
156 |
|
|
if (!isset($returns[$account->uid])) {
|
157 |
|
|
if (user_access('bypass node access', $account)) {
|
158 |
|
|
return $returns[$account->uid] = 1;
|
159 |
|
|
}
|
160 |
|
|
if (!user_access('access content')) {
|
161 |
|
|
return $returns[$account->uid] = FALSE;
|
162 |
|
|
}
|
163 |
|
|
$rids = variable_get('forum_access_rids', NULL);
|
164 |
|
|
if (!isset($rids)) {
|
165 |
|
|
$rids = db_query("SELECT fa.rid FROM {forum_access} fa WHERE fa.grant_view > 0 GROUP BY fa.rid")->fetchCol();
|
166 |
|
|
variable_set('forum_access_rids', $rids);
|
167 |
|
|
}
|
168 |
|
|
foreach ($rids as $rid) {
|
169 |
|
|
if (isset($account->roles[$rid])) {
|
170 |
|
|
return $returns[$account->uid] = 1;
|
171 |
|
|
}
|
172 |
|
|
}
|
173 |
|
|
// Check moderator, too.
|
174 |
|
|
$query = db_select('acl', 'acl');
|
175 |
|
|
$query->join('acl_user', 'aclu', "acl.acl_id = aclu.acl_id");
|
176 |
|
|
$count = $query
|
177 |
|
|
->fields('acl', array('number'))
|
178 |
|
|
->condition('acl.module', 'forum_access')
|
179 |
|
|
->condition('aclu.uid', $account->uid)
|
180 |
|
|
->countQuery()
|
181 |
|
|
->execute()
|
182 |
|
|
->fetchField();
|
183 |
|
|
$returns[$account->uid] = ($count > 0 ? 2 : FALSE);
|
184 |
|
|
}
|
185 |
|
|
return $returns[$account->uid];
|
186 |
|
|
}
|
187 |
|
|
|
188 |
|
|
/**
|
189 |
|
|
* Implements hook_node_grants().
|
190 |
|
|
*
|
191 |
|
|
* This function supplies the forum access grants. forum_access simply uses
|
192 |
|
|
* roles as ACLs, so rids translate directly to gids.
|
193 |
|
|
*/
|
194 |
|
|
function forum_access_node_grants($user, $op) {
|
195 |
|
|
$grants['forum_access'] = array_keys($user->roles);
|
196 |
|
|
return $grants;
|
197 |
|
|
}
|
198 |
|
|
|
199 |
|
|
/**
|
200 |
|
|
* Implements hook_node_access_records().
|
201 |
|
|
*
|
202 |
|
|
* Returns a list of grant records for the passed in node object.
|
203 |
|
|
* Checks to see if maybe we're being disabled.
|
204 |
|
|
*/
|
205 |
|
|
function forum_access_node_access_records($node) {
|
206 |
|
|
if (!forum_access_enabled()) {
|
207 |
|
|
return;
|
208 |
|
|
}
|
209 |
|
|
|
210 |
|
|
static $seers;
|
211 |
|
|
|
212 |
|
|
$grants = &drupal_static(__FUNCTION__, array());
|
213 |
|
|
$seers = &drupal_static(__FUNCTION__ . '__seers');
|
214 |
|
|
$tid = _forum_access_get_tid($node);
|
215 |
|
|
|
216 |
|
|
// Set proper grants for nodecomment comment nodes.
|
217 |
|
|
//if (isset($node->comment_target_nid)) {
|
218 |
|
|
// if ($changed_tid = _forum_access_changed_tid()) {
|
219 |
|
|
// $tid = $changed_tid; // the topic node hasn't been saved yet!
|
220 |
|
|
// }
|
221 |
|
|
// else {
|
222 |
|
|
// $node = node_load($node->comment_target_nid);
|
223 |
|
|
// $tid = _forum_access_get_tid($node);
|
224 |
|
|
// }
|
225 |
|
|
//}
|
226 |
|
|
|
227 |
|
|
if ($tid) {
|
228 |
|
|
if (!isset($grants[$tid])) {
|
229 |
|
|
if (!isset($seers)) {
|
230 |
|
|
$seers = user_roles(FALSE, 'bypass node access');
|
231 |
|
|
}
|
232 |
|
|
$result = db_query('SELECT * FROM {forum_access} WHERE tid = :tid', array(
|
233 |
|
|
':tid' => $tid
|
234 |
|
|
));
|
235 |
|
|
foreach ($result as $grant) {
|
236 |
|
|
if (isset($seers[$grant->rid])) {
|
237 |
|
|
continue; // Don't provide any useless grants!
|
238 |
|
|
}
|
239 |
|
|
$grants[$tid][] = array(
|
240 |
|
|
'realm' => 'forum_access',
|
241 |
|
|
'gid' => $grant->rid,
|
242 |
|
|
'grant_view' => $grant->grant_view,
|
243 |
|
|
'grant_update' => $grant->grant_update,
|
244 |
|
|
'grant_delete' => $grant->grant_delete,
|
245 |
|
|
'priority' => $grant->priority,
|
246 |
|
|
);
|
247 |
|
|
}
|
248 |
|
|
//dsm("forum_access_node_access_records($node->nid) (tid=$tid) returns ". var_export($grants[$tid], TRUE), 'status');
|
249 |
|
|
}
|
250 |
|
|
if (isset($grants[$tid])) {
|
251 |
|
|
return $grants[$tid];
|
252 |
|
|
}
|
253 |
|
|
}
|
254 |
|
|
}
|
255 |
|
|
|
256 |
|
|
/**
|
257 |
|
|
* Implements hook_form_alter().
|
258 |
|
|
*
|
259 |
|
|
* Alter the node/comment create/edit forms and various admin forms.
|
260 |
|
|
*/
|
261 |
|
|
function forum_access_form_alter(&$form, &$form_state, $form_id) {
|
262 |
|
|
//dpm($form, "form_id($form_id)");
|
263 |
|
|
if ($form_id == 'forum_node_form' && !empty($form['#node_edit_form'])) {
|
264 |
|
|
_forum_access_module_load_include('node.inc');
|
265 |
|
|
_forum_access_node_form($form, $form_state);
|
266 |
|
|
}
|
267 |
|
|
elseif ($form['#id'] == 'comment-form') {
|
268 |
|
|
_forum_access_module_load_include('node.inc');
|
269 |
|
|
_forum_access_comment_form($form, $form_state);
|
270 |
|
|
}
|
271 |
|
|
elseif ($form_id == 'forum_overview') {
|
272 |
|
|
_forum_access_module_load_include('admin.inc');
|
273 |
|
|
_forum_access_forum_overview($form, $form_state);
|
274 |
|
|
}
|
275 |
|
|
elseif ($form_id == 'forum_form_container') {
|
276 |
|
|
_forum_access_module_load_include('admin.inc');
|
277 |
|
|
_forum_access_forum_form($form, $form_state, TRUE);
|
278 |
|
|
}
|
279 |
|
|
elseif ($form_id == 'forum_form_forum') {
|
280 |
|
|
_forum_access_module_load_include('admin.inc');
|
281 |
|
|
_forum_access_forum_form($form, $form_state, FALSE);
|
282 |
|
|
}
|
283 |
|
|
elseif ($form_id == 'content_access_admin_settings' && empty($_POST)) {
|
284 |
|
|
_forum_access_module_load_include('admin.inc');
|
285 |
136a805a
|
Assos Assos
|
_forum_access_content_access_admin_form($form_state['build_info']['args'][0]);
|
286 |
85ad3d82
|
Assos Assos
|
}
|
287 |
|
|
}
|
288 |
|
|
|
289 |
e9734207
|
Assos Assos
|
/**
|
290 |
|
|
* Implements hook_form_node_form_alter().
|
291 |
|
|
*
|
292 |
|
|
* Allows the forum field to be optional on non-forum nodes.
|
293 |
|
|
*/
|
294 |
|
|
function forum_access_form_node_form_alter(&$form, &$form_state, $form_id) {
|
295 |
|
|
if (isset($form['taxonomy_forums'])) {
|
296 |
|
|
$field = field_info_instance('node', 'taxonomy_forums', $form['type']['#value']);
|
297 |
|
|
// Make the vocabulary required for 'real' forum-nodes.
|
298 |
|
|
if (!$field['required']) {
|
299 |
|
|
$langcode = $form['taxonomy_forums']['#language'];
|
300 |
|
|
$form['taxonomy_forums'][$langcode]['#required'] = FALSE;
|
301 |
|
|
}
|
302 |
|
|
}
|
303 |
|
|
}
|
304 |
|
|
|
305 |
|
|
/**
|
306 |
|
|
* Implement hook_node_load().
|
307 |
|
|
*
|
308 |
|
|
* Sets $node->forum_tid to avoid confusing forum_node_view().
|
309 |
|
|
*/
|
310 |
|
|
function forum_access_node_load($nodes, $types) {
|
311 |
|
|
foreach ($nodes as $node) {
|
312 |
|
|
if (isset($node->taxonomy_forums) && empty($node->taxonomy_forums) && !isset($node->forum_tid)) {
|
313 |
|
|
$node->forum_tid = NULL;
|
314 |
|
|
}
|
315 |
|
|
}
|
316 |
|
|
}
|
317 |
|
|
|
318 |
85ad3d82
|
Assos Assos
|
/**
|
319 |
|
|
* Implements hook_comment_load().
|
320 |
|
|
*/
|
321 |
|
|
function forum_access_comment_load($comments) {
|
322 |
|
|
//TODO: Investigate usefulness of this hook.
|
323 |
|
|
return;
|
324 |
|
|
}
|
325 |
|
|
|
326 |
|
|
/**
|
327 |
|
|
* Implements hook_query_alter().
|
328 |
|
|
*/
|
329 |
|
|
function forum_access_query_alter($p1, $p2, $p3) {
|
330 |
|
|
//TODO: Investigate usefulness of this hook.
|
331 |
|
|
return;
|
332 |
|
|
}
|
333 |
|
|
|
334 |
e9734207
|
Assos Assos
|
/**
|
335 |
|
|
* Implements hook_query_term_access_alter().
|
336 |
|
|
*
|
337 |
|
|
* @param QueryAlterableInterface $query
|
338 |
|
|
*/
|
339 |
85ad3d82
|
Assos Assos
|
function forum_access_query_term_access_alter(QueryAlterableInterface $query) {
|
340 |
|
|
global $user;
|
341 |
|
|
|
342 |
|
|
// Read meta-data from query, if provided.
|
343 |
|
|
if (!$account = $query->getMetaData('account')) {
|
344 |
|
|
$account = $user;
|
345 |
|
|
}
|
346 |
|
|
if (!$op = $query->getMetaData('op')) {
|
347 |
|
|
$op = 'view';
|
348 |
|
|
}
|
349 |
|
|
|
350 |
e9734207
|
Assos Assos
|
// If $account can bypass node access, we let them administer the full forum
|
351 |
|
|
// structure and see the nodes, i.e. we don't restrict the query.
|
352 |
|
|
if (user_access('bypass node access', $account) && (strpos(current_path(), 'admin/structure/forum') === 0 || strpos(current_path(), 'node/') === 0)) {
|
353 |
85ad3d82
|
Assos Assos
|
return;
|
354 |
|
|
}
|
355 |
|
|
|
356 |
|
|
// Prevent duplicate records.
|
357 |
|
|
$query->distinct();
|
358 |
|
|
|
359 |
|
|
// Find all instances of the {taxonomy_term_data} table being joined --
|
360 |
|
|
// could appear more than once in the query, and could be aliased.
|
361 |
|
|
// Join each one to the forum_access table.
|
362 |
|
|
|
363 |
|
|
$tables = $query->getTables();
|
364 |
|
|
$rids = array_keys($account->roles);
|
365 |
|
|
foreach ($tables as $talias => $tableinfo) {
|
366 |
|
|
$table = $tableinfo['table'];
|
367 |
|
|
if (!($table instanceof SelectQueryInterface) && $table == 'taxonomy_term_data') {
|
368 |
|
|
// The node_access table has the access grants for any given node.
|
369 |
|
|
$access_alias = $query->leftJoin('forum_access', 'fa', '%alias.tid = ' . $talias . '.tid');
|
370 |
|
|
$acl_alias = $query->leftJoin('acl', 'acl', "%alias.number = $talias.tid AND %alias.module = 'forum_access'");
|
371 |
e9734207
|
Assos Assos
|
if (user_access('bypass node access', $account)) {
|
372 |
|
|
// If $account can bypass node access, we allow access if any role or
|
373 |
|
|
// account has access.
|
374 |
|
|
$aclu_alias = $query->leftJoin('acl_user', 'aclu', "%alias.acl_id = $acl_alias.acl_id");
|
375 |
|
|
$query->condition(db_or()
|
376 |
|
|
->isNull("$access_alias.rid")
|
377 |
|
|
->condition("$access_alias.grant_$op", 1, '>=')
|
378 |
|
|
->isNotNull("$aclu_alias.uid")
|
379 |
|
|
);
|
380 |
|
|
}
|
381 |
|
|
else {
|
382 |
|
|
$aclu_alias = $query->leftJoin('acl_user', 'aclu', "%alias.acl_id = $acl_alias.acl_id AND %alias.uid = $account->uid");
|
383 |
|
|
$query->condition(db_or()
|
384 |
|
|
->isNull("$access_alias.rid")
|
385 |
|
|
->condition(db_and()
|
386 |
|
|
->condition("$access_alias.rid", $rids, 'IN')
|
387 |
|
|
->condition("$access_alias.grant_$op", 1, '>='))
|
388 |
|
|
->condition("$aclu_alias.uid", $account->uid));
|
389 |
|
|
}
|
390 |
85ad3d82
|
Assos Assos
|
}
|
391 |
|
|
}
|
392 |
|
|
}
|
393 |
|
|
|
394 |
|
|
/**
|
395 |
|
|
* Implements hook_node_presave().
|
396 |
|
|
*/
|
397 |
|
|
function forum_access_node_presave($node, $return_old_tid = FALSE) {
|
398 |
|
|
$old_tid = &drupal_static('forum_access_node_presave');
|
399 |
|
|
if (_forum_node_check_node_type($node)) {
|
400 |
e9734207
|
Assos Assos
|
if (empty($node->nid)) {
|
401 |
|
|
// Added for migrations, which log errors due to no nid during presave, see #3003279.
|
402 |
|
|
$old_tid = NULL;
|
403 |
|
|
}
|
404 |
|
|
else {
|
405 |
|
|
$old_tid = db_query('SELECT tid FROM {forum} WHERE nid = :nid', array(
|
406 |
|
|
':nid' => $node->nid,
|
407 |
|
|
))->fetchField();
|
408 |
|
|
}
|
409 |
|
|
}
|
410 |
|
|
if (!empty($old_tid) && empty($node->taxonomy_forums['und'])) {
|
411 |
|
|
$node->forum_tid = null;
|
412 |
85ad3d82
|
Assos Assos
|
}
|
413 |
|
|
}
|
414 |
|
|
|
415 |
|
|
/**
|
416 |
|
|
* Implements hook_node_update().
|
417 |
|
|
*/
|
418 |
|
|
function forum_access_node_update($node) {
|
419 |
|
|
$old_tid = &drupal_static('forum_access_node_presave');
|
420 |
|
|
if (_forum_node_check_node_type($node)) {
|
421 |
|
|
$tid = _forum_access_get_tid($node);
|
422 |
|
|
if (isset($old_tid)) {
|
423 |
|
|
if ($tid == $old_tid) {
|
424 |
|
|
return;
|
425 |
|
|
}
|
426 |
|
|
acl_node_clear_acls($node->nid, 'forum_access');
|
427 |
|
|
|
428 |
|
|
/*
|
429 |
|
|
if (module_exists('nodecomment')) {
|
430 |
|
|
_forum_access_changed_tid($tid);
|
431 |
|
|
$result = db_query('SELECT cid FROM {node_comments} WHERE nid = :nid', array(
|
432 |
|
|
':nid' => $node->nid,
|
433 |
|
|
));
|
434 |
|
|
foreach ($result as $row) {
|
435 |
|
|
acl_node_clear_acls($row->cid, 'forum_access');
|
436 |
|
|
}
|
437 |
|
|
}
|
438 |
|
|
*/
|
439 |
|
|
}
|
440 |
|
|
// For changed and for previously unassigned terms we need to fake an insert.
|
441 |
|
|
forum_access_node_insert($node);
|
442 |
|
|
}
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
/**
|
446 |
|
|
* Implements hook_node_insert().
|
447 |
|
|
*/
|
448 |
|
|
function forum_access_node_insert($node) {
|
449 |
|
|
$old_tid = &drupal_static('forum_access_node_presave');
|
450 |
|
|
if (_forum_node_check_node_type($node)) {
|
451 |
|
|
if ($tid = _forum_access_get_tid($node)) {
|
452 |
|
|
$acl_id = _forum_access_get_acl($tid);
|
453 |
|
|
acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
|
454 |
|
|
|
455 |
|
|
/*
|
456 |
|
|
if (isset($old_tid) && module_exists('nodecomment')) {
|
457 |
|
|
$result = db_query('SELECT cid FROM {node_comments} WHERE nid = :nid', array(
|
458 |
|
|
':nid' => $node->nid,
|
459 |
|
|
));
|
460 |
|
|
foreach ($result as $row) {
|
461 |
|
|
acl_node_add_acl($row->cid, $acl_id, 1, 1, 1);
|
462 |
|
|
node_access_acquire_grants(node_load($row->cid)); //TODO use node_load_multiple() here
|
463 |
|
|
}
|
464 |
|
|
}
|
465 |
|
|
*/
|
466 |
|
|
}
|
467 |
|
|
$old_tid = NULL;
|
468 |
|
|
}
|
469 |
|
|
/*
|
470 |
|
|
elseif (isset($node->comment_target_nid)) {
|
471 |
|
|
// Set moderator on nodecomment.
|
472 |
|
|
$topic_node = node_load($node->comment_target_nid);
|
473 |
|
|
if (_forum_node_check_node_type($topic_node) && $topic_tid = _forum_access_get_tid($topic_node)) {
|
474 |
|
|
$acl_id = _forum_access_get_acl($topic_tid);
|
475 |
|
|
acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
|
476 |
|
|
}
|
477 |
|
|
}
|
478 |
|
|
*/
|
479 |
|
|
}
|
480 |
|
|
|
481 |
|
|
function forum_access_enable_moderator($enable = TRUE) {
|
482 |
|
|
global $user;
|
483 |
|
|
|
484 |
e9734207
|
Assos Assos
|
if (!$enable || !user_access('administer comments')) {
|
485 |
85ad3d82
|
Assos Assos
|
$perm = &drupal_static('user_access');
|
486 |
|
|
if ($enable) {
|
487 |
|
|
$perm[$user->uid]['administer comments'] = $enable;
|
488 |
|
|
$user->_forum_access_moderator = $enable;
|
489 |
|
|
}
|
490 |
|
|
else {
|
491 |
|
|
unset($perm[$user->uid]['administer comments']);
|
492 |
|
|
unset($user->_forum_access_moderator);
|
493 |
|
|
}
|
494 |
|
|
}
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
/**
|
498 |
|
|
* Get an array of moderator UIDs or NULL.
|
499 |
|
|
*/
|
500 |
|
|
function forum_access_get_moderator_uids($tid) {
|
501 |
|
|
$acl_id = _forum_access_get_acl($tid);
|
502 |
|
|
if ($uids = acl_get_uids($acl_id)) {
|
503 |
|
|
return $uids;
|
504 |
|
|
}
|
505 |
|
|
}
|
506 |
|
|
|
507 |
|
|
/**
|
508 |
|
|
* Implements hook_custom_theme().
|
509 |
|
|
*/
|
510 |
|
|
function forum_access_custom_theme() {
|
511 |
|
|
}
|
512 |
|
|
|
513 |
|
|
/**
|
514 |
|
|
* Implements hook_menu_get_item_alter().
|
515 |
|
|
*
|
516 |
|
|
* Saves the tid on the forum-specific pages.
|
517 |
|
|
*/
|
518 |
|
|
function forum_access_menu_get_item_alter(&$router_item, $path, $original_map) {
|
519 |
136a805a
|
Assos Assos
|
if (forum_access_current_tid() == 0) {
|
520 |
|
|
switch ($original_map[0]) {
|
521 |
|
|
case 'forum':
|
522 |
|
|
if (isset($original_map[1]) && is_numeric($original_map[1])) {
|
523 |
|
|
forum_access_current_tid($original_map[1]);
|
524 |
|
|
}
|
525 |
|
|
break;
|
526 |
|
|
case 'node':
|
527 |
|
|
if (isset($original_map[1]) && is_numeric($nid = $original_map[1]) && ($node = node_load($nid)) && ($tid = _forum_access_get_tid($node))) {
|
528 |
|
|
forum_access_current_tid($tid);
|
529 |
|
|
}
|
530 |
|
|
break;
|
531 |
|
|
}
|
532 |
85ad3d82
|
Assos Assos
|
}
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
/**
|
536 |
|
|
* Saves and returns the forum TID, if we're on a forum-specific page.
|
537 |
|
|
*/
|
538 |
|
|
function forum_access_current_tid($tid = NULL) {
|
539 |
|
|
static $saved_tid = 0;
|
540 |
|
|
if (isset($tid)) {
|
541 |
|
|
$saved_tid = $tid;
|
542 |
|
|
}
|
543 |
|
|
return $saved_tid;
|
544 |
|
|
}
|
545 |
|
|
|
546 |
|
|
/**
|
547 |
|
|
* Implements $modulename_preprocess_$hook() for forum_list.
|
548 |
|
|
*
|
549 |
|
|
* Add forum_access_moderators to each forum,
|
550 |
|
|
* containing a list of user objects.
|
551 |
|
|
*
|
552 |
|
|
* Note: On a site with many moderators, this function is expensive,
|
553 |
|
|
* and thus it is disabled by default. Set the variable to TRUE to enable.
|
554 |
|
|
*/
|
555 |
|
|
function forum_access_preprocess_forum_list(&$variables) {
|
556 |
|
|
if (variable_get('forum_access_provide_moderators_template_variable', FALSE)) {
|
557 |
|
|
foreach ($variables['forums'] as $tid => $forum) {
|
558 |
|
|
$forum->forum_access_moderators = NULL;
|
559 |
|
|
if ($uids = forum_access_get_moderator_uids($tid)) {
|
560 |
136a805a
|
Assos Assos
|
$forum->forum_access_moderators = user_load_multiple($uids);
|
561 |
85ad3d82
|
Assos Assos
|
}
|
562 |
|
|
}
|
563 |
|
|
}
|
564 |
|
|
}
|
565 |
|
|
|
566 |
|
|
/**
|
567 |
|
|
* Implements hook_node_view_alter().
|
568 |
|
|
*
|
569 |
e9734207
|
Assos Assos
|
* Remove 'Add new comment' link and breadcrumb if they shouldn't be there.
|
570 |
85ad3d82
|
Assos Assos
|
*/
|
571 |
|
|
function forum_access_node_view_alter(&$build) {
|
572 |
|
|
if ($tid = _forum_access_get_tid($build['#node'])) {
|
573 |
|
|
_forum_access_module_load_include('node.inc');
|
574 |
|
|
_forum_access_node_view_alter($build, $tid);
|
575 |
|
|
}
|
576 |
e9734207
|
Assos Assos
|
|
577 |
|
|
$breadcrumb = drupal_get_breadcrumb();
|
578 |
|
|
if (!$tid && count($breadcrumb) == 2 && strpos($breadcrumb[0], '<a href="/">') === 0 && strpos($breadcrumb[1], '<a href="/forum">') === 0) {
|
579 |
|
|
// We must hack away the bogus breadcrumb set by forum module
|
580 |
|
|
// (empty taxonomy_forums).
|
581 |
|
|
$stored_breadcrumb = &drupal_static('drupal_set_breadcrumb');
|
582 |
|
|
$stored_breadcrumb = NULL;
|
583 |
|
|
}
|
584 |
85ad3d82
|
Assos Assos
|
}
|
585 |
|
|
|
586 |
|
|
/**
|
587 |
|
|
* Implements hook_comment_view_alter().
|
588 |
|
|
*/
|
589 |
|
|
function forum_access_comment_view_alter(&$build) {
|
590 |
|
|
if ($tid = _forum_access_get_tid($build['#node'])) {
|
591 |
|
|
_forum_access_module_load_include('node.inc');
|
592 |
|
|
_forum_access_comment_view_alter($build, $tid);
|
593 |
|
|
}
|
594 |
|
|
}
|
595 |
|
|
|
596 |
|
|
/**
|
597 |
|
|
* This is also required by ACL module.
|
598 |
|
|
*/
|
599 |
|
|
function forum_access_enabled($set = NULL) {
|
600 |
|
|
static $enabled = TRUE; // not drupal_static!
|
601 |
|
|
if ($set !== NULL) {
|
602 |
|
|
$enabled = $set;
|
603 |
|
|
}
|
604 |
|
|
return $enabled;
|
605 |
|
|
}
|
606 |
|
|
|
607 |
|
|
/**
|
608 |
|
|
* Implements hook_node_access().
|
609 |
|
|
*/
|
610 |
|
|
function forum_access_node_access($node, $op, $account) {
|
611 |
|
|
$cache = &drupal_static(__FUNCTION__, array());
|
612 |
|
|
|
613 |
|
|
$type = is_string($node) ? $node : $node->type;
|
614 |
|
|
if ($op == 'create') {
|
615 |
|
|
if ($type == 'forum') {
|
616 |
|
|
$tid = forum_access_current_tid();
|
617 |
|
|
if (isset($cache[$account->uid][$op][$tid])) {
|
618 |
|
|
return $cache[$account->uid][$op][$tid];
|
619 |
|
|
}
|
620 |
|
|
if (!forum_access_access('create', $tid, $account)) {
|
621 |
|
|
return $cache[$account->uid][$op][$tid] = NODE_ACCESS_DENY;
|
622 |
|
|
}
|
623 |
|
|
return $cache[$account->uid][$op][$tid] = NODE_ACCESS_IGNORE;
|
624 |
|
|
}
|
625 |
|
|
}
|
626 |
|
|
else {
|
627 |
|
|
$nid = $node->nid;
|
628 |
|
|
if (!isset($cache[$account->uid][$op][$nid])) {
|
629 |
|
|
if ($tid = _forum_access_get_tid($node)) {
|
630 |
|
|
if (!forum_access_access('view', $tid, $account)) {
|
631 |
|
|
return $cache[$account->uid][$op][$nid] = NODE_ACCESS_DENY;
|
632 |
|
|
}
|
633 |
e9734207
|
Assos Assos
|
if (($op == 'update' && (user_access('edit any forum content', $account) || ($node->uid == $account->uid && user_access('edit own forum content', $account))))
|
634 |
|
|
|| ($op == 'delete' && (user_access('delete any forum content', $account) || ($node->uid == $account->uid && user_access('delete own forum content', $account))))) {
|
635 |
85ad3d82
|
Assos Assos
|
return $cache[$account->uid][$op][$nid] = forum_access_node_access($node, 'view', $account);
|
636 |
|
|
}
|
637 |
|
|
$access = forum_access_access($op, $tid, $account);
|
638 |
|
|
if ($op == 'view' && $access == 1 && !$node->status) {
|
639 |
|
|
if (user_access('view own unpublished content', $account) && $account->uid && $account->uid == $node->uid) {
|
640 |
|
|
// Allow access to own unpublished node.
|
641 |
|
|
}
|
642 |
|
|
elseif (forum_access_is_moderator($account, $tid)) {
|
643 |
|
|
// Allow access to moderator.
|
644 |
|
|
}
|
645 |
|
|
else {
|
646 |
|
|
$access = FALSE;
|
647 |
|
|
}
|
648 |
|
|
}
|
649 |
|
|
return $cache[$account->uid][$op][$nid] = ($access ? NODE_ACCESS_IGNORE : NODE_ACCESS_DENY);
|
650 |
|
|
}
|
651 |
|
|
else {
|
652 |
|
|
return $cache[$account->uid][$op][$nid] = NODE_ACCESS_IGNORE;
|
653 |
|
|
}
|
654 |
|
|
}
|
655 |
|
|
return $cache[$account->uid][$op][$nid];
|
656 |
|
|
}
|
657 |
|
|
return NODE_ACCESS_IGNORE;
|
658 |
|
|
}
|
659 |
|
|
|
660 |
|
|
/**
|
661 |
|
|
* Implements access checking.
|
662 |
|
|
*
|
663 |
|
|
* $op -- view, update, delete or create
|
664 |
|
|
* $tid -- the tid of the forum
|
665 |
|
|
* $account -- the account to test for; if NULL use current user
|
666 |
|
|
* $administer_nodes_sees_everything -- pass FALSE to ignore the 'administer nodes' permission
|
667 |
|
|
*
|
668 |
|
|
* Return:
|
669 |
|
|
* FALSE - access not granted
|
670 |
|
|
* 1 - access granted
|
671 |
|
|
* 2 - access granted for forum moderator
|
672 |
|
|
*/
|
673 |
|
|
function forum_access_access($op, $tid, $account = NULL, $administer_nodes_sees_everything = TRUE) {
|
674 |
|
|
$cache = &drupal_static(__FUNCTION__, array());
|
675 |
|
|
if (!$account) {
|
676 |
|
|
global $user;
|
677 |
|
|
$account = $user;
|
678 |
|
|
}
|
679 |
|
|
|
680 |
|
|
if (user_access('bypass node access', $account)) {
|
681 |
|
|
//TODO revise (including comment above)
|
682 |
|
|
// $administer_nodes_sees_everything && user_access('administer nodes', $account) && array_search($type, array('view', 'update', 'delete')) !== FALSE) {
|
683 |
|
|
return 1;
|
684 |
|
|
}
|
685 |
|
|
|
686 |
|
|
if ($op == 'delete' && user_access('delete any forum content', $account)) {
|
687 |
|
|
return 1;
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
if ($op == 'update' && user_access('edit any forum content', $account)) {
|
691 |
|
|
return 1;
|
692 |
|
|
}
|
693 |
|
|
|
694 |
|
|
if (!isset($cache[$account->uid][$tid][$op])) {
|
695 |
|
|
$query = db_select('forum_access', 'fa')
|
696 |
|
|
->fields('fa', array('tid'))
|
697 |
|
|
->condition("fa.grant_$op", 1, '>=')
|
698 |
|
|
->condition('fa.rid', array_keys($account->roles), 'IN');
|
699 |
|
|
if ($tid != 0) {
|
700 |
|
|
$query = $query
|
701 |
|
|
->condition('fa.tid', $tid, '=');
|
702 |
|
|
}
|
703 |
|
|
$result = $query
|
704 |
|
|
->execute()
|
705 |
|
|
->fetchField();
|
706 |
|
|
|
707 |
|
|
if ($result) {
|
708 |
|
|
$cache[$account->uid][$tid][$op] = 1;
|
709 |
|
|
}
|
710 |
|
|
else {
|
711 |
|
|
// check our moderators too
|
712 |
|
|
$result = forum_access_is_moderator($account, $tid);
|
713 |
|
|
$cache[$account->uid][$tid][$op] = ($result ? 2 : FALSE);
|
714 |
|
|
}
|
715 |
|
|
}
|
716 |
|
|
return $cache[$account->uid][$tid][$op];
|
717 |
|
|
}
|
718 |
|
|
|
719 |
|
|
/**
|
720 |
|
|
* Implements hook_taxonomy_term_delete().
|
721 |
|
|
*
|
722 |
|
|
* Delete {forum_access} records when forums are deleted.
|
723 |
|
|
*/
|
724 |
|
|
function forum_access_taxonomy_term_delete($term) {
|
725 |
|
|
//dpm($array, "hook_taxonomy_term_delete($term->tid)");
|
726 |
|
|
if ($term->vid == _forum_access_get_vid()) {
|
727 |
|
|
db_delete('forum_access')
|
728 |
|
|
->condition('tid', $term->tid)
|
729 |
|
|
->execute();
|
730 |
|
|
variable_del('forum_access_rids'); // clear cache
|
731 |
|
|
}
|
732 |
|
|
}
|
733 |
|
|
|
734 |
|
|
/**
|
735 |
|
|
* Implements hook_user_role_delete().
|
736 |
|
|
*/
|
737 |
|
|
function forum_access_user_role_delete($role) {
|
738 |
|
|
db_delete('forum_access')
|
739 |
|
|
->condition('rid', $role->rid)
|
740 |
|
|
->execute();
|
741 |
|
|
db_delete('node_access')
|
742 |
|
|
->condition('gid', $role->rid)
|
743 |
|
|
->condition('realm', 'forum_access')
|
744 |
|
|
->execute();
|
745 |
|
|
}
|
746 |
|
|
|
747 |
|
|
/**
|
748 |
|
|
* Check whether the given user is a moderator.
|
749 |
|
|
*
|
750 |
|
|
* @param $account
|
751 |
|
|
* The user or user ID to check.
|
752 |
|
|
* @param $tid
|
753 |
|
|
* ID of the forum to check or NULL to check whether the user is moderator
|
754 |
|
|
* in any forum at all.
|
755 |
|
|
*/
|
756 |
|
|
function forum_access_is_moderator($account, $tid = NULL) {
|
757 |
|
|
$uid = (is_object($account) ? $account->uid : $account);
|
758 |
|
|
return (bool) acl_get_ids_by_user('forum_access', $uid, NULL, ($tid ? $tid : NULL));
|
759 |
|
|
}
|
760 |
|
|
|
761 |
|
|
/**
|
762 |
|
|
* Return forum.module's forum vocabulary ID.
|
763 |
|
|
*/
|
764 |
|
|
function _forum_access_get_vid() {
|
765 |
|
|
return variable_get('forum_nav_vocabulary', '');
|
766 |
|
|
}
|
767 |
|
|
|
768 |
|
|
/**
|
769 |
|
|
* Returns the forum tid or FALSE.
|
770 |
|
|
*/
|
771 |
|
|
function _forum_access_get_tid($node) {
|
772 |
|
|
return (isset($node->forum_tid) ? $node->forum_tid : FALSE);
|
773 |
|
|
}
|
774 |
|
|
|
775 |
|
|
/**
|
776 |
|
|
* Saves and returns the $tid.
|
777 |
|
|
*/
|
778 |
|
|
function _forum_access_changed_tid($tid = NULL) {
|
779 |
|
|
$saved_tid = &drupal_static(__FUNCTION__);
|
780 |
|
|
if (!empty($tid)) {
|
781 |
|
|
$saved_tid = $tid;
|
782 |
|
|
}
|
783 |
|
|
return $saved_tid;
|
784 |
|
|
}
|
785 |
|
|
|
786 |
|
|
/**
|
787 |
|
|
* Returns the ACL ID of the forum.
|
788 |
|
|
*/
|
789 |
|
|
function _forum_access_get_acl($tid) {
|
790 |
|
|
$acl_id = acl_get_id_by_number('forum_access', $tid);
|
791 |
|
|
if (!$acl_id) { // create one
|
792 |
|
|
$acl_id = acl_create_new_acl('forum_access', NULL, $tid);
|
793 |
|
|
$subselect = db_select('taxonomy_index', 'n');
|
794 |
|
|
$subselect
|
795 |
|
|
->fields('n', array('nid'))
|
796 |
|
|
->condition('n.tid', $tid);
|
797 |
|
|
acl_add_nodes($subselect, $acl_id, 1, 1, 1);
|
798 |
|
|
}
|
799 |
|
|
return $acl_id;
|
800 |
|
|
}
|
801 |
|
|
|
802 |
|
|
function _forum_access_module_load_include($type) {
|
803 |
|
|
static $loaded = array();
|
804 |
|
|
|
805 |
|
|
if (!isset($loaded[$type])) {
|
806 |
|
|
$path = module_load_include($type, 'forum_access');
|
807 |
|
|
$loaded[$type] = drupal_get_path('module', 'forum_access') . "/forum_access.$type";
|
808 |
|
|
}
|
809 |
|
|
return $loaded[$type];
|
810 |
|
|
}
|
811 |
|
|
|
812 |
|
|
/**
|
813 |
|
|
* Implements hook_theme().
|
814 |
|
|
*/
|
815 |
|
|
function forum_access_theme() {
|
816 |
|
|
return array(
|
817 |
|
|
'forum_access_table' => array(
|
818 |
|
|
'render element' => 'form',
|
819 |
|
|
'file' => 'forum_access.admin.inc',
|
820 |
|
|
),
|
821 |
|
|
);
|
822 |
|
|
}
|
823 |
|
|
|
824 |
|
|
/**
|
825 |
|
|
* Implements hook_node_access_explain().
|
826 |
|
|
*/
|
827 |
|
|
function forum_access_node_access_explain($row) {
|
828 |
|
|
$roles = &drupal_static(__FUNCTION__);
|
829 |
|
|
if ($row->realm == 'forum_access') {
|
830 |
|
|
if (!isset($roles)) {
|
831 |
|
|
$roles = user_roles();
|
832 |
|
|
}
|
833 |
|
|
if (isset($roles[$row->gid])) {
|
834 |
|
|
return array($roles[$row->gid]);
|
835 |
|
|
}
|
836 |
|
|
return array('(unknown gid)');
|
837 |
|
|
}
|
838 |
|
|
}
|
839 |
|
|
|
840 |
|
|
/**
|
841 |
|
|
* Implements hook_acl_explain().
|
842 |
|
|
*/
|
843 |
|
|
function forum_access_acl_explain($acl_id, $name, $number, $users = NULL) {
|
844 |
|
|
if (empty($users)) {
|
845 |
|
|
return "ACL (id=$acl_id) would grant access to nodes in forum/$number.";
|
846 |
|
|
}
|
847 |
|
|
return "ACL (id=$acl_id) grants access to nodes in forum/$number to the listed user(s).";
|
848 |
|
|
}
|