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

Contents of /contributions/modules/menu_stp/menu_stp.module

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


Revision 1.5 - (show annotations) (download) (as text)
Thu Apr 23 17:31:42 2009 UTC (7 months ago) by rwohleb
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +323 -209 lines
File MIME type: text/x-php
Refactored code to fit with Drupal coding standards. Fixed security issues. Made compatible with D6.
1 <?php
2 // $Id: menu_stp.module,v 1.1.2.3 2007/08/09 11:07:40 ray007 Exp $
3
4 /**
5 * @file
6 * Allow user to add nodes into specific portions of the menu structure.
7 */
8
9 // TODO: Handle node deletion
10
11 /**
12 * Implementation of hook_form_alter().
13 */
14 function menu_stp_form_alter(&$form, &$form_state, $form_id) {
15 switch ($form_id) {
16 case 'menu_edit_menu':
17 _menu_stp_form_alter_menu_edit_menu($form, $form_state, $form_id);
18 break;
19
20 case 'menu_edit_item':
21 // Skip if this is a new menu item.
22 // TODO: Is this required?
23 if (empty($form['menu']['mlid']['#value'])) {
24 return;
25 }
26
27 _menu_stp_form_alter_menu_edit_item(&$form, &$form_state, $form_id);
28 break;
29
30 case 'menu_delete_menu_confirm':
31 // Register submit handler.
32 $form['#submit'][] = 'menu_stp_delete_menu_confirm';
33 break;
34
35 case 'menu_item_delete_form':
36 // Register submit handler.
37 $form['#submit'][] = 'menu_stp_delete_menu_item_confirm';
38 break;
39
40 default:
41 // Is this a node edit form?
42 if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
43 // Skip if user has 'administer menu' permission.
44 if (user_access('administer menu')) {
45 return;
46 }
47
48 // Modify the menu form elements.
49 _menu_stp_form_alter_node_edit_form($form, $form_state, $form_id);
50 }
51 }
52 }
53
54 function _menu_stp_form_alter_menu_edit_menu(&$form, &$form_state, $form_id) {
55 $mlid = 0;
56 $menu_name = (!empty($form['menu_name']['#value'])) ? $form['menu_name']['#value'] : '';
57
58 // Register submit handler.
59 $form['#submit'][] = 'menu_stp_form_submission';
60
61 // Add form elements.
62 $form += _menu_stp_form($mlid, $menu_name);
63 }
64
65 function _menu_stp_form_alter_menu_edit_item(&$form, &$form_state, $form_id) {
66 $mlid = (!empty($form['menu']['mlid']['#value'])) ? $form['menu']['mlid']['#value'] : 0;
67 $menu_name = '';
68
69 // Register submit handler.
70 $form['#submit'][] = 'menu_stp_form_submission';
71
72 // Add form elements.
73 $form += _menu_stp_form($mlid);
74 }
75
76 /**
77 * Helper function that creates the STP form.
78 * If $mlid is provided it assumes this is for a sub-tree.
79 * If $menu_name is provided it assumes it is for a menu root.
80 */
81 function _menu_stp_form($mlid, $menu_name = '') {
82 $form = array();
83
84 // Add fields for additional permissions.
85 $form['menu_stp'] = array(
86 '#type' => 'fieldset',
87 '#title' => t('Menu Sub-tree Permissions'),
88 '#access' => user_access('administer menu'),
89 '#collapsible' => TRUE,
90 '#collapsed' => TRUE,
91 '#weight' => variable_get('menu_stp_item_edit_weight', -10),
92 );
93
94 $form['menu_stp']['menu_stp_perms_roles'] = array(
95 '#type' => 'checkboxes',
96 '#title' => t('Roles'),
97 '#options' => user_roles(TRUE), // Get all roles, except anonymous.
98 '#default_value' => !empty($mlid) ? _menu_stp_get_rids_by_mlid($mlid) : _menu_stp_get_rids_by_menu_name($menu_name),
99 '#description' => t('Select the roles that will be allowed to edit this sub-tree.'),
100 );
101 // TODO: more options for other auth-methods, like ACL and organic groups.
102 // Probably only links to forms here, so this form doesn't get too big.
103
104 return $form;
105 }
106
107 /**
108 * Helper function to manipulate the menu settings on the node edit page.
109 */
110 function _menu_stp_form_alter_node_edit_form(&$form, &$form_state, $form_id) {
111 $rids = _menu_stp_get_user_roles();
112 $mlid = $form['menu']['mlid']['#value'];
113
114 // If current user has no roles, skip check.
115 // This shouldn't be possible.
116 if (empty($rids)) {
117 return;
118 }
119
120 // Do we already have a menu item?
121 if (!empty($mlid)) {
122 $plid = db_result(db_query("SELECT plid FROM {menu_links} WHERE mlid = %d", $mlid));
123 if (!_menu_stp_has_perms_roles($plid, $rids)) {
124 // Existing menu item is not in a permissable sub-tree.
125 // TODO: There should be better error handling here.
126 return;
127 }
128 }
129
130 // Get array of permissable menu roots.
131 $mroots = _menu_stp_get_menu_names_by_rids($rids);
132
133 // Get array of permissable menu items.
134 $mitems = _menu_stp_get_mlids_by_rids($rids);
135
136 if (empty($mroots) && empty($mitems)) {
137 // There are no permissable roots/sub-trees for this user.
138 // TODO: There should be better error handling here.
139 return;
140 }
141
142 // No advanced setting for normal user.
143 //? Drupal5.x
144 unset($form['menu']['advanced']);
145
146 // Seems we can do something -> enable form part.
147 //? Drupal5.x
148 $form['menu']['#access'] = true;
149
150 // Correct the parent select options.
151 foreach(array_keys($form['menu']['parent']['#options']) as $option) {
152 list($menu_name, $plid) = explode(":",$option);
153
154 // If no permissions for this menu root, remove it.
155 if (empty($plid) && !in_array($menu_name, $mroots)) {
156 unset($form['menu']['parent']['#options'][$option]);
157 }
158 // If no permissions for this menu item, remove it.
159 elseif (!isset($mitems[$menu_name][$plid])) {
160 unset($form['menu']['parent']['#options'][$option]);
161 }
162 // If this is a sub-tree root, fix the title.
163 elseif ($mitems[$menu_name][$plid] && !empty($plid)) {
164 $form['menu']['parent']['#options'][$option] = _menu_stp_full_title($plid);
165 }
166 }
167 }
168
169 /**
170 * Create a menu title indicating the position in the menu structure.
171 */
172 function _menu_stp_full_title($mlid) {
173 $link = menu_link_load($mlid);
174 $title = $link['title'];
175 $mlid = $link['plid'];
176 $menu_name = $link['menu_name'];
177
178 $depth = 1;
179 while($mlid) {
180 $depth++;
181
182 $link = menu_link_load($mlid);
183 $title = $link['title'] . '/' . $title;
184 $mlid = $link['plid'];
185 }
186
187 return str_repeat('--', $depth) . ' ' . $menu_name . '/' . $title;
188 }
189
190 /**
191 * Helper function to get all menu roots permissable for a set of roles.
192 */
193 function _menu_stp_get_menu_names_by_rids($rids) {
194 $menus = array();
195
196 $result = db_query("SELECT DISTINCT menu_name FROM {menu_stp_menu_roles} WHERE rid IN (" . db_placeholders($rids, 'int') . ")", $rids);
197 while($row = db_fetch_object($result)) {
198 if (!empty($row->menu_name)) {
199 $menus[] = $row->menu_name;
200 }
201 }
202
203 return $menus;
204 }
205
206 /**
207 * Helper function to get all menu IDs permissable for a set of roles.
208 *
209 * @returns array with menu name as keys, which contains arrays with the menu-ids as keys, values: TRUE for subtree-roots, FALSE for editable items below
210 */
211 function _menu_stp_get_mlids_by_rids($rids) {
212 $menus = array();
213
214 // Get root menu items.
215 $result = db_query("SELECT DISTINCT mlid FROM {menu_stp_roles} WHERE rid IN (" . db_placeholders($rids, 'int') . ")", $rids);
216 while($row = db_fetch_object($result)) {
217 if (!empty($row->mlid)) {
218 $link = _menu_stp_link_load($row->mlid);
219 $row->menu_name = $link['menu_name'];
220 $menus[$row->menu_name][strval($row->mlid)] = TRUE;
221 }
222 }
223
224 foreach ($menus as $menu_name => $mlids) {
225 // Get the child items.
226 $new_mlids = array_keys($mlids);
227 while ($new_mlids) {
228 $result = db_query("SELECT menu_name, mlid FROM {menu_links} WHERE plid IN (" . db_placeholders($new_mlids, 'int') . ")", $new_mlids);
229 $new_mlids = array();
230 while($row = db_fetch_object($result)) {
231 // have we seen this mid before?
232 if (!isset($mlids[$row->mlid])) {
233 $new_mlids[] = $row->mlid;
234 }
235 if (!empty($row->mlid)) {
236 $menus[$row->menu_name][strval($row->mlid)] = FALSE;
237 }
238 }
239 }
240 }
241
242 return $menus;
243 }
244
245 /**
246 * Helper function to get all roles that are directly permissable for this menu root.
247 */
248 function _menu_stp_get_rids_by_menu_name($menu_name) {
249 $rids = array();
250
251 $result = db_query("SELECT rid FROM {menu_stp_menu_roles} WHERE menu_name = '%s'", $menu_name);
252 while($row = db_fetch_object($result)) {
253 $rids[] = $row->rid;
254 }
255
256 return $rids;
257 }
258
259 /**
260 * Helper function to get all roles that are directly permissable for this menu item.
261 */
262 function _menu_stp_get_rids_by_mlid($mlid) {
263 $rids = array();
264
265 $result = db_query("SELECT rid FROM {menu_stp_roles} WHERE mlid = %d", $mlid);
266 while($row = db_fetch_object($result)) {
267 $rids[] = $row->rid;
268 }
269
270 return $rids;
271 }
272
273 /**
274 * Check if a user with the supplied roles has permission for the menu item.
275 */
276 function _menu_stp_has_perms_roles($mlid, $rids, $recursive = TRUE) {
277 $mlids = array($mlid);
278
279 // If recursive, gather mids back to root.
280 if ($recursive) {
281 while(!empty($mlid)) {
282 $mlid = db_result(db_query("SELECT plid FROM {menu_links} WHERE mlid = %d", $mlid));
283 if (!empty($mlid)) {
284 $mlids[] = $mlid;
285 }
286 }
287 }
288
289 // Get permission count for this sub-tree.
290 return db_result(db_query(
291 "SELECT count(*) AS pnum " .
292 "FROM {menu_stp_roles} " .
293 "WHERE " .
294 "rid IN (" . db_placeholders($rids, 'int') . ") AND " .
295 "mlid IN (" . db_placeholders($mlids, 'int') . ")",
296 array_merge($rids, $mlids)
297 ));
298 }
299
300 /**
301 * Get roles for $account. If $account is NULL, get roles for current user.
302 */
303 function _menu_stp_get_user_roles($account = NULL) {
304 global $user;
305
306 if (empty($account->uid)) {
307 $account = $user;
308 }
309
310 if (!empty($account->roles)) {
311 return array_keys($account->roles);
312 }
313
314 return array();
315 }
316
317 /**
318 * Implementation of hook_help().
319 */
320 function menu_stp_help($path, $arg) {
321 switch ($path) {
322 case 'admin/help#menu_stp':
323 return t('Provide means to allow users to modify parts of the menu without giving permissions for the whole menu structure.');
324
325 case 'admin/modules#description':
326 return t('Allow users to edit some parts of the menu');
327 break;
328
329 default:
330 if (strstr($path, 'menu_stp')) {
331 return "Missing: help for section '$path' in module 'menu_stp'";
332 }
333 }
334 }
335
336 /**
337 * Registered callback for form submission
338 */
339 function menu_stp_form_submission($form, $form_state) {
340 $mlid = 0;
341 $menu_name = '';
342
343 switch ($form['form_id']['#value']) {
344 case 'menu_edit_item':
345 $mlid = !empty($form['menu']['mlid']['#value']) ? $form['menu']['mlid']['#value'] : 0;
346 break;
347
348 case 'menu_edit_menu':
349 $menu_name = !empty($form['menu_name']['#value']) ? $form['menu_name']['#value'] : '';
350 break;
351 }
352
353 // If we have a valid mlid, store using mlid.
354 if (!empty($mlid)) {
355 // Delete old permissions
356 db_query("DELETE FROM {menu_stp_roles} WHERE mlid = %d", $mlid);
357
358 foreach ($form_state['values']['menu_stp_perms_roles'] as $rid => $selected) {
359 // Does role get permission?
360 if ($selected) {
361 db_query("INSERT INTO {menu_stp_roles} (mlid, rid) VALUES (%d, %d)", $mlid, $rid);
362 }
363 }
364 }
365 // If we have only the menu name, store using menu name.
366 elseif (!empty($menu_name)) {
367 // Delete old permissions
368 db_query("DELETE FROM {menu_stp_menu_roles} WHERE menu_name = '%s'", $menu_name);
369
370 foreach ($form_state['values']['menu_stp_perms_roles'] as $rid => $selected) {
371 // Does role get permission?
372 if ($selected) {
373 db_query("INSERT INTO {menu_stp_menu_roles} (menu_name, rid) VALUES ('%s', %d)", $menu_name, $rid);
374 }
375 }
376 }
377 }
378
379 /**
380 * Registered callback for deleting a menu item
381 */
382 function menu_stp_delete_menu_item_confirm($form, $form_state) {
383 // A menu item is being deleted, so delete extra permissions as well.
384 db_query("DELETE FROM {menu_stp_roles} WHERE mlid = %d", $form['#item']['mlid']);
385 }
386
387 /**
388 * Registered callback for deleting a menu
389 */
390 function menu_stp_delete_menu_confirm($form, $form_state) {
391 // A menu item is being deleted, so delete extra permissions as well.
392 db_query("DELETE FROM {menu_stp_menu_roles} WHERE menu_name = '%s'", $form['#item']['menu_name']);
393 }
394
395 /**
396 * Same as menu_link_load, but without further processing
397 */
398 function _menu_stp_link_load($mlid) {
399 if (is_numeric($mlid) && $item = db_fetch_array(db_query("SELECT m.*, ml.* FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid))) {
400 return $item;
401 }
402 return FALSE;
403 }

  ViewVC Help
Powered by ViewVC 1.1.2