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

Contents of /contributions/modules/drupalvb/drupalvb.module

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


Revision 1.36 - (show annotations) (download) (as text)
Tue Aug 11 16:18:46 2009 UTC (3 months, 2 weeks ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.35: +2 -2 lines
File MIME type: text/x-php
#545702 by sun: Fixed fatal error on path drupalvb/logout.
1 <?php
2 // $Id: drupalvb.module,v 1.35 2009/08/02 01:21:43 sun Exp $
3
4 /**
5 * @file
6 * Drupal vB module core functions for Drupal.
7 *
8 * Note: vBulletin only supports MySQL, queries have been optimized.
9 */
10
11 require_once drupal_get_path('module', 'drupalvb') .'/drupalvb.inc.php';
12
13 /**
14 * Implementation of hook_theme().
15 */
16 function drupalvb_theme() {
17 return array(
18 'drupalvb_block_recent' => array(
19 'arguments' => array('recent' => NULL, 'vb_options' => NULL),
20 ),
21 'drupalvb_block_recent_user' => array(
22 'arguments' => array('recent' => NULL, 'vb_options' => NULL),
23 ),
24 'drupalvb_block_top_posters' => array(
25 'arguments' => array('items' => array()),
26 ),
27 'drupalvb_username' => array(
28 'arguments' => array('object' => NULL, 'class' => NULL),
29 ),
30 'drupalvb_settings_variables' => array(
31 'arguments' => array('form' => array()),
32 ),
33 );
34 }
35
36 /**
37 * Implementation of hook_help().
38 */
39 function drupalvb_help($path, $arg) {
40 switch ($path) {
41 case 'admin/settings#description':
42 return t('Allows basic integration of Drupal with a vBulletin forum.');
43
44 case 'admin/settings/drupalvb':
45 module_load_include('inc', 'drupalvb');
46 $vb_config = drupalvb_get('config');
47 $vb_options = drupalvb_get('options');
48 if (empty($vb_config)) {
49 return '';
50 }
51 $items = array(
52 l(t('View the Forum'), $vb_options['bburl']),
53 l(t('Forum Admin Control Panel'), $vb_options['bburl'] .'/'. $vb_config['Misc']['admincpdir']),
54 l(t('Forum Moderator Control Panel'), $vb_options['bburl'] .'/'. $vb_config['Misc']['modcpdir']),
55 );
56 return theme_item_list($items);
57
58 case 'admin/help#drupalvb':
59 return filter_filter('process', 2, NULL, file_get_contents(dirname(__FILE__) .'/README.txt'));
60 }
61 }
62
63 /**
64 * Implementation of menu_hook().
65 */
66 function drupalvb_menu() {
67 $items = array();
68
69 $items['admin/settings/drupalvb'] = array(
70 'title' => 'Drupal vB integration',
71 'page callback' => 'drupalvb_settings',
72 'page arguments' => array('integration'),
73 'description' => 'Configure integration of Drupal with vBulletin forum.',
74 'access arguments' => array('administer drupalvb'),
75 );
76 $items['admin/settings/drupalvb/integration'] = array(
77 'title' => 'Integration',
78 'type' => MENU_DEFAULT_LOCAL_TASK,
79 'weight' => -10,
80 );
81 $items['admin/settings/drupalvb/database'] = array(
82 'title' => 'Database',
83 'page callback' => 'drupalvb_settings',
84 'page arguments' => array('database'),
85 'access arguments' => array('administer drupalvb'),
86 'type' => MENU_LOCAL_TASK,
87 );
88 $items['admin/settings/drupalvb/actions'] = array(
89 'title' => 'Actions',
90 'page callback' => 'drupalvb_settings',
91 'page arguments' => array('actions'),
92 'access arguments' => array('administer drupalvb'),
93 'type' => MENU_LOCAL_TASK,
94 'weight' => 10,
95 );
96 $items['admin/settings/drupalvb/variables'] = array(
97 'title' => 'Variables',
98 'page callback' => 'drupalvb_settings',
99 'page arguments' => array('variables'),
100 'access arguments' => array('access devel information'),
101 'type' => MENU_LOCAL_TASK,
102 'weight' => 88,
103 );
104 $items['drupalvb/pms'] = array(
105 'page callback' => 'drupalvb_private_messages',
106 'access arguments' => array('access content'),
107 'type' => MENU_CALLBACK,
108 );
109 $items['drupalvb'] = array(
110 'page callback' => 'drupalvb_redirect',
111 'access callback' => 'drupalvb_acct_generation_access',
112 'type' => MENU_CALLBACK,
113 );
114 $items['drupalvb/login'] = array(
115 'page callback' => 'drupalvb_login',
116 'access callback' => TRUE,
117 'type' => MENU_CALLBACK,
118 );
119 $items['drupalvb/logout'] = array(
120 'page callback' => 'drupalvb_logout',
121 'access callback' => TRUE,
122 'type' => MENU_CALLBACK,
123 );
124
125 return $items;
126 }
127
128 /**
129 * Menu access callback; determine whether /drupalvb redirects are allowed.
130 */
131 function drupalvb_acct_generation_access() {
132 return variable_get('drupalvb_acct_generation', TRUE);
133 }
134
135 /**
136 * Implementation of hook_perm().
137 */
138 function drupalvb_perm() {
139 return array('administer drupalvb');
140 }
141
142 /**
143 * Form builder function for DrupalvB database connection.
144 */
145 function drupalvb_settings($form = 'integration') {
146 $path = drupal_get_path('module', 'drupalvb');
147 module_load_include('inc', 'drupalvb');
148 module_load_include('inc', 'drupalvb', 'drupalvb.admin-pages');
149 return drupal_get_form('drupalvb_settings_'. $form);
150 }
151
152 /**
153 * Implementation of hook_form_alter().
154 *
155 * Validate the submitted values of user login forms before Drupal core invokes
156 * its regular form validation callback.
157 *
158 * Add a validation handler to the password recovery form to import a user from
159 * vB, should one exist there.
160 *
161 * @see drupalvb_user_pass_validate()
162 */
163 function drupalvb_form_alter(&$form, $form_state, $form_id) {
164 if ($form_id == 'user_login_block' || $form_id == 'user_login') {
165 module_load_include('inc', 'drupalvb');
166
167 // Splice in our validate handler for authentication if user is performing
168 // a vBulletin login.
169 if (!empty($form_state['post']['name']) && drupalvb_db_is_valid()) {
170 $username = $form_state['post']['name'];
171 if ($vbuser = db_fetch_array(drupalvb_db_query("SELECT userid, password, salt, email FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($username)))) {
172 $key = array_search('user_login_final_validate', $form['#validate']);
173 if ($key !== FALSE) {
174 array_splice($form['#validate'], $key, 0, 'drupalvb_login_validate');
175 }
176 else {
177 // Another module altered the validation sequence before us, not sure
178 // how to properly handle this case...
179 $form['#validate'] = array('drupalvb_login_validate') + $form['#validate'];
180 }
181 }
182 }
183 }
184 else if ($form_id == 'user_pass') {
185 $form['#validate'] = array_merge(array('drupalvb_user_pass_validate' => array()), $form['#validate']);
186 }
187 }
188
189 /**
190 * Validate login against vBulletin user database.
191 */
192 function drupalvb_login_validate($form, &$form_state) {
193 global $user;
194
195 if (!variable_get('drupalvb_dual_login', TRUE)) {
196 return;
197 }
198 if ($user->uid) {
199 return;
200 }
201
202 $username = $form_state['values']['name'];
203 $password = trim($form_state['values']['pass']);
204
205 if (empty($username) || empty($password)) {
206 return;
207 }
208
209 // If this user already exists in Drupal, no further validation required.
210 $finduser = user_load(array('name' => $username));
211 if ($finduser && $finduser->uid) {
212 return TRUE;
213 }
214
215 module_load_include('inc', 'drupalvb');
216 if (!drupalvb_db_is_valid()) {
217 return;
218 }
219 if ($vbuser = db_fetch_array(drupalvb_db_query("SELECT userid, username, password, salt, email, joindate FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($username)))) {
220 // Rebuild the password.
221 $vbpassword = md5(md5($password) . $vbuser['salt']);
222 if ($vbuser['password'] === $vbpassword) {
223 // We have a valid vBulletin account, so try to lookup this user in the
224 // mapping table. If a mapping exists, then user_authenticate() didn't
225 // find a user with the given password, otherwise we wouldn't be here.
226 // This can happen if the user has been temporarily created by
227 // drupalvb_redirect().
228 if ($uid = drupalvb_user_load($vbuser['userid'])) {
229 // Only update the password of the existing Drupal user record.
230 $account = user_load(array('uid' => $uid));
231 $userinfo['pass'] = $password;
232 $user = user_save($account, $userinfo);
233 }
234 else {
235 // This user is completely unknown to Drupal, register a new account.
236 // Fall back on the user submitted user name if the vBulletin name
237 // contains encoded &amp;'s.
238 $username = (strpos($vbuser['username'], '&amp;') === FALSE ? $vbuser['username'] : $username);
239 $userinfo = array(
240 'name' => $username,
241 'pass' => $password,
242 'mail' => $vbuser['email'],
243 'init' => $username,
244 'created' => $vbuser['joindate'],
245 'status' => 1,
246 );
247 $user = user_save('', $userinfo);
248 watchdog('drupalvb', t('New external user: %user.', array('%user' => $user->name)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
249
250 // Update the mapping table.
251 drupalvb_set_mapping($user->uid, $vbuser['userid']);
252 }
253 return TRUE;
254 }
255 }
256 }
257
258 /**
259 * Validation handler for the password recovery form.
260 *
261 * Create a non-existent Drupal user if one with the requested username or mail
262 * exists in vB. Note that the user_pass form asks the user to enter a username
263 * OR email address in one form field internally called 'name'.
264 *
265 * @see user_pass_validate()
266 */
267 function drupalvb_user_pass_validate($form_id, $form_values) {
268 $name = $form_values['name'];
269
270 // Return if the given user exists in Drupal.
271 if (user_load(array('name' => $name)) || user_load(array('mail' => $name))) {
272 return;
273 }
274
275 module_load_include('inc', 'drupalvb');
276
277 // Try to import a corresponding user from vB.
278 if ($userid = db_result(drupalvb_db_query("SELECT userid FROM {user} WHERE username = '%s' OR email = '%s'", drupalvb_htmlspecialchars($name), $name))) {
279 drupalvb_lookup_drupal_user($userid);
280 }
281 }
282
283 /**
284 * Try to lookup a Drupal user account for a vBulletin user id, using the mapping
285 * table.
286 *
287 * @param $userid
288 * A vBulletin user id.
289 */
290 function drupalvb_user_load($userid) {
291 return db_result(db_query("SELECT uid FROM {drupalvb_users} WHERE userid = %d", $userid));
292 }
293
294 /**
295 * Implementation of hook_user().
296 */
297 function drupalvb_user($op, &$edit, &$account, $category = NULL) {
298 module_load_include('inc', 'drupalvb');
299 if (!drupalvb_db_is_valid()) {
300 return;
301 }
302
303 switch ($op) {
304 case 'login':
305 case 'logout':
306 if (variable_get('drupalvb_dual_login', TRUE)) {
307 $function = 'drupalvb_user_'. $op;
308 return $function($account);
309 }
310 break;
311
312 case 'validate':
313 if ($category == 'account' && (variable_get('drupalvb_acct_generation', TRUE) || variable_get('drupalvb_acct_sync', TRUE))) {
314 return drupalvb_user_validate(arg(1), $edit);
315 }
316 break;
317
318 case 'insert':
319 if (variable_get('drupalvb_acct_generation', TRUE)) {
320 return drupalvb_user_insert($account, $edit);
321 }
322 break;
323
324 case 'update':
325 if (variable_get('drupalvb_acct_sync', TRUE)) {
326 return drupalvb_user_update($account, $edit);
327 }
328 break;
329
330 case 'delete':
331 if (variable_get('drupalvb_acct_sync', TRUE)) {
332 return drupalvb_user_delete($account);
333 }
334 break;
335 }
336 }
337
338 /**
339 * Log in a user in vB upon login in Drupal.
340 *
341 * @see drupalvb_user()
342 */
343 function drupalvb_user_login($account) {
344 $vbuser = db_fetch_array(drupalvb_db_query_range("SELECT u.userid, ub.liftdate FROM {user} u LEFT JOIN {userban} ub ON ub.userid = u.userid WHERE u.username = '%s'", drupalvb_htmlspecialchars($account->name), 0, 1));
345
346 // Create account in vB if user does not exist.
347 if (!$vbuser) {
348 if (!$vbuser['userid'] = drupalvb_create_user($account, (array)$account)) {
349 // Indicates duplicate username (should not happen).
350 return FALSE;
351 }
352 }
353 // Succeed if not banned, set last activity time and ensure user mapping.
354 else if ($vbuser['liftdate'] < time()) {
355 drupalvb_update_user($account, array());
356 }
357 // User is banned.
358 else {
359 return FALSE;
360 }
361
362 // Setup vB user session and cookies.
363 if (drupalvb_set_login_cookies($vbuser['userid'])) {
364 return TRUE;
365 }
366 else {
367 drupal_set_message(t('Login to forums failed.'), 'error');
368 watchdog('drupalvb', t('Login to forum failed for user %user.', array('%user' => $account->name)), WATCHDOG_ERROR);
369 return FALSE;
370 }
371 }
372
373 /**
374 * Log out a user in vB upon logout in Drupal.
375 *
376 * @see drupalvb_user()
377 */
378 function drupalvb_user_logout($account) {
379 $vbuser = db_fetch_array(drupalvb_db_query_range("SELECT userid, username FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($account->name), 0, 1));
380 if ($vbuser) {
381 // Remove all vB cookies for current user.
382 drupalvb_clear_cookies($vbuser['userid']);
383 watchdog('drupalvb', t('Forum session closed for user %username (@uid).', array('%username' => $vbuser['username'], '@uid' => $vbuser['userid'])));
384 }
385 }
386
387 /**
388 * Ensure a username or e-mail address does not already exist in vB.
389 */
390 function drupalvb_user_validate($uid, &$edit) {
391 $userid = db_result(db_query("SELECT userid FROM {drupalvb_users} WHERE uid = %d", $uid));
392 // Validate the username.
393 if (arg(1) == 'register' || user_access('change own username') || user_access('administer users')) {
394 if (db_result(drupalvb_db_query_range("SELECT userid FROM {user} WHERE userid <> %d AND LOWER(username) = LOWER('%s')", $userid, drupalvb_htmlspecialchars($edit['name']), 0, 1))) {
395 form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
396 }
397 }
398
399 // Validate the e-mail address.
400 if (db_result(drupalvb_db_query_range("SELECT userid FROM {user} WHERE userid <> %d AND LOWER(email) = LOWER('%s')", $userid, drupalvb_htmlspecialchars($edit['mail']), 0, 1)) > 0) {
401 form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $edit['mail'], '@password' => url('user/password'))));
402 }
403 }
404
405 /**
406 * Register a new user in vB upon registration in Drupal.
407 *
408 * @see drupalvb_user()
409 */
410 function drupalvb_user_insert($account, $edit) {
411 global $user;
412
413 if ($userid = drupalvb_create_user($account, $edit)) {
414 // Prevent overriding cookies of administrators.
415 if ($edit['name'] === $user->name) {
416 drupalvb_set_login_cookies($userid);
417 }
418 }
419 }
420
421 /**
422 * Update a user in vB upon update in Drupal.
423 *
424 * @see drupalvb_user()
425 */
426 function drupalvb_user_update($account, $edit) {
427 global $user;
428
429 // Update data if user exists.
430 if ($vbuser = db_fetch_array(drupalvb_db_query_range("SELECT userid, salt FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($account->name), 0, 1))) {
431 // Merge current username, salt, and finally edited values into one array,
432 // so usernames may be altered (if allowed).
433 drupalvb_update_user($account, array_merge(array('name' => $account->name), $vbuser, $edit));
434 }
435 // If not, create a new user in vB.
436 else {
437 if (!$vbuser['userid'] = drupalvb_create_user($account, array_merge(array('name' => $account->name), $edit))) {
438 // Indicates duplicate username (should not happen).
439 return;
440 }
441 }
442
443 // Prevent overriding cookies of administrators.
444 if ($account->name == $user->name) {
445 drupalvb_set_login_cookies($vbuser['userid']);
446 }
447 }
448
449 /**
450 * Delete a user in vB upon deletion in Drupal.
451 *
452 * @see drupalvb_user()
453 */
454 function drupalvb_user_delete($account) {
455 // If vBulletin user exists, delete user account, session and profile data.
456 if ($userid = db_result(drupalvb_db_query("SELECT userid FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($account->name)))) {
457 drupalvb_db_query("DELETE FROM {session} WHERE userid = %d", $userid);
458 drupalvb_db_query("DELETE FROM {user} WHERE userid = %d", $userid);
459 drupalvb_db_query("DELETE FROM {userfield} WHERE userid = %d", $userid);
460 drupalvb_db_query("DELETE FROM {usertextfield} WHERE userid = %d", $userid);
461 }
462 // Delete from mapping table.
463 db_query("DELETE FROM {drupalvb_users} WHERE uid = %d", $account->uid);
464 }
465
466 /**
467 * Log in a user; menu callback.
468 *
469 * This is required for login forms embedded in vBulletin, to ensure a user is
470 * properly logged in into both systems.
471 */
472 function drupalvb_login() {
473 global $user;
474
475 if ($_POST['name']) {
476 $form_state = array('values' => $_POST);
477 if ($user->uid) {
478 // If the user is already logged in to Drupal, we ensure the same for
479 // vBulletin.
480 if (drupalvb_login_validate(array(), $form_state)) {
481 drupal_goto(!empty($_REQUEST['destination']) ? $_REQUEST['destination'] : 'user/'. $user->uid);
482 }
483 else {
484 // Where do we go from here? user/login won't work, as the user is
485 // already authenticated in Drupal.
486 unset($_REQUEST['destination']);
487 drupal_goto(variable_get('site_frontpage', 'node'));
488 }
489 }
490 else {
491 // Otherwise perform the full login procedure.
492 foreach (user_login_default_validators() as $validator) {
493 $validator(array(), $form_state);
494 }
495 if (!form_get_errors()) {
496 user_login_submit(array(), $form_state);
497 $redirect = (isset($form_state['redirect']) ? $form_state['redirect'] : '');
498 drupal_goto(!empty($_REQUEST['destination']) ? $_REQUEST['destination'] : $redirect);
499 }
500 else {
501 // Login failed: send back to login form.
502 unset($_REQUEST['destination']);
503 drupal_goto('user/login');
504 }
505 }
506 }
507 }
508
509 /**
510 * Log out a user (ensuring a logout in vBulletin); menu callback.
511 *
512 * This is required in cases a user manages to log out from Drupal, but not
513 * from vBulletin (due to stale cookies or any other possible event).
514 *
515 * @see drupalvb_user_logout()
516 */
517 function drupalvb_logout() {
518 global $user;
519 module_load_include('inc', 'drupalvb');
520 module_load_include('inc', 'user', 'user.pages');
521
522 if ($user->uid) {
523 if (module_exists('singlesignon')) {
524 _singlesignon_session_logout($user->uid);
525 }
526
527 // If user is logged on in Drupal, we just invoke the regular logout
528 // procedure, which will invoke drupalvb_user_logout().
529 user_logout();
530 }
531 else {
532 // If there is no user session in Drupal for the user trying to logout,
533 // something went wrong and we can only invalidate the user's cookies.
534 drupalvb_clear_cookies();
535 drupal_goto('');
536 }
537 }
538
539 /**
540 * Implementation of hook_panels_include_directory().
541 */
542 function drupalvb_panels_include_directory($plugintype) {
543 switch ($plugintype) {
544 case 'content_types':
545 return $plugintype;
546 }
547 }
548
549 /**
550 * Implementation of hook_block().
551 */
552 function drupalvb_block($op = 'list', $delta = 0, $edit = array()) {
553 global $user;
554
555 if ($op == 'list') {
556 $blocks = array();
557 $blocks['recent']['info'] = t('vBulletin: Recent forum threads/posts');
558 $blocks['recent_user']['info'] = t('vBulletin: Recent posts by user (user account)');
559 $blocks['top_posters']['info'] = t('vBulletin: User list of top forum posters');
560 $blocks['user']['info'] = t('vBulletin: User info');
561 $blocks['stats']['info'] = t('vBulletin: Overall statistics');
562 return $blocks;
563 }
564 else if ($op == 'configure') {
565 $form = array();
566 switch ($delta) {
567 case 'recent':
568 $form['drupalvb_block_recent_type'] = array(
569 '#type' => 'radios',
570 '#title' => t('Type of displayed items'),
571 '#default_value' => variable_get('drupalvb_block_recent_type', 'threads'),
572 '#options' => array(
573 'threads' => t('Recent forum threads'),
574 'posts' => t('Recent forum posts'),
575 ),
576 '#description' => t('Please choose whether the block should display recent threads or posts.'),
577 );
578 $form['drupalvb_block_recent_count'] = array(
579 '#type' => 'select',
580 '#title' => t('Number of items'),
581 '#default_value' => variable_get('drupalvb_block_recent_count', 5),
582 '#options' => drupal_map_assoc(range(1, 12)),
583 );
584 $form['drupalvb_block_recent_limit'] = array(
585 '#type' => 'select',
586 '#title' => t('Timeframe threshold'),
587 '#default_value' => variable_get('drupalvb_block_recent_limit', 7),
588 '#options' => drupal_map_assoc(array_merge(range(1, 8), range(14, 30, 7), range(30, 360, 30))),
589 '#description' => t('How many days back you want the recent posts/threads to include.'),
590 );
591 $form['drupalvb_block_recent_authors'] = array(
592 '#type' => 'checkbox',
593 '#title' => t('Display author names'),
594 '#default_value' => variable_get('drupalvb_block_recent_authors', 0),
595 '#return_value' => 1,
596 '#description' => t('Enable this option to display author names for recent threads/posts.'),
597 );
598 return $form;
599
600 case 'user':
601 $form['drupalvb_block_user'] = array(
602 '#type' => 'checkboxes',
603 '#title' => t('Display Options'),
604 '#default_value' => variable_get('drupalvb_block_user', drupal_map_assoc(array('newposts', 'recent', 'online', 'pms'))),
605 '#options' => array(
606 'newposts' => t('New posts (since last visit)'),
607 'recent' => t('Recent posts (last 24 hours)'),
608 'online' => t('Users online'),
609 'pms' => t('New private messages'),
610 ),
611 '#description' => t('Please select which information should be displayed in the user info block.'),
612 );
613 return $form;
614
615 case 'stats':
616 $form['drupalvb_block_stats'] = array(
617 '#type' => 'checkboxes',
618 '#title' => t('Display Options'),
619 '#default_value' => variable_get('drupalvb_block_stats', drupal_map_assoc(array('threads', 'posts', 'tmembers', 'amembers'))),
620 '#options' => array(
621 'threads' => t('Total Threads'),
622 'posts' => t('Total Posts'),
623 'tmembers' => t('Total Members'),
624 'amembers' => t('Active Members'),
625 ),
626 '#description' => t('Choose what information is shown in the Forum Admin block.'),
627 );
628 return $form;
629 }
630 }
631 else if ($op == 'save') {
632 if ($delta == 'recent') {
633 variable_set('drupalvb_block_recent_type', $edit['drupalvb_block_recent_type']);
634 variable_set('drupalvb_block_recent_count', $edit['drupalvb_block_recent_count']);
635 variable_set('drupalvb_block_recent_limit', $edit['drupalvb_block_recent_limit']);
636 variable_set('drupalvb_block_recent_authors', $edit['drupalvb_block_recent_authors']);
637 }
638 else {
639 variable_set('drupalvb_block_'. $delta, $edit['drupalvb_block_'. $delta]);
640 }
641 }
642 else if ($op == 'view') {
643 module_load_include('inc', 'drupalvb');
644 $block = array();
645 if (!drupalvb_db_is_valid()) {
646 return $block;
647 }
648 switch ($delta) {
649 case 'recent':
650 $display = variable_get('drupalvb_block_recent_type', 'threads');
651 $block['subject'] = ($display == 'threads' ? t('Recent forum threads') : t('Recent forum posts'));
652 $block['content'] = drupalvb_block_recent($display);
653 return $block;
654
655 case 'recent_user':
656 if (arg(0) != 'user' && !is_numeric(arg(1))) {
657 return $block;
658 }
659 $account = user_load(array('uid' => arg(1)));
660 $block['subject'] = t('Recent forum posts by %name', array('%name' => $account->name));
661 $block['content'] = drupalvb_block_recent_user($account);
662 return $block;
663
664 case 'top_posters':
665 $block['subject'] = t('Top forum posters');
666 $block['content'] = drupalvb_block_top_posters();
667 return $block;
668
669 case 'user':
670 if (!user_access('access content') || $user->uid < 1) {
671 return $block;
672 }
673 $block['subject'] = t('Forum info');
674 $block['content'] = drupalvb_block_info();
675 return $block;
676
677 case 'stats':
678 $block['subject'] = t('Forum statistics');
679 $block['content'] = drupalvb_block_stats();
680 return $block;
681 }
682 }
683 }
684
685 /**
686 * Build data for recent threads/posts block.
687 *
688 * @param $display
689 * The type of data to display, 'threads' or 'posts'.
690 */
691 function drupalvb_block_recent($display) {
692 $date_cut = time() - (variable_get('drupalvb_block_recent_limit', 7) * 86400);
693 $num_items = variable_get('drupalvb_block_recent_count', 5);
694 $vb_options = drupalvb_get('options');
695 switch ($display) {
696 case 'threads':
697 $result = drupalvb_db_query("SELECT t.threadid, t.title, t.replycount, t.dateline AS created, t.postuserid AS userid, t.postusername AS name FROM {thread} t INNER JOIN {forum} f ON f.forumid = t.forumid WHERE f.showprivate = 0 AND t.lastpost >= %d ORDER BY t.dateline DESC LIMIT %d", $date_cut, $num_items);
698 break;
699
700 case 'posts':
701 $result = drupalvb_db_query("SELECT p.postid, p.title, p.threadid, p.dateline AS created, p.userid, p.username AS name, t.title AS threadtitle FROM {post} p LEFT JOIN {thread} t ON p.threadid = t.threadid WHERE p.dateline >= %d ORDER BY p.dateline DESC LIMIT %d", $date_cut, $num_items);
702 break;
703 }
704 $items = $userids = array();
705 while ($data = db_fetch_array($result)) {
706 if ($data['title'] == '') {
707 $data['title'] = t('Re:') .' '. $data['threadtitle'];
708 }
709 $data['title'] = decode_entities($data['title']);
710 $data['url'] = $vb_options['bburl'] .'/showthread.php';
711 $data['query'] = 't='. $data['threadid'];
712 $data['fragment'] = (isset($data['postid']) ? $data['postid'] : NULL);
713 $items[] = $data;
714 // Store mapping of vB userids.
715 if (!isset($userids[$data['userid']])) {
716 $userids[$data['userid']] = array();
717 }
718 $userids[$data['userid']][] = count($items) - 1;
719 }
720
721 // Try to find matching Drupal uids. These might not exist yet,
722 // theme_drupalvb_username() takes care of that.
723 if ($userids) {
724 $result = db_query("SELECT d.userid, d.uid, u.picture FROM {drupalvb_users} d INNER JOIN {users} u ON u.uid = d.uid WHERE d.userid IN (". implode(',', array_keys($userids)) .")");
725 while ($data = db_fetch_array($result)) {
726 foreach ($userids[$data['userid']] as $i) {
727 $items[$i] = array_merge($items[$i], $data);
728 }
729 }
730 }
731 return theme('drupalvb_block_recent', $items, $vb_options);
732 }
733
734 /**
735 * Generate HTML for Recent threads/posts block.
736 *
737 * @todo Unused $recent['replycount'] for threads.
738 */
739 function theme_drupalvb_block_recent($recent, $vb_options) {
740 $items = array();
741 $display_authors = variable_get('drupalvb_block_recent_authors', 0);
742 foreach ($recent as $item) {
743 $link = l($item['title'], $item['url'], array('query' => $item['query'], 'fragment' => $item['fragment']));
744 $items[] = ($display_authors ? t('!title <span>by !name</span>', array('!title' => $link, '!name' => theme('drupalvb_username', (object)$item))) : $link);
745 }
746 $output = theme('item_list', $items);
747 $output .= '<div class="forum-link">'. l(t('Visit the forum'), $vb_options['bburl']) .'</div>';
748 return $output;
749 }
750
751 /**
752 * Build data for recent posts by user block.
753 */
754 function drupalvb_block_recent_user($account) {
755 if ($vbuserid = db_result(db_query("SELECT userid FROM {drupalvb_users} WHERE uid = %d", $account->uid))) {
756 $num_items = variable_get('drupalvb_block_recent_count', 5);
757 $vb_options = drupalvb_get('options');
758 $result = drupalvb_db_query("SELECT p.postid, p.title, p.threadid, p.dateline AS created, p.userid, p.username AS name, t.title AS threadtitle, p.pagetext AS body FROM {post} p INNER JOIN {thread} t ON p.threadid = t.threadid INNER JOIN {forum} f ON f.forumid = t.forumid WHERE f.showprivate = 0 AND p.userid = %d GROUP BY p.threadid ORDER BY p.dateline DESC LIMIT %d", $vbuserid, $num_items);
759 $items = array();
760 while ($data = db_fetch_array($result)) {
761 if ($data['title'] == '') {
762 // $data['title'] = t('Re:') .' '. $data['threadtitle'];
763 $data['body'] = preg_replace('@\[ [^\]]+ \]@x', '', $data['body']);
764 $data['title'] = truncate_utf8($data['body'], 80);
765 }
766 $data['title'] = decode_entities($data['title']);
767 $data['threadtitle'] = decode_entities($data['threadtitle']);
768 $data['url'] = $vb_options['bburl'] .'/showthread.php';
769 $data['query'] = 't='. $data['threadid'];
770 $data['fragment'] = (isset($data['postid']) ? $data['postid'] : NULL);
771 $items[$data['postid']] = $data;
772 }
773 return theme('drupalvb_block_recent_user', $items, $vb_options);
774 }
775 }
776
777 /**
778 * Generate HTML for Recent threads/posts block.
779 *
780 * @todo Unused $recent['replycount'] for threads.
781 */
782 function theme_drupalvb_block_recent_user($recent, $vb_options) {
783 $items = array();
784 foreach ($recent as $item) {
785 $link_post = l($item['title'], $item['url'], array('query' => $item['query'], 'fragment' => $item['fragment']));
786 $link_thread = l($item['threadtitle'], $item['url'], array('query' => $item['query']));
787 $items[] = t('<span class="drupalvb-post">!title</span> <span class="drupalvb-thread">Thread: !thread</span>', array('!title' => $link_post, '!thread' => $link_thread));
788 }
789 return theme('item_list', $items);
790 }
791
792 /**
793 * Generate a block containing top form posters.
794 */
795 function drupalvb_block_top_posters() {
796 $items = array();
797 $num_items = variable_get('drupalvb_block_recent_count', 5);
798 $result = drupalvb_db_query_range("SELECT posts AS count, userid, username AS name FROM {user} ORDER BY posts DESC", 0, $num_items);
799 while ($data = db_fetch_array($result)) {
800 $items[$data['userid']] = $data;
801 }
802
803 $result = db_query("SELECT d.userid, d.uid, u.picture FROM {drupalvb_users} d INNER JOIN {users} u ON u.uid = d.uid WHERE d.userid IN (". implode(',', array_keys($items)) .")");
804 while ($data = db_fetch_array($result)) {
805 $items[$data['userid']] = array_merge($items[$data['userid']], $data);
806 }
807 return theme('drupalvb_block_top_posters', $items);
808 }
809
810 /**
811 * Render top forum posters block.
812 *
813 * @param $items
814 * An array of users.
815 */
816 function theme_drupalvb_block_top_posters($items) {
817 foreach ($items as $key => $item) {
818 $items[$key] = theme('drupalvb_username', (object)$item, 'custom_toplist_posts') .' <span class="count">'. format_plural($item['count'], 'wrote <span>1 post</span>', 'wrote <span>@count posts</span>') .'</span>';
819 }
820 return theme('item_list', $items);
821 }
822
823 /**
824 * Build contents for the forum user info block.
825 */
826 function drupalvb_block_info() {
827 global $user;
828
829 $vb_options = drupalvb_get('options');
830 $display = variable_get('drupalvb_block_user', drupal_map_assoc(array('online', 'recent', 'newposts', 'pms')));
831 $header = array(array(
832 'data' => l($vb_options['bbtitle'], $vb_options['bburl']),
833 'colspan' => 2,
834 ));
835 $rows = array();
836 if ($display['newposts']) {
837 $rows[] = array(
838 l(t('New posts'), $vb_options['bburl'] .'/search.php?do=getnew'),
839 drupalvb_get_recent_posts(),
840 );
841 }
842 if ($display['recent']) {
843 $rows[] = array(
844 l(t('Recent posts'), $vb_options['bburl'] .'/search.php?do=getdaily'),
845 drupalvb_get_recent_posts('daily'),
846 );
847 }
848 if ($display['online']) {
849 $users_online = drupalvb_get_users_online();
850 $rows[] = array(
851 l(t('Users online'), $vb_options['bburl'] .'/online.php'),
852 $users_online['guests'] + $users_online['members'],
853 );
854 }
855 if ($display['pms']) {
856 $vbuser = db_fetch_array(drupalvb_db_query("SELECT pmtotal, pmunread FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($user->name)));
857 $rows[] = array(
858 l(t('New private messages'), 'drupalvb/pms'),
859 (int)$vbuser['pmunread'],
860 );
861 }
862 return theme('table', $header, $rows);
863 }
864
865 /**
866 * Build contents for the forum statistics block.
867 */
868 function drupalvb_block_stats() {
869 // Get total threads & posts.
870 $totalthreads = $totalposts = 0;
871 $result = drupalvb_db_query("SELECT forumid, title, threadcount, replycount FROM {forum}");
872 while ($forum = db_fetch_array($result)) {
873 $totalthreads += $forum['threadcount'];
874 $totalposts += $forum['replycount'];
875 }
876 // Get user statistics.
877 $result = drupalvb_db_query("SELECT data FROM {datastore} WHERE title = 'userstats'");
878 $data = db_fetch_array($result);
879 $userstats = unserialize($data['data']);
880 $display = variable_get('drupalvb_block_stats', array('threads' => '1', 'posts' => '1', 'tmembers' => '1', 'amembers' => '1'));
881
882 $rows = array();
883 if ($display['posts']) {
884 $rows[] = array(t('Total Posts:'), $totalposts);
885 }
886 if ($display['threads']) {
887 $rows[] = array(t('Total Threads:'), $totalthreads);
888 }
889 if ($display['tmembers']) {
890 $rows[] = array(t('Total Members:'), $userstats['numbermembers']);
891 }
892 if ($display['amembers']) {
893 $rows[] = array(t('Active Members:'), $userstats['activemembers']);
894 }
895 return theme('table', array(), $rows);
896 }
897
898 /**
899 * Formats a Drupal or vBulletin username.
900 *
901 * @param $object
902 * The user object to format. Should contain either a vBulletin userid, or
903 * a Drupal uid, if available.
904 * @param $class
905 * A class name for User Display API.
906 */
907 function theme_drupalvb_username($object, $class = NULL) {
908 if ($object && !empty($object->uid) && $object->name) {
909 // Drupal account exists: fall back on default theming.
910 $output = theme('username', $object, $class);
911 }
912 else if ($object && !empty($object->userid) && $object->name) {
913 // Remove any html entities injected by vBulletin.
914 $object->name = decode_entities($object->name);
915 // Drupal account doesn't exists yet. Link to it using our redirector,
916 // which will create the account on the fly.
917 if (drupal_strlen($object->name) > 20) {
918 $name = drupal_substr($object->name, 0, 15) .'...';
919 }
920 else {
921 $name = $object->name;
922 }
923 if (user_access('access user profiles')) {
924 $output = l($name, 'drupalvb/user/'. $object->userid, array('title' => t('View user profile.')));
925 }
926 else {
927 $output = check_plain($name);
928 }
929 }
930 else {
931 $output = variable_get('anonymous', t('Anonymous'));
932 }
933 return $output;
934 }
935
936 /**
937 * Render a page containing (vB) private messages of a user.
938 */
939 function drupalvb_private_messages() {
940 global $user;
941 module_load_include('inc', 'drupalvb');
942
943 $vb_options = drupalvb_get('options');
944
945 $output = '<p>'. t("Below is a list of private messages you have received. You may click on a user's name to see their profile, a message's title to view it, or a reply link to message the user in return.") .'</p>';
946 $output .= l('View your inbox.', $vb_options['bburl'] .'/private.php');
947
948 $result = drupalvb_db_query("SELECT userid, username FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($user->name));
949
950 // If user exists, then grab and display a list of PMs.
951 if ($userinfo = db_fetch_array($result)) {
952 // Format a table with the results.
953 $header = array(
954 array('data' => t('From'), 'width' => '75'),
955 array('data' => t('Message Title'), 'width' => '150'),
956 array('data' => t('Received'), 'width' => '145'),
957 array('data' => t('Read?'), 'width' => '30'),
958 array('data' => t('Operations')),
959 );
960
961 $result = drupalvb_db_query("SELECT pm.pmid, pm.userid, pm.messageread, pmtext.fromusername, pmtext.fromuserid, pmtext.title, pmtext.message, pmtext.dateline FROM {pmtext} AS pmtext LEFT JOIN {pm} AS pm ON (pm.pmtextid = pmtext.pmtextid) WHERE pm.userid = %d AND pm.folderid <> -1 ORDER BY pmtext.dateline DESC", $userinfo['userid']);
962 while ($pm = db_fetch_array($result)) {
963 $rows[] = array(
964 l($pm['fromusername'], $vb_options['bburl'] .'/member.php?u='. $pm['fromuserid']),
965 l($pm['title'], $vb_options['bburl'] .'/private.php?do=showpm&pmid='. $pm['pmid']),
966 date('n-d-y g:i a', $pm['dateline']),
967 $pm['messageread'] ? t('Yes') : '<strong>'. t('No') .'</strong>',
968 l('reply', $vb_options['bburl'] .'/private.php?do=newpm&u='. $pm['fromuserid']),
969 );
970 }
971 $output .= theme('table', $header, $rows);
972 }
973 // Deny access to a user not logged in.
974 else {
975 $output = t('You need to login to see your private messages.');
976 }
977 return $output;
978 }
979
980 /**
981 * Redirector for Drupal paths containing vBulletin userids.
982 *
983 * This function is useful when changing paths in vBulletin to point to Drupal
984 * module paths. For example, if you want to use the Buddylist module instead
985 * of vBulletin's buddy feature, change the link in template MEMBERINFO to
986 * <code>/drupalvb/buddy/add/$userinfo[userid]</code>.
987 * The function looks up the corresponding Drupal user and exchanges the
988 * userid, and redirects the user to the new path.
989 *
990 * @param ...
991 * A Drupal path. Numeric path arguments will be mapped to Drupal uids.
992 */
993 function drupalvb_redirect() {
994 // Keep script running even if a request was terminated to ensure user
995 // table integrity.
996 ignore_user_abort(TRUE);
997
998 $path = func_get_args();
999 foreach ($path as $key => $arg) {
1000 if (is_numeric($arg) && ($uid = drupalvb_lookup_drupal_user($arg))) {
1001 $path[$key] = $uid;
1002 }
1003 }
1004
1005 // Issue a 301 Moved Permanently response code to make search engines
1006 // forget about the redirector page.
1007 drupal_goto(implode('/', $path), NULL, NULL, 301);
1008 }
1009
1010 /**
1011 * Lookup the corresponding Drupal uid for a vBulletin userid.
1012 *
1013 * If the vBulletin userid is valid, then a temporary Drupal user will be
1014 * created and it's uid returned.
1015 *
1016 * @param $userid
1017 * A vBulletin user id.
1018 * @return
1019 * The corresponding Drupal uid, if the vBulletin userid could be validated.
1020 */
1021 function drupalvb_lookup_drupal_user($userid) {
1022 module_load_include('inc', 'drupalvb');
1023
1024 // Check if this vBulletin user id already exists as Drupal user.
1025 if ($uid = drupalvb_user_load($userid)) {
1026 return $uid;
1027 }
1028
1029 // Try to lookup the user id in the vBulletin database.
1030 if ($vbuser = db_fetch_array(drupalvb_db_query("SELECT userid, username, email, joindate FROM {user} WHERE userid = %d", $userid))) {
1031 // Register this user in Drupal using a temporary password, since we don't
1032 // know the real one. It will be updated when the user logs in to Drupal
1033 // for the first time using its vBulletin credentials.
1034 // @see drupalvb_login_validate()
1035 $userinfo = array(
1036 'name' => $vbuser['username'],
1037 'pass' => user_password(),
1038 'mail' => $vbuser['email'],
1039 'init' => $vbuser['username'],
1040 'created' => $vbuser['joindate'],
1041 'status' => 1,
1042 );
1043 $user = user_save('', $userinfo);
1044
1045 // On a heavy Drupal installation, it can happen that when a user accidently
1046 // double-clicks on a redirector link we run into a timing problem:
1047 // while the first request is in the middle of registering the Drupal account,
1048 // the immediate second request tries to do the same again, resulting
1049 // in an error.
1050 if ($user->uid) {
1051 watchdog('drupalvb', t('New external user: %user (unverified).', array('%user' => $user->name)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
1052
1053 // Update the mapping table.
1054 drupalvb_set_mapping($user->uid, $vbuser['userid']);
1055
1056 return $user->uid;
1057 }
1058 // In case the user couldn't be registered, try to load it from the database.
1059 else if ($uid = drupalvb_user_load($vbuser['userid'])) {
1060 return $uid;
1061 }
1062 // We're out of luck...
1063 else {
1064 watchdog('drupalvb', t('Failed to create external user: %user (unverified).', array('%user' => $vbuser['username'])), WATCHDOG_ERROR);
1065 }
1066 }
1067 return 0;
1068 }
1069
1070 /**
1071 * Implementation of hook_privatemsg().
1072 *
1073 * This hack requires re-mapping of all requests for /forum/private.php to
1074 * privatemsg paths using .htaccess rewrite rules. Plus, it messes around with
1075 * vBulletin's pm table, which means you can't easily switch back (you have to
1076 * reset that table to be able to do that).
1077 *
1078 * Note: message id is set to privatemsg->id + 100.000 to avoid collision with
1079 * existing messages.
1080 */
1081 function drupalvb_privatemsg($message, $op) {
1082 module_load_include('inc', 'drupalvb');
1083 if (!(variable_get('drupalvb_pm_sync', FALSE) && drupalvb_db_is_valid())) {
1084 return;
1085 }
1086
1087 // Shift message id to avoid overwriting existing messages.
1088 $mid = $message->id + 100000;
1089
1090 switch ($op) {
1091 case 'sent':
1092 // Verify that recipient exists in vB.
1093 $recipient = user_load(array('uid' => $message->recipient));
1094 if (!$userid = db_result(drupalvb_db_query_range("SELECT userid FROM {user} WHERE username = '%s'", drupalvb_htmlspecialchars($recipient->name), 0, 1))) {
1095 if (!$userid = drupalvb_create_user($recipient, (array)$recipient)) {
1096 // Indicates duplicate username (should not happen).
1097 return;
1098 }
1099 }
1100 // pmtextid stores mapping of privatemsg id to pmid, to be able to
1101 // display accurate message counts in vBulletin.
1102 drupalvb_db_query("INSERT INTO {pm} (userid, pmtextid) VALUES (%d, %d)", $userid, $mid);
1103 break;
1104
1105 case 'view':
1106 // Mark as read in vBulletin.
1107 drupalvb_db_query("UPDATE {pm} SET messageread = 0 WHERE pmtextid = %d", $mid);
1108 break;
1109
1110 case 'prune':
1111 case 'delete':
1112 // Delete in vBulletin.
1113 drupalvb_db_query("DELETE FROM {pm} WHERE pmtextid = %d", $mid);
1114 break;
1115 }
1116 }
1117

  ViewVC Help
Powered by ViewVC 1.1.2