| 1 |
<?php
|
| 2 |
// $Id: og_subgroups.module,v 1.46 2008/12/15 21:35:36 amitaibu Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Maintains subgroups outline created by the organic groups module.
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* The number of directions a content/ member can propagate.
|
| 11 |
*
|
| 12 |
* Directions are: up (parent), down (children) and side (siblings).
|
| 13 |
*/
|
| 14 |
define('OG_SUBGROUPS_DIRECTION_COUNT', 3);
|
| 15 |
|
| 16 |
/**
|
| 17 |
* Implementation of hook_perm().
|
| 18 |
*/
|
| 19 |
function og_subgroups_perm() {
|
| 20 |
return array('administer subgroups');
|
| 21 |
}
|
| 22 |
|
| 23 |
/**
|
| 24 |
* Implementation of hook_menu().
|
| 25 |
*/
|
| 26 |
function og_subgroups_menu() {
|
| 27 |
$items['admin/og/subgroups'] = array(
|
| 28 |
'title' => 'Subgroups for organic groups configuration',
|
| 29 |
'description' => "Manage your site's subgroups outline.",
|
| 30 |
'page callback' => 'drupal_get_form',
|
| 31 |
'page arguments' => array('og_subgroups_admin_settings'),
|
| 32 |
'access arguments' => array('administer subgroups'),
|
| 33 |
'weight' => 1,
|
| 34 |
'file' => 'og_subgroups.admin.inc',
|
| 35 |
);
|
| 36 |
return $items;
|
| 37 |
}
|
| 38 |
|
| 39 |
/**
|
| 40 |
* Implementation of hook_nodeapi().
|
| 41 |
*/
|
| 42 |
function og_subgroups_nodeapi(&$node, $op, $teaser, $page) {
|
| 43 |
switch ($op) {
|
| 44 |
case 'view':
|
| 45 |
// Remove the book navigation on group nodes.
|
| 46 |
if (og_is_group_type($node->type) && !empty($node->content['book_navigation'])) {
|
| 47 |
unset($node->content['book_navigation']);
|
| 48 |
}
|
| 49 |
case 'insert':
|
| 50 |
og_subgroups_propogate_content($node);
|
| 51 |
break;
|
| 52 |
case 'update':
|
| 53 |
og_subgroups_propogate_content($node);
|
| 54 |
break;
|
| 55 |
}
|
| 56 |
}
|
| 57 |
|
| 58 |
/**
|
| 59 |
* Implementation of hook_block().
|
| 60 |
*
|
| 61 |
* Displays the book table of contents in a block when the current page is a
|
| 62 |
* group post or group node and part of a book.
|
| 63 |
* Pattern taken from book module.
|
| 64 |
*/
|
| 65 |
function og_subgroups_block($op = 'list', $delta = 0, $edit = array()) {
|
| 66 |
$block = array();
|
| 67 |
switch ($op) {
|
| 68 |
case 'list':
|
| 69 |
$block[0]['info'] = t('Subgroups navigation');
|
| 70 |
$block[0]['cache'] = BLOCK_CACHE_PER_PAGE | BLOCK_CACHE_PER_ROLE;
|
| 71 |
return $block;
|
| 72 |
case 'view':
|
| 73 |
$current_bid = 0;
|
| 74 |
if ($node = og_get_group_context()) {
|
| 75 |
// Check if node is a group member and if the group is part of a book.
|
| 76 |
$current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
|
| 77 |
}
|
| 78 |
if (variable_get('og_subgroups_block_mode', 'all pages') == 'all pages') {
|
| 79 |
$block['subject'] = t('Subgroups navigation');
|
| 80 |
$book_menus = array();
|
| 81 |
$pseudo_tree = array(0 => array('below' => FALSE));
|
| 82 |
foreach (book_get_books() as $book_id => $book) {
|
| 83 |
if ($book['bid'] == $current_bid) {
|
| 84 |
// If the current page is a node associated with a book, the menu
|
| 85 |
// needs to be retrieved.
|
| 86 |
$book_menus[$book_id] = menu_tree_output(menu_tree_all_data($node->book['menu_name'], NULL));
|
| 87 |
}
|
| 88 |
else {
|
| 89 |
// Since we know we will only display a link to the top node, there
|
| 90 |
// is no reason to run an additional menu tree query for each book.
|
| 91 |
$book['in_active_trail'] = FALSE;
|
| 92 |
$pseudo_tree[0]['link'] = $book;
|
| 93 |
$book_menus[$book_id] = menu_tree_output($pseudo_tree);
|
| 94 |
}
|
| 95 |
}
|
| 96 |
$block['content'] = theme('book_all_books_block', $book_menus);
|
| 97 |
}
|
| 98 |
elseif ($current_bid) {
|
| 99 |
// Only display this block when the user is browsing a book.
|
| 100 |
$title = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $node->book['bid']));
|
| 101 |
// Only show the block if the user has view access for the top-level
|
| 102 |
// node.
|
| 103 |
if ($title) {
|
| 104 |
$tree = menu_tree_all_data($node->book['menu_name'], $node->book);
|
| 105 |
// There should only be one element at the top level.
|
| 106 |
$data = array_shift($tree);
|
| 107 |
$block['subject'] = theme('book_title_link', $data['link']);
|
| 108 |
$block['content'] = ($data['below']) ? menu_tree_output($data['below']) : '';
|
| 109 |
}
|
| 110 |
}
|
| 111 |
return $block;
|
| 112 |
case 'configure':
|
| 113 |
$options = array(
|
| 114 |
'all pages' => t('Show block on all pages'),
|
| 115 |
'book pages' => t('Show block only on group post or group nodes which are in a book'),
|
| 116 |
);
|
| 117 |
$form['og_subgroups_block_mode'] = array(
|
| 118 |
'#type' => 'radios',
|
| 119 |
'#title' => t('Subgroups navigation block display'),
|
| 120 |
'#options' => $options,
|
| 121 |
'#default_value' => variable_get('og_subgroups_block_mode', 'all pages'),
|
| 122 |
'#description' => t("If <em>Show block on all pages</em> is selected, the block will contain the automatically generated menus for all of the site's books. If <em>Show block only on book pages</em> is selected, the block will contain only the one menu corresponding to the current page's book. In this case, if the current page is not a group post or a group node and part of a book, no block will be displayed. The <em>Page specific visibility settings</em> or other visibility settings can be used in addition to selectively display this block."),
|
| 123 |
);
|
| 124 |
return $form;
|
| 125 |
case 'save':
|
| 126 |
variable_set('og_subgroups_block_mode', $edit['og_subgroups_block_mode']);
|
| 127 |
break;
|
| 128 |
}
|
| 129 |
}
|
| 130 |
|
| 131 |
/**
|
| 132 |
* Propagate a group post along the subgroup outline.
|
| 133 |
*
|
| 134 |
* @param $node
|
| 135 |
* The node object that is being inserted/ updated.
|
| 136 |
*/
|
| 137 |
function og_subgroups_propogate_content($node) {
|
| 138 |
$directions = variable_get('og_subgroups_propagate_content', array());
|
| 139 |
$nodes = og_subgroups_get_groups_for_propagate($node, $directions);
|
| 140 |
foreach ($nodes as $key => $value) {
|
| 141 |
// Check that post isn't already assigned to the group.
|
| 142 |
$save = FALSE;
|
| 143 |
if (og_is_group_post_type($node->type) && !in_array($key, $node->og_groups)) {
|
| 144 |
// Add og's data to the group post node.
|
| 145 |
$node->og_groups[] = $key;
|
| 146 |
$node->og_groups_both[$key] = $value['title'];
|
| 147 |
$save = TRUE;
|
| 148 |
|
| 149 |
}
|
| 150 |
// Save the node only if it was changed.
|
| 151 |
if ($save) {
|
| 152 |
og_save_ancestry($node);
|
| 153 |
}
|
| 154 |
}
|
| 155 |
}
|
| 156 |
|
| 157 |
/**
|
| 158 |
* Implementation of hook_og().
|
| 159 |
*/
|
| 160 |
function og_subgroups_og($op, $gid, $uid, $args = array()) {
|
| 161 |
switch ($op) {
|
| 162 |
case 'user insert':
|
| 163 |
og_subgroups_propogate_user($gid, $uid, $args);
|
| 164 |
break;
|
| 165 |
case 'user update':
|
| 166 |
og_subgroups_propogate_user($gid, $uid, $args);
|
| 167 |
break;
|
| 168 |
case 'user delete':
|
| 169 |
og_subgroups_propogate_user($gid, $uid, $args);
|
| 170 |
break;
|
| 171 |
}
|
| 172 |
}
|
| 173 |
|
| 174 |
/**
|
| 175 |
* Propagates members and admins along the subgroups outline.
|
| 176 |
*
|
| 177 |
* @param $gid
|
| 178 |
* The group id.
|
| 179 |
* @param $uid
|
| 180 |
* The propagated user id.
|
| 181 |
* @param $args
|
| 182 |
* Array with the updated action, as returned from hook_og()
|
| 183 |
*/
|
| 184 |
function og_subgroups_propogate_user($gid, $uid, $args) {
|
| 185 |
if (empty($args['og_subgroups'])) {
|
| 186 |
global $user;
|
| 187 |
if ($user->uid != $uid) {
|
| 188 |
$account = user_load(array('uid' => $uid));
|
| 189 |
}
|
| 190 |
else {
|
| 191 |
$account = $user;
|
| 192 |
}
|
| 193 |
$admin_propagate = variable_get('og_subgroups_propagate_type', 'admin_propagate');
|
| 194 |
$is_admin = $args['is_admin'] && $admin_propagate != 'no_admin_propagate';
|
| 195 |
$demote = variable_get('og_subgroups_propagate_demote', array());
|
| 196 |
|
| 197 |
if (!$is_admin && $admin_propagate == 'only_admin_propagate' && !$demote['remove_admin']) {
|
| 198 |
// If propagate only admin rights and it's a regular membership
|
| 199 |
// and there is no admin rights demotion - do nothing.
|
| 200 |
// Like this we can escape redundant calculations.
|
| 201 |
return;
|
| 202 |
}
|
| 203 |
elseif ($node = node_load($gid)) {
|
| 204 |
$directions = variable_get('og_subgroups_propagate_member', array());
|
| 205 |
$nodes = og_subgroups_get_groups_for_propagate($node, $directions);
|
| 206 |
// Remove the original group node from the nodes list.
|
| 207 |
unset($nodes[$gid]);
|
| 208 |
foreach ($nodes as $group_nid => $value) {
|
| 209 |
// TODO: OG should allow passing $args['og_subgroups'] as it currently
|
| 210 |
// loops over and over again.
|
| 211 |
if (empty($args) && $demote['unsubscribe']) {
|
| 212 |
// Remove user from groups.
|
| 213 |
og_delete_subscription($group_nid, $account->uid);
|
| 214 |
}
|
| 215 |
// Make sure:
|
| 216 |
// 1) User isn't a member;
|
| 217 |
// 2) or Admin propagation, and member isn't admin;
|
| 218 |
// 3) or Admin demotion and user is member of the group.
|
| 219 |
elseif (!og_is_group_member($group_nid, TRUE, $account->uid) || ($is_admin && !$account->og_groups[$group_nid]['is_admin']) || (!empty($account->og_groups[$group_nid]['is_admin']) && !$args['is_admin'] && $demote['remove_admin'])) {
|
| 220 |
// Pass in the $args info about propagation done by og_subgroups module.
|
| 221 |
og_save_subscription($group_nid, $uid, array('is_active' => 1, 'is_admin' => $is_admin, 'og_subgroups' => TRUE));
|
| 222 |
}
|
| 223 |
}
|
| 224 |
}
|
| 225 |
}
|
| 226 |
}
|
| 227 |
|
| 228 |
/**
|
| 229 |
* Helper function; get all the groups which content/ user should be propagated
|
| 230 |
* to.
|
| 231 |
*
|
| 232 |
* @param $node
|
| 233 |
* The loaded node object.
|
| 234 |
* @return
|
| 235 |
* The nids and depth relative to the menu item the node group node
|
| 236 |
* belongs to.
|
| 237 |
*/
|
| 238 |
function og_subgroups_get_groups_for_propagate($node, $directions = array()) {
|
| 239 |
$nodes = array();
|
| 240 |
// Clean up the directions of propagation.
|
| 241 |
$directions = array_filter($directions);
|
| 242 |
|
| 243 |
// Propagation can be done only if there is a direction and
|
| 244 |
// on group posts and group nodes.
|
| 245 |
// and if node belongs to any group(s).
|
| 246 |
if ($directions && (og_is_group_post_type($node->type) || og_is_group_type($node->type))) {
|
| 247 |
if (!empty($node->og_groups)) {
|
| 248 |
// Node is a group post.
|
| 249 |
$groups = $node->og_groups;
|
| 250 |
}
|
| 251 |
else {
|
| 252 |
// Node is a group node.
|
| 253 |
$groups[$node->nid] = $node->nid;
|
| 254 |
}
|
| 255 |
foreach ($groups as $gid) {
|
| 256 |
// Check if node isn't already loaded.
|
| 257 |
if ($gid == $node->nid) {
|
| 258 |
$group_node = $node;
|
| 259 |
}
|
| 260 |
else {
|
| 261 |
$group_node = node_load($gid);
|
| 262 |
}
|
| 263 |
// Get the menu from root down.
|
| 264 |
$menu = menu_tree_all_data($group_node->book['menu_name'], NULL);
|
| 265 |
|
| 266 |
// Get the nids of every menu item.
|
| 267 |
$node_links = array();
|
| 268 |
menu_tree_collect_node_links($menu, $node_links);
|
| 269 |
|
| 270 |
// If direction is up, down and side then all groups will be used.
|
| 271 |
// Otherwise remove the unnecessary groups.
|
| 272 |
if (count($directions) != OG_SUBGROUPS_DIRECTION_COUNT && $node_links) {
|
| 273 |
$mlid = array_values($node_links[$gid]);
|
| 274 |
$mlid = $mlid[0]['mlid'];
|
| 275 |
_og_subgroups_filter_groups($gid, $mlid, $node_links, $directions);
|
| 276 |
}
|
| 277 |
|
| 278 |
// Get all the nodes required for propagation.
|
| 279 |
// Duplicate groups will be removed as it is an associative array.
|
| 280 |
$nodes += $node_links;
|
| 281 |
}
|
| 282 |
}
|
| 283 |
return $nodes;
|
| 284 |
}
|
| 285 |
|
| 286 |
/**
|
| 287 |
* Helper function - remove node groups which are not required for propagation.
|
| 288 |
*
|
| 289 |
* @param $gid
|
| 290 |
* The group id.
|
| 291 |
* @param $mlid
|
| 292 |
* The menu id of the group.
|
| 293 |
* @param $node_links
|
| 294 |
* Passed by reference. node groups which aren't needed will be unset.
|
| 295 |
* @param $directions
|
| 296 |
* The directions of propagation.
|
| 297 |
*/
|
| 298 |
function _og_subgroups_filter_groups($gid, $mlid, &$node_links, $directions) {
|
| 299 |
foreach ($node_links as $key => $links) {
|
| 300 |
$item_key = array_keys($links);
|
| 301 |
$item_key = $item_key[0];
|
| 302 |
$remove = TRUE;
|
| 303 |
if (isset($directions['up'])) {
|
| 304 |
// Get parents from the group's menu path.
|
| 305 |
$i = 1;
|
| 306 |
while ($i <= MENU_MAX_DEPTH && $remove && $node_links[$gid][$mlid]['p'. $i] != 0) {
|
| 307 |
$node_links[$gid][$mlid]['p'. $i] == $item_key ? $remove = FALSE : $i++;
|
| 308 |
}
|
| 309 |
}
|
| 310 |
if (isset($directions['down'])) {
|
| 311 |
// Get children parent is in their menu.
|
| 312 |
$i = 1;
|
| 313 |
while ($i <= MENU_MAX_DEPTH && $remove && $links[$item_key]['p'. $i] != 0) {
|
| 314 |
$links[$item_key]['p'. $i] == $mlid ? $remove = FALSE : $i++;
|
| 315 |
}
|
| 316 |
}
|
| 317 |
// Get brothers that have the same parent.
|
| 318 |
if (isset($directions['side']) && $links[$item_key]['plid'] == $node_links[$gid][$mlid]['plid']) {
|
| 319 |
$remove = FALSE;
|
| 320 |
}
|
| 321 |
if (!$remove) {
|
| 322 |
$group = node_load($key);
|
| 323 |
// Check node is a group node, as there might be non-group nodes
|
| 324 |
// in the book outline.
|
| 325 |
if (!og_is_group_type($group->type)) {
|
| 326 |
$remove = TRUE;
|
| 327 |
}
|
| 328 |
}
|
| 329 |
if ($remove) {
|
| 330 |
// Group post doesn't need to be propagated to this group node.
|
| 331 |
unset($node_links[$key]);
|
| 332 |
}
|
| 333 |
}
|
| 334 |
}
|