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

Contents of /contributions/modules/me/me.module

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


Revision 1.11 - (show annotations) (download) (as text)
Sun Feb 22 21:15:19 2009 UTC (9 months ago) by cdale
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +3 -3 lines
File MIME type: text/x-php
Fix for issue [#368252] which changes the weight of the 'me' module.
1 <?php
2 // $Id: me.module,v 1.10 2009/01/30 21:39:28 cdale Exp $
3
4 /**
5 * @file
6 *
7 * Provides 'me' aliases to allow users to enter 'me' in common paths instead of their user id.
8 */
9
10 /**
11 * Constants defining the different ways paths can be matched.
12 */
13 // Exclude paths
14 define('ME_PATH_EXCLUDE', 0);
15
16 // Include paths
17 define('ME_PATH_INCLUDE', 1);
18
19 // PHP for paths
20 define('ME_PATH_PHP', 2);
21
22 /**
23 * Implementation of hook_help().
24 */
25 function me_help($path, $arg) {
26 switch ($path) {
27 case 'admin/help#me':
28 return t("Allows a user to enter user/me, blog/me etc.. using 'me' in place of their user id.");
29 }
30 }
31
32 /**
33 * Implementation of hook_theme_registry_alter().
34 */
35 function me_theme_registry_alter(&$theme_registry) {
36 if (isset($theme_registry['menu_item_link']['function'])) {
37 variable_set('me_theme_menu_item_link_func', $theme_registry['menu_item_link']['function']);
38 $theme_registry['menu_item_link']['function'] = 'me_theme_menu_item_link';
39 }
40 }
41
42 /**
43 * Implementaiton of moduleName_preprocess_hook() for theme_menu_item_link.
44 */
45 function me_preprocess_menu_item_link(&$vars) {
46 _me_check_path($vars['link']);
47 }
48
49 /**
50 * Implementation of theme_menu_item_link().
51 */
52 function me_theme_menu_item_link($link) {
53 _me_check_path($link);
54 $function = me_variable_get('me_theme_menu_item_link_func');
55 return $function($link);
56 }
57
58 /**
59 * Helper function to check if a path can be rewritten or not.
60 *
61 * By this stage, the path is already rewritten, so we need to
62 * reverse the process.
63 *
64 * @param &$link
65 * The link object to check.
66 */
67 function _me_check_path(&$link) {
68 // If the link has been rewritten, and we are not supposed to be handling this
69 // path, then rewite it back to its original.
70 if (me_variable_get('me_rewrite_link') && !_me_handle_path($link['href'])) {
71 $path_parts = explode('/', $link['href'], MENU_MAX_PARTS);
72
73 // The wildcarded path will either be in $link['path'], or $link['router_path'].
74 $wild_parts = explode('/', (isset($link['path']) ? $link['path'] : $link['router_path']), MENU_MAX_PARTS);
75
76 // Go over each of the path parts and if one is equal to the me alias, make sure it is a wildcard,
77 // and if so, switch it back out.
78 while (list($key, $val) = each($path_parts)) {
79 if (_me_is_alias($val) && $wild_parts[$key] == '%') {
80 $path_parts[$key] = $GLOBALS['user']->uid;
81 }
82 }
83
84 $link['href'] = implode('/', $path_parts);
85 }
86 }
87
88 /**
89 * Helper function to keep all the variable gets in one place.
90 *
91 * @param $name
92 * The variable we wish to retrieve.
93 *
94 * @return mixed
95 * The value of the requested variable.
96 */
97 function me_variable_get($name) {
98 static $defaults = array(
99 'me_alias' => 'me',
100 'me_case_insensitive' => FALSE,
101 'me_redirect' => FALSE,
102 'me_path_rule' => ME_PATH_EXCLUDE,
103 'me_paths' => '',
104 'me_redirect_anonymous' => '',
105 'me_rewrite_link' => TRUE,
106 'me_theme_menu_item_link_func' => 'theme_menu_item_link',
107 'me_user_override' => FALSE,
108 );
109
110 return variable_get($name, $defaults[$name]);
111 }
112
113 /**
114 * Helper function to check if me should handle a given path.
115 *
116 * @param $path
117 * The path to check
118 *
119 * @return boolean
120 * TRUE if the path is handled by the me module. FALSE otherwise.
121 */
122 function _me_handle_path($path) {
123 // Match path if necessary
124 $paths = me_variable_get('me_paths');
125 $path_rule = me_variable_get('me_path_rule');
126 $path_match = TRUE;
127
128 if (!empty($paths)) {
129 if ($path_rule !== ME_PATH_PHP) {
130 $path = drupal_get_path_alias($_GET['q']);
131
132 // Compare with the internal and path alias (if any).
133 $path_match = drupal_match_path($path, $paths);
134 if ($path != $_GET['q']) {
135 $path_match = $path_match || drupal_match_path($_GET['q'], $paths);
136 }
137
138 // When $path_rule has a value of ME_PATH_EXCLUDE, then me works on
139 // all paths except those listed in $paths. When set to ME_PATH_INCLUDE, it
140 // is used only on those pages listed in $paths.
141 $path_match = !($path_rule xor $path_match);
142 }
143 else {
144 $path_match = drupal_eval($paths);
145 }
146 }
147
148 return $path_match;
149 }
150
151 /**
152 * A special menu callback function that either redirects to
153 * a page with the uid in the path, or calls the real menu handler.
154 *
155 * @param $parts
156 * The menu parts we are working with.
157 * @param $callback
158 * The page callback to call.
159 * @param ...
160 * count($parts) arguments for each part of the actual path
161 * @param ...
162 * Any extra arguments will be the real page arguments.
163 *
164 * @return mixed
165 * Whatever the real page callback returns.
166 */
167 function me_handler($parts, $callback) {
168 // Get the arguments, and shift off $parts and $callback.
169 $args = func_get_args();
170 array_shift($args);
171 array_shift($args);
172
173 // If we want the uid shown in the address bar, we need to do a redirect.
174 if (me_variable_get('me_redirect') || _me_user_disabled() || !_me_handle_path($_GET['q'])) {
175 $redirect = FALSE;
176 // Get the menu path arguments.
177 $menu_parts = explode('/', $_GET['q'], MENU_MAX_PARTS);
178
179 // Loop over each part. If it's a %me wildcard, then
180 // check the corresponding menu part for the me alias,
181 // if so, replace it out with the user id so we can redirect correctly.
182 // If no changes are required, then call the required function.
183 while (list($key, $val) = each($parts)) {
184 if (0 === strpos($val, '%me') && _me_is_alias($menu_parts[$key])) {
185 $redirect = TRUE;
186 $menu_parts[$key] = $GLOBALS['user']->uid;
187 }
188 }
189
190 if ($redirect) {
191 $path = implode('/', $menu_parts);
192 // Save on an extra redirect by also checking the anonymous redirect here.
193 $redirect_path = me_variable_get('me_redirect_anonymous');
194 if ($GLOBALS['user']->uid == 0 && !empty($redirect_path)) {
195 $path = $redirect_path;
196 }
197 drupal_goto($path);
198 }
199 }
200
201 return call_user_func_array($callback, $args);
202 }
203
204 /**
205 * Helper function to check if a user can have, and has me disabled.
206 *
207 * @return boolean
208 * TRUE if the user has me disabled. FALSE otherwise.
209 */
210 function _me_user_disabled() {
211 return me_variable_get('me_user_override') && !empty($GLOBALS['user']->me_disable);
212 }
213
214 /**
215 * Implementation of hook_menu_alter().
216 */
217 function me_menu_alter(&$callbacks) {
218 // Loop over each of the paths, finding all %user* loaders,
219 // and replace them with a %me equivelant. This should catch
220 // all drupal modules that use the %user loader to load up
221 // user objects, which should be most well written D6 modules.
222 // Certainly all of core.
223 $processed = array();
224 //XXX: For now, we only handle known user loaders. I might make a module hook, or a configuration
225 // area to allow these to be exteneded if users make the requests.
226 $handlers = array('%user', '%user_uid_optional', '%user_category');
227 foreach ($callbacks as $path => $data) {
228 $found = FALSE;
229 $parts = explode('/', $path, MENU_MAX_PARTS);
230 foreach ($handlers as $handler) {
231 if (in_array($handler, $parts)) {
232 $found = TRUE;
233 break;
234 }
235 }
236
237 if ($found) {
238 // We need to make sure that the correct files are loaded up. when the path
239 // is used.
240 if (isset($data['file']) && !isset($data['file path'])) {
241 $data['file path'] = drupal_get_path('module', $data['module']);
242 }
243
244 // We need to find the right page callback and page arguments to make
245 // the me handler work correctly.
246 $new_parts = array();
247
248 // The only load argument that needs to be passed by reference is map.
249 // We make sure that we have map in the right place to be passed by reference.
250 if (!is_array($data['load arguments'])) {
251 $data['load arguments'] = array();
252 }
253
254 $load_arguments = array();
255 while (list($key, $val) = each($parts)) {
256 if (in_array($val, $handlers)) {
257 $load_arguments[$key] = str_replace('%', '', $val) .'_load';
258 $val = '%me';
259 }
260 $new_parts[] = $val;
261 }
262 $new_path = implode('/', $new_parts);
263
264 // Find the current map index, and add our load arguments, putting map
265 // in the place we expect it to be.
266 if (FALSE !== ($map_index = array_search('%map', $data['load arguments']))) {
267 unset($data['load arguments'][$map_index]);
268 $map_index = strval($map_index);
269 }
270
271 array_unshift($data['load arguments'], $load_arguments, '%map', '%index', $map_index);
272
273 // First, we need to find the parent.
274 $parent_path = implode('/', array_slice($parts, 0, count($parts) - 1));
275 if (in_array($parent_path, $processed)) {
276 $parts = explode('/', $new_path, MENU_MAX_PARTS);
277 $parent_path = implode('/', array_slice($parts, 0, count($parts) - 1));
278 }
279 $parent = $callbacks[$parent_path];
280
281 if (!isset($data['page callback']) && isset($parent['page callback'])) {
282 $data['page callback'] = $parent['page callback'];
283 if (!isset($data['page arguments']) && isset($parent['page arguments'])) {
284 $data['page arguments'] = $parent['page arguments'];
285 }
286 if (!isset($data['file']) && isset($parent['file'])) {
287 $data['file'] = $parent['file'];
288 }
289 if (!isset($data['file path']) && isset($parent['file path'])) {
290 $data['file path'] = $parent['file path'];
291 }
292 }
293
294 if (isset($data['page callback'])) {
295 if (!is_array($data['page arguments'])) {
296 $data['page arguments'] = array();
297 }
298
299 $parts = explode('/', $new_path, MENU_MAX_PARTS);
300 $data['page arguments'] = array_merge(array($parts, $data['page callback']), $data['page arguments']);
301 $data['page callback'] = 'me_handler';
302 }
303
304 $callbacks[$new_path] = $data;
305 unset($callbacks[$path]);
306 $processed[] = $path;
307 }
308 }
309 }
310
311 /**
312 * Menu load callback in place of user_load().
313 */
314 function me_load($uid, $arguments, &$map, $index, $map_index = FALSE) {
315 // We need to get all the arguments, remove our custom ones,
316 // put %map in the right place, then call the menu load callack.
317 $args = func_get_args();
318 array_splice($args, 0, min(5, count($args)));
319
320 if (FALSE !== $map_index) {
321 $insert = array(
322 &$map,
323 );
324 array_splice($args, $map_index, 0, $insert);
325 $map[$index] = _me_check_arg($uid);
326 }
327
328 array_unshift($args, _me_check_arg($uid));
329
330 // If we have a valid function to call, call it.
331 if (isset($arguments[$index]) && function_exists($arguments[$index])) {
332 return call_user_func_array($arguments[$index], $args);
333 }
334
335 return FALSE;
336 }
337
338 /**
339 * Menu to_arg function for %me.
340 */
341 function me_to_arg($arg, $map, $index) {
342 $uid = user_uid_optional_to_arg($arg, $map, $index);
343 if (me_variable_get('me_rewrite_link') && !_me_user_disabled()) {
344 return $uid == $GLOBALS['user']->uid ? me_variable_get('me_alias') : $uid;
345 }
346 else {
347 return $uid;
348 }
349 }
350
351 /**
352 * A Helper function to check for the 'me' alias.
353 *
354 * @param $arg
355 * The argument to check.
356 * @param $redirect
357 * When TRUE, anonymous users will be redirected if a path is available.
358 *
359 * @return mixed
360 * The current user id if a match is found, or the given argument
361 * if no match.
362 */
363 function _me_check_arg($arg, $redirect = TRUE) {
364 $return = _me_is_alias($arg) ? $GLOBALS['user']->uid : $arg;
365
366 $redirect_path = me_variable_get('me_redirect_anonymous');
367 if ($redirect && $return == 0 && !empty($redirect_path)) {
368 drupal_goto($redirect_path);
369 }
370
371 return $return;
372 }
373
374 /**
375 * A helper function to check if a string is equal to the 'me' alias.
376 *
377 * @param $arg
378 * The argument to check.
379 *
380 * @return boolean
381 * TRUE if the argument given is a 'me' alias. FALSE otherwise.
382 */
383 function _me_is_alias($arg) {
384 $compare_function = me_variable_get('me_case_insensitive') ? 'strcasecmp' : 'strcmp';
385 return $compare_function($arg, me_variable_get('me_alias')) === 0;
386 }
387
388 /**
389 * Implementation of hook_views_api().
390 */
391 function me_views_api() {
392 return array(
393 'api' => views_api_version(),
394 'path' => drupal_get_path('module', 'me') .'/includes',
395 );
396 }
397
398 /**
399 * Implementation of hook_menu().
400 */
401 function me_menu() {
402 $items = array();
403
404 $items['admin/settings/me'] = array(
405 'title' => "'Me' Aliases",
406 'description' => "Configure the 'me' aliases, and how they're matched.",
407 'page callback' => 'drupal_get_form',
408 'page arguments' => array('me_admin_settings_form'),
409 'access arguments' => array('administer site configuration'),
410 'type' => MENU_NORMAL_ITEM,
411 );
412
413 // TODO: Remove when/if http://drupal.org/node/109588 gets in.
414 // We don't need this here if we are doing redirects.
415 if (!me_variable_get('me_redirect')) {
416 $items['user/'. me_variable_get('me_alias') .'/edit'] = array(
417 'title' => 'Edit',
418 'page callback' => 'me_user_edit',
419 'access callback' => 'me_user_edit_access',
420 'type' => MENU_LOCAL_TASK,
421 );
422 }
423
424 return $items;
425 }
426
427 /**
428 * Menu callback to redirect to the user edit pages with the correct
429 * user id.
430 *
431 * TODO: Remove when/if http://drupal.org/node/109588 gets in.
432 */
433 function me_user_edit() {
434 drupal_goto('user/'. $GLOBALS['user']->uid .'/edit');
435 }
436
437 /**
438 * Menu access callback to check access before user edit redirection
439 * takes place. This keeps 'me' in the path when access will be denied
440 * anyway, and saves an extra request.
441 *
442 * TODO: Remove when/if http://drupal.org/node/109588 gets in.
443 */
444 function me_user_edit_access() {
445 return user_edit_access($GLOBALS['user']);
446 }
447
448 /**
449 * Implementation of hook_perm().
450 */
451 function me_perm() {
452 return array(
453 'use PHP for me alias paths',
454 );
455 }
456
457 /**
458 * Form callback for the admin settings form.
459 */
460 function me_admin_settings_form(&$form_state) {
461 $form = array();
462
463 $form['me_alias'] = array(
464 '#type' => 'textfield',
465 '#title' => t("'Me' Alias"),
466 '#description' => t('The alias to use to represent the current users uid.'),
467 '#default_value' => me_variable_get('me_alias'),
468 '#required' => TRUE,
469 );
470
471 $form['me_case_insensitive'] = array(
472 '#type' => 'checkbox',
473 '#title' => t('Case Insensitive Alias Checking'),
474 '#description' => t('When checked, "Me" will be matched the same as "me", "ME", and "mE".'),
475 '#default_value' => me_variable_get('me_case_insensitive'),
476 );
477
478 $form['me_rewrite_link'] = array(
479 '#type' => 'checkbox',
480 '#title' => t('Rewrite links generated by the drupal menu system'),
481 '#description' => t('When checked, links output by the drupal menu system will replace uid with the me alias.'),
482 '#default_value' => me_variable_get('me_rewrite_link'),
483 );
484
485 $form['me_user_override'] = array(
486 '#type' => 'checkbox',
487 '#title' => t('Allow users to turn off me for their account'),
488 '#default_value' => me_variable_get('me_user_override'),
489 );
490
491 $form['me_redirect'] = array(
492 '#type' => 'checkbox',
493 '#title' => t('Redirect to uid'),
494 '#description' => t('When checked, perform a redirect so the users uid is shown in the address bar instead of the me alias.'),
495 '#default_value' => me_variable_get('me_redirect'),
496
497 );
498
499 $form['me_redirect_anonymous'] = array(
500 '#type' => 'textfield',
501 '#title' => t('Redirect anonymous users'),
502 '#description' => t('When this is non-empty, anonymous users will be redirected to the specified drupal path.'),
503 '#default_value' => me_variable_get('me_redirect_anonymous'),
504 );
505
506 $access = user_access('use PHP for me alias paths');
507 $path_rule = me_variable_get('me_path_rule');
508 $paths = me_variable_get('me_paths');
509
510 if ($path_rule == ME_PATH_PHP && !$access) {
511 $form['me_paths_settings'] = array();
512 $form['me_paths_settings']['me_path_rule'] = array('#type' => 'value', '#value' => $path_rule);
513 $form['me_paths_settings']['me_paths'] = array('#type' => 'value', '#value' => $paths);
514 }
515 else {
516 $options = array(
517 ME_PATH_EXCLUDE => t('Use me alias on every path except the listed paths.'),
518 ME_PATH_INCLUDE => t('Use me alias only on the listed paths.'),
519 );
520 $description = t("Enter one path per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the '
521 .'blog page and %blog-wildcard for every personal blog. %front is the front page.",
522 array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
523
524 if ($access) {
525 $options[ME_PATH_PHP] = t('Use me alias if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
526 $description .= ' '. t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can '
527 .'break your Drupal site.', array('%php' => '<?php ?>'));
528 }
529 $form['me_paths_settings']['me_path_rule'] = array(
530 '#type' => 'radios',
531 '#title' => t('Use me alias on specific paths'),
532 '#options' => $options,
533 '#default_value' => $path_rule,
534 );
535 $form['me_paths_settings']['me_paths'] = array(
536 '#type' => 'textarea',
537 '#title' => t('Paths'),
538 '#default_value' => $paths,
539 '#description' => $description . t('<p>NOTE: This option simply ensures that the browser address bar for these paths have '
540 .'the uid and not me. The me alias will still work for these paths. It will have no effect on specific uids in paths, '
541 .'but if the path includes the me alias, then me will be affected for those paths. This will only affect paths '
542 .'that me can already handle. It will not allow me to work for unknown paths.</p>'),
543 );
544 }
545
546 $form['#validate'] = array('me_admin_settings_form_validate');
547
548 $form = system_settings_form($form);
549
550 // Quite a few options only have an affect on theme and menu rebuilds. We just do them here
551 // to make sure the options have an instant effect.
552 $form['#submit'][] = 'menu_rebuild';
553 $form['#submit'][] = 'drupal_rebuild_theme_registry';
554
555 return $form;
556 }
557
558 /**
559 * Validation callback for me_admin_settings_form.
560 */
561 function me_admin_settings_form_validate($form, &$form_state) {
562 if (preg_match('/[^a-zA-Z]/', $form_state['values']['me_alias'])) {
563 form_set_error('me_alias', t('The alias can only contain characters from a-z and A-Z.'));
564 }
565 }
566
567 /**
568 * Implementation of hook_user().
569 */
570 function me_user($op, &$edit, &$account, $category = NULL) {
571 switch ($op) {
572 case 'categories':
573 if (me_variable_get('me_user_override')) {
574 return array(
575 array(
576 'name' => 'me',
577 'title' => t("'@me' alias", array('@me' => me_variable_get('me_alias'))),
578 'weight' => 2,
579 ),
580 );
581 }
582 break;
583 case 'form' && $category == 'me':
584 $form = array();
585
586 $form['me_uid'] = array(
587 '#type' => 'item',
588 '#title' => t('User id'),
589 '#value' => $account->uid,
590 );
591
592 $form['me_disable'] = array(
593 '#type' => 'checkbox',
594 '#title' => t("Disable '%me' alias for this account", array('%me' => me_variable_get('me_alias'))),
595 '#description' => t('This option stops your user id from being replaced with %me. %me will still work when entered '
596 .'into the address bar, but you will be redirected to a page with your uid in its place.',
597 array('%me' => me_variable_get('me_alias'))),
598 '#default_value' => !empty($account->me_disable),
599 );
600
601 return $form;
602 case 'view':
603 if (me_variable_get('me_user_override')) {
604 $enabled = 'enabled';
605 if (!empty($account->me_disable)) {
606 $enabled = 'disabled';
607 }
608
609 $account->content['me'] = array(
610 '#type' => 'markup',
611 '#value' => t("'%me' aliases are $enabled for this account. Account user id is '@uid'.",
612 array('%me' => me_variable_get('me_alias'), '@uid' => $account->uid)),
613 '#weight' => 10,
614 );
615 }
616 break;
617 }
618 }

  ViewVC Help
Powered by ViewVC 1.1.2