/[drupal]/contributions/modules/contentblocker/contentblocker.module
ViewVC logotype

Contents of /contributions/modules/contentblocker/contentblocker.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.16 - (show annotations) (download) (as text)
Tue Dec 9 21:05:41 2008 UTC (11 months, 2 weeks ago) by nedjo
Branch: MAIN
CVS Tags: HEAD
Changes since 1.15: +60 -56 lines
File MIME type: text/x-php
Issue #342314, initial work toward D6 upgrade of contentblocker.
1 <?php
2 // $Id: contentblocker.module,v 1.15 2008/04/24 18:40:27 nedjo Exp $
3
4 /**
5 * Implementation of hook_boot().
6 */
7 function contentblocker_init() {
8 contentblocker_load_modules();
9 }
10
11 /**
12 * Implementation of hook_help().
13 */
14 function contentblocker_help($path, $arg) {
15 switch ($path) {
16 case 'admin/settings/contentblocker':
17 return t('To enable users to filter or block content, visit the access control page after selecting which modules to enable filtering for.');
18 }
19 if (strpos($path, 'contentblocker/') === 0) {
20 return t('Here is a list of the content filters you have registered.');
21 }
22 }
23
24 /**
25 * Implementation of hook_menu().
26 */
27 function contentblocker_menu() {
28
29 $items = array();
30
31 // Add a settings menu item.
32 $items['admin/settings/contentblocker'] = array(
33 'title' => 'Content blocker',
34 'description' => 'Select which data types to offer for blocking.',
35 'access arguments' => array('administer site configuration'),
36 'type' => MENU_NORMAL_ITEM,
37 'page callback' => 'drupal_get_form',
38 'page arguments' => array('contentblocker_settings_form'),
39 );
40
41 $types = contentblocker_get_data();
42 if (!empty($types)) {
43 $items['contentblocker'] = array(
44 'title' => 'Content blocker',
45 'description' => 'Administer content filters',
46 'type' => MENU_NORMAL_ITEM,
47 'access arguments' => TRUE,
48 'position' => 'right',
49 'weight' => -5,
50 'page callback' => 'system_admin_menu_block_page',
51 );
52 foreach ($types as $type => $data) {
53 if (!isset($data['save_type'])) {
54 // Add a settings menu item.
55 $items['contentblocker/'. $type] = array(
56 'title' => filter_xss_admin($data['type_title']),
57 'description' => 'Administer @type filters', array('@type' => $data['type_title']),
58 'type' => MENU_NORMAL_ITEM,
59 'access arguments' => TRUE,
60 'page callback' => 'drupal_get_form',
61 'page arguments' => array('contentblocker_admin', $type),
62 );
63 }
64 }
65 }
66
67 }
68
69 /**
70 * Implementation of hook_theme().
71 */
72 function contentblocker_theme() {
73 return array(
74 'contentblocker_admin' => array(
75 'file' => 'contentblocker.module',
76 'arguments' => array(
77 'form' => NULL,
78 ),
79 ),
80 );
81 }
82
83 /**
84 * Settings form.
85 *
86 * Select components to share with the hub site.
87 */
88 function contentblocker_settings_form() {
89 $form = array();
90
91 // Scan for available modules.
92 $options = array();
93 $path = drupal_get_path('module', 'contentblocker') .'/modules';
94 $files = file_scan_directory($path, '\.inc$');
95 foreach ($files as $file) {
96 // The system module is a special case. It will be used in all cases.
97 if (module_exists($file->name)) {
98 // Grab the .info file and set name.
99 $options[$file->name] = _contentblocker_get_module_name($file->name);
100 }
101 }
102
103 $form['contentblocker_modules'] = array(
104 '#type' => 'checkboxes',
105 '#options' => $options,
106 '#default_value' => variable_get('contentblocker_modules', array()),
107 '#title' => t('Enabled filters'),
108 '#description' => t('Select the types of filters you wish to enable.'),
109 );
110
111 return system_settings_form($form);
112 }
113
114 /**
115 * Implementation of hook_perm().
116 */
117 function contentblocker_perm() {
118 $modules = contentblocker_load_modules();
119 foreach ($modules as $module) {
120 $perms[] = _contentblocker_get_perm($module);
121 }
122 return $perms;
123 }
124
125 /**
126 * Return the permission to block content for a given module.
127 */
128 function _contentblocker_get_perm($module) {
129 return 'block content by '. $module;
130 }
131
132 /**
133 * Implementation of hook_nodeapi().
134 *
135 * Load and save contentblocker properties on nodes.
136 */
137 function contentblocker_nodeapi($node, $op, $arg = 0) {
138 return contentblocker_object_api('node', $node, $op);
139 }
140
141 /**
142 * Implementation of hook_comment().
143 *
144 * Load and save contentblocker properties on comments.
145 */
146 function contentblocker_comment($comment, $op) {
147 return contentblocker_object_api('comment', $comment, $op);
148 }
149
150 /**
151 * Cross-object-type API functions.
152 *
153 * Load and save contentblocker properties on objects.
154 */
155 function contentblocker_object_api($object_type, $object, $op) {
156 global $user;
157
158 // Only block content for logged in users.
159 if ($user->uid) {
160 switch ($op) {
161 case 'load':
162 $properties = array();
163 $types = contentblocker_get_block_types();
164 if (!empty($types)) {
165 foreach ($types as $type) {
166 $properties['contentblocker_'. $type] = $properties['contentblocker_original_'. $type] = contentblocker_has_block($type, (object) $object);
167 }
168 }
169 return $properties;
170
171 // We don't need an insert, because it's not possible to block on object creation.
172 case 'update':
173 // E.g. commments are received as an array.
174 $object = (object) $object;
175 $types = contentblocker_get_block_types();
176 if (!empty($types)) {
177 foreach ($types as $type) {
178 $type_key = 'contentblocker_'. $type;
179 $original_type_key = 'contentblocker_original_'. $type;
180 if (isset($object->$type_key) && isset($object->$original_type_key) && $object->$type_key != $object->$original_type_key) {
181 contentblocker_save_block($type, $object);
182 }
183 }
184 }
185 break;
186 }
187 }
188 }
189
190 /**
191 * Determine whether a block of a given type exists on a given object.
192 */
193 function contentblocker_has_block($type, $object) {
194 global $user;
195 $data = contentblocker_get_data($type);
196
197 $object_field = $data['object_field'];
198 // If the join field is also the primary field, we filter by the object field.
199 if ($data['primary_join_field'] == $date['primary_id_field']) {
200 $and = 'cb.id = %d';
201 }
202 // Otherwise, we filter by the join field.
203 else {
204 $and = $data['primary_table_alias'] .'.'. $data['primary_join_field'] .' = %d';
205 }
206 $result = db_query("SELECT cb.* FROM {contentblocker} cb INNER JOIN {". $data['primary_table'] ."} ". $data['primary_table_alias'] ." ON cb.id = ". $data['primary_table_alias'] .".". $data['primary_id_field'] ." WHERE cb.uid = %d and cb.type = '%s' AND ". $and, $user->uid, isset($data['save_type']) ? $data['save_type'] : $type, $object->$object_field);
207 return db_num_rows($result) ? 1 : 0;
208 }
209
210 /**
211 * Save blocking information for a node.
212 */
213 function contentblocker_save_block($type, $object) {
214 global $user;
215 $data = contentblocker_get_data($type);
216
217 // Determine value of join field.
218 $data = contentblocker_get_data($type);
219 $field = $data['object_field'];
220 if ($id = db_result(db_query("SELECT ". $data['primary_table_alias'] .".". $data['primary_id_field'] ." FROM {". $data['primary_table'] ."} ". $data['primary_table_alias'] ." INNER JOIN {". $data['object_table'] ."} ". $data['object_table_alias'] ." ON ". $data['primary_table_alias'] .".". $data['primary_join_field'] ." = ". $data['object_table_alias'] .".". $data['object_field'] ." WHERE ". $data['object_table_alias'] .".". $data['object_field'] ." = %d", $object->$field))) {
221
222 $has_block = contentblocker_has_block($type, $object);
223 $property = 'contentblocker_'. $type;
224 switch ($object->$property) {
225 // Delete existing block.
226 case 0:
227 if ($has_block) {
228 db_query("DELETE FROM {contentblocker} WHERE uid = %d AND type = '%s' AND id = %d", $user->uid, isset($data['save_type']) ? $data['save_type'] : $type, $id);
229 }
230 break;
231 // Insert a new block.
232 case 1:
233 if (!$has_block) {
234 db_query("INSERT INTO {contentblocker} (uid, type, id) VALUES (%d, '%s', %d)", $user->uid, isset($data['save_type']) ? $data['save_type'] : $type, $id);
235 }
236 break;
237 }
238 // Menus need to reflect the current state of the users' registered content blocks.
239 menu_rebuild();
240 }
241 }
242
243 /**
244 * Return data used to determine blocking behaviour.
245 */
246 function contentblocker_get_data($type = NULL) {
247 static $data;
248
249 if ($data == NULL) {
250 $data = array();
251 foreach (module_implements('contentblocker_data') as $module) {
252 // Test for access. We won't need to test for access again
253 // on data loaded from this function, since we already know the
254 // user has access.
255 if (user_access(_contentblocker_get_perm($module))) {
256 $data = array_merge($data, module_invoke($module, 'contentblocker_data'));
257 }
258 }
259 }
260
261 return $type ? ($data[$type] ? $data[$type] : FALSE) : $data;
262 }
263
264 /**
265 * Return data used to determine blocking behaviour.
266 */
267 function contentblocker_get_options($obj_type, $obj) {
268 $data = array();
269
270 foreach (module_implements('contentblocker_options') as $module) {
271 // Test for access. We won't need to test for access again
272 // on data loaded from this function, since we already know the
273 // user has access.
274 if (user_access(_contentblocker_get_perm($module))) {
275 $data = array_merge($data, module_invoke($module, 'contentblocker_options', $obj_type, $obj));
276 }
277 }
278
279 return $data;
280 }
281
282 /**
283 * Implementation of hook_db_rewrite_sql().
284 */
285 function contentblocker_db_rewrite_sql($query, $primary_table, $primary_field) {
286 global $user;
287 $return = array();
288 // Only block content for logged in users. Act on nodes.
289 if ($user->uid && $primary_field == 'nid') {
290 $return = contentblocker_node_sql($user->uid, $primary_table);
291 }
292 return $return;
293 }
294
295 /**
296 * Return SQL fragments for blocking nodes.
297 */
298 function contentblocker_node_sql($uid = NULL, $primary_table = 'n') {
299 global $user;
300 $return = array();
301 $uid = ($uid == NULL) ? $user->uid : $uid;
302 $join = array();
303 // If altering a query on other than the node table, join on node
304 // and use it instead as the primary table.
305 if (!($primary_table == 'n' || $primary_table == 'node')) {
306 $join[] = "LEFT JOIN {node} n ON $primary_table.nid = n.nid";
307 $primary_table = 'n';
308 }
309 $where = array();
310 $types = contentblocker_get_block_types($uid);
311 if (!empty($types)) {
312 foreach($types as $index => $type) {
313 $sql = contentblocker_node_sql_type($type, $index, $uid, $primary_table);
314 if (isset($sql['join'])) {
315 $join[] = $sql['join'];
316 }
317 $where[] = $sql['where'];
318 }
319 if (!empty($join)) {
320 $return['join'] = implode(' ', $join);
321 }
322 if (!empty($where)) {
323 $return['where'] = implode(' AND ', $where);
324 }
325 }
326 return $return;
327 }
328
329 /**
330 * Return SQL fragments for blocking nodes.
331 */
332 function contentblocker_node_sql_type($type, $index, $uid, $primary_table = 'n') {
333 $return = array();
334 $data = contentblocker_get_data($type);
335 // If this type doesn't save its own data, return.
336 if (isset($data['save_type']) && !empty($data['save_type'])) {
337 return array();
338 }
339 if ($data['block_table'] != 'node') {
340 $return['join'] = "LEFT JOIN {". $data['block_table'] ."} ". $data['block_table_alias'] ." ON ". $primary_table .".". $data['primary_join_field'] ." = ". $data['block_table_alias'] .".". $data['block_field'];
341 }
342 else {
343 $data['block_table_alias'] = $primary_table;
344 }
345
346 // MySQL didn't support subqueries before 4.1.
347 if ($GLOBALS['db_type'] == 'mysql' && version_compare(mysql_get_server_info($GLOBALS['active_db']), '4.1.0', '<')) {
348 $ids = array();
349 $result = db_query("SELECT id FROM {contentblocker} WHERE type = '%s' AND uid = %d", $type, $uid);
350 while ($row = db_fetch_array($result)) {
351 $ids[] = $row['id'];
352 }
353 $return['where'] = "(". $data['block_table_alias'] ."." .$data['block_field'] ." NOT IN(". implode(',', $ids) .") OR ". $data['block_table_alias'] ."." .$data['block_field'] ." IS NULL)";
354 }
355 else {
356 // $type is potentially user input, so escape it.
357 $return['where'] = "(". $data['block_table_alias'] ."." .$data['block_field'] ." NOT IN(SELECT id FROM {contentblocker} WHERE type = '". db_escape_string($type) ."' AND uid = ". $uid .") OR ". $data['block_table_alias'] ."." .$data['block_field'] ." IS NULL)";
358 }
359 return $return;
360 }
361
362 /**
363 * Return the list of registered block types.
364 */
365 function contentblocker_get_block_types($uid = NULL) {
366
367 if ($uid) {
368 $types = array();
369 $result = db_query("SELECT DISTINCT(type) FROM {contentblocker} WHERE uid = %d", $uid);
370 while ($type = db_fetch_array($result)) {
371 $types[] = $type['type'];
372 }
373 return $types;
374 }
375 else {
376 return array_keys(contentblocker_get_data());
377 }
378
379 }
380
381 /**
382 * Load the include files used by this module.
383 */
384 function contentblocker_load_modules() {
385 static $modules;
386 if ($modules == NULL) {
387 $modules = variable_get('contentblocker_modules', array());
388 if (!empty($modules)) {
389 $path = drupal_get_path('module', 'contentblocker');
390 foreach ($modules as $module) {
391 if (module_exists($module)) {
392 module_load_include('inc', 'contentblocker', 'modules/' . $module);
393 }
394 else {
395 unset($modules[$module]);
396 }
397 }
398 }
399 }
400 return $modules;
401 }
402
403 /**
404 * Read and return the name defined in a module's .info file.
405 */
406 function _contentblocker_get_module_name($module) {
407 static $names = array();
408 if (!isset($names[$module])) {
409 $info = _module_parse_info_file(drupal_get_path('module', $module) .'/'. $module .'.info');
410 $names[$module] = $info['name'] ? $info['name'] : $module;
411 }
412 return $names[$module];
413 }
414
415 /**
416 * Implementation of hook_fasttoggle_options().
417 */
418 function contentblocker_fasttoggle_options($type, $obj) {
419 $return = array();
420 switch ($type) {
421 case 'node':
422 case 'comment':
423 $data = contentblocker_get_options($type, $obj);
424 $options = array();
425 foreach (array_keys($data) as $cb_type) {
426 $options['contentblocker_'. $cb_type] = $data[$cb_type];
427 }
428 return $options;
429 }
430 }
431
432 /**
433 * Menu callback. Provide administration for content filters.
434 */
435 function contentblocker_admin($type) {
436 global $user;
437 $data = contentblocker_get_data($type);
438 $form = array();
439 $form['title'] = array();
440 $items = array();
441
442 $result = pager_query("SELECT cb.id, ". $data['title_table_alias'] .".". $data['title_field'] ." FROM {contentblocker} cb INNER JOIN {". $data['title_table'] ."} ". $data['title_table_alias'] ." ON cb.id = ". $data['title_table_alias']. ".". $data['title_id_field'] ." WHERE cb.type = '%s' AND cb.uid = %d ORDER BY ". $data['title_table_alias'] .".". $data['title_field'], 50, 0, NULL, $type, $user->uid);
443
444 while ($item = db_fetch_array($result)) {
445 $items[$item['id']] = '';
446 $title_property = $data['title_property'];
447 $form['title'][$item['id']] = array('#value' => l($item[$data['title_field']], $data['title_path_prefix'] .'/'. $item['id']));
448 }
449 $form['items'] = array('#type' => 'checkboxes', '#options' => $items);
450 $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
451 $form['uid'] = array('#type' => 'value', '#value' => $user->uid);
452 $form['contentblocker_type'] = array('#type' => 'value', '#value' => $type);
453 $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Delete selected filters'));
454 return $form;
455 }
456
457 /**
458 * Theme contentblocker administration overview.
459 */
460 function theme_contentblocker_admin($form) {
461 // Overview table:
462 $header = array(theme('table_select_header_cell'), t('Title'));
463
464 if (count(element_children($form['title']))) {
465 foreach (element_children($form['title']) as $key) {
466 $row = array();
467 $row[] = drupal_render($form['items'][$key]);
468 $row[] = drupal_render($form['title'][$key]);
469 $rows[] = $row;
470 }
471
472 }
473 else {
474 $rows[] = array(array('data' => t('No content filters available.'), 'colspan' => '2'));
475 }
476
477 $output .= theme('table', $header, $rows);
478 if ($form['pager']['#value']) {
479 $output .= drupal_render($form['pager']);
480 }
481
482 $output .= drupal_render($form);
483
484 return $output;
485 }
486
487 /**
488 * Submit the contentblocker administration form.
489 */
490 function contentblocker_admin_submit($form, &$form_state) {
491 // Filter out unchecked nodes
492 $items = array_filter($form_state['values']['items']);
493 $count = 0;
494 foreach ($items as $id) {
495 db_query("DELETE FROM {contentblocker} WHERE uid = %d AND type = '%s' AND id = %d", $form_state['values']['uid'], $form_state['values']['contentblocker_type'], $id);
496 $count ++;
497 }
498 drupal_set_message(format_plural($count, '1 filter deleted', '@count filters deleted'));
499 }
500
501 /**
502 * Validate the contentblocker administration form.
503 */
504 function contentblocker_admin_validate($form, &$form_state) {
505 $items = array_filter($form_state['values']['items']);
506 if (count($items) == 0) {
507 form_set_error('', t('No items selected.'));
508 }
509 }

  ViewVC Help
Powered by ViewVC 1.1.2