boinccore_form_alter()   F
last analyzed

Complexity

Conditions 18
Paths 72

Size

Total Lines 179
Code Lines 115

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 115
nc 72
nop 3
dl 0
loc 179
rs 3.8933
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// $Id$
3
4
/**
5
 * @file
6
 * Provides common BOINC module functionality.
7
 *
8
 * In general, any custom feature or function required independently by
9
 * multiple BOINC modules should be in this module.
10
 */
11
12
13
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
14
 * Includes that provide supporting functions
15
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
16
17
//require_once('includes/boinccore.forms.inc');
18
//require_once('includes/boinccore.helpers.inc');
19
require_once('includes/boinccore.rules.inc');
20
require_once('boinccore.admin.inc');
21
22
23
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
24
 * Hooks into core modules
25
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
26
27
/**
28
 * Implementation of hook_menu(); determine the actions that correspond
29
 * with defined URL paths
30
 */
31
function boinccore_menu() {
32
  $items['node_control'] = array(
33
    'page callback' => 'boinccore_node_control',
34
    'access arguments' => array('access content'),
35
    'type' => MENU_CALLBACK
36
  );
37
  $items['comment_control'] = array(
38
    'page callback' => 'boinccore_comment_control',
39
    'access arguments' => array('administer comments'),
40
    'type' => MENU_CALLBACK
41
  );
42
  $items['goto'] = array(
43
    'page callback' => 'boinccore_url_pagination_handler',
44
    'access arguments' => array('access content'),
45
    'type' => MENU_CALLBACK
46
  );
47
  $items['admin/boinc/community'] = array(
48
    'title' => 'Community',
49
    'description' => 'Global settings for community interaction.',
50
    'page callback' => 'drupal_get_form',
51
    'page arguments' => array('boinccore_admin_community'),
52
    'access arguments' => array('administer site configuration'),
53
    'type' => MENU_NORMAL_ITEM,
54
    'file' => 'boinccore.admin.inc'
55
  );
56
  $items['admin/boinc/standard-content-generator'] = array(
57
    'title' => 'Standard page generator',
58
    'description' => 'Regenerate standard site content (e.g. Help and About Us
59
      pages).',
60
    'page callback' => 'drupal_get_form',
61
    'page arguments' => array('boinccore_admin_default_content'),
62
    'access arguments' => array('administer site configuration'),
63
    'type' => MENU_NORMAL_ITEM,
64
    'file' => 'boinccore.admin.inc'
65
  );
66
67
  // BOINC RPC wrappers
68
  $items['lookup_account.php'] = array(
69
    'title' => 'Look up account RPC',
70
    'description' => 'RPC for getting the authenticator for a user account.',
71
    'page callback' => 'boinccore_lookup_account',
72
    'access callback' => TRUE,
73
    'type' => MENU_CALLBACK
74
  );
75
  $items['am_get_info.php'] = array(
76
    'title' => 'Account manager get info RPC',
77
    'description' => 'RPC for getting assorted details of a user account.',
78
    'page callback' => 'boinccore_am_get_info',
79
    'access callback' => TRUE,
80
    'type' => MENU_CALLBACK
81
  );
82
  $items['am_set_info.php'] = array(
83
    'title' => 'Account manager set info RPC',
84
    'description' => 'RPC for updating assorted details of a user account.',
85
    'page callback' => 'boinccore_am_set_info',
86
    'access callback' => TRUE,
87
    'type' => MENU_CALLBACK
88
  );
89
  $items['am_set_host_info.php'] = array(
90
    'title' => 'Account manager set host info RPC',
91
    'description' => 'RPC for updating the venue for a given host.',
92
    'page callback' => 'boinccore_am_set_host_info',
93
    'access callback' => TRUE,
94
    'type' => MENU_CALLBACK
95
  );
96
  $items['show_user.php'] = array(
97
    'title' => 'Show user RPC',
98
    'description' => 'RPC for getting assorted details of a user account.',
99
    'page callback' => 'boinccore_show_user',
100
    'access callback' => TRUE,
101
    'type' => MENU_CALLBACK
102
  );
103
  $items['pending.php'] = array(
104
    'title' => 'Pending credit RPC',
105
    'description' => 'RPC for getting pending credit for a given account.',
106
    'page callback' => 'boinccore_pending_credit',
107
    'access callback' => TRUE,
108
    'type' => MENU_CALLBACK
109
  );
110
  $items['create_team.php'] = array(
111
    'title' => 'Create team RPC',
112
    'description' => 'RPC for creating a new team.',
113
    'page callback' => 'boinccore_create_team',
114
    'access callback' => TRUE,
115
    'type' => MENU_CALLBACK
116
  );
117
  $items['team_lookup.php'] = array(
118
    'title' => 'Team lookup RPC',
119
    'description' => 'RPC for getting info on a team or matching teams.',
120
    'page callback' => 'boinccore_team_lookup',
121
    'access callback' => TRUE,
122
    'type' => MENU_CALLBACK
123
  );
124
  $items['team_email_list.php'] = array(
125
    'title' => 'Get team member list RPC',
126
    'description' => 'RPC for getting a list of members of a given team.',
127
    'page callback' => 'boinccore_team_email_list',
128
    'access callback' => TRUE,
129
    'type' => MENU_CALLBACK
130
  );
131
  $items['edit_forum_preferences_action.php'] = array(
132
    'title' => 'Forum preferences RPC',
133
    'description' => 'RPC for setting forum preferences for a given user.',
134
    'page callback' => 'boinccore_edit_forum_preferences',
135
    'access callback' => TRUE,
136
    'type' => MENU_CALLBACK
137
  );
138
  $items['forum_get_data.php'] = array(
139
    'title' => 'Forum get data RPC',
140
    'description' => 'RPC for getting recent forum activity for a given user.',
141
    'page callback' => 'boinccore_forum_get_data',
142
    'access callback' => TRUE,
143
    'type' => MENU_CALLBACK
144
  );
145
  $items['apps.php'] = array(
146
    'title' => 'Apps RPC',
147
    'description' => 'RPC for getting the applications in the system.',
148
    'page callback' => 'boinccore_apps',
149
    'access callback' => TRUE,
150
    'type' => MENU_CALLBACK
151
  );
152
153
  return $items;
154
}
155
156
/**
157
 * Implementation of hook_menu_alter()
158
 */
159
function boinccore_menu_alter(&$items) {
160
  // If using Solr search and not core Drupal search, disable core search!
161
  if (module_exists('global_search_solr') AND !module_exists('global_search')) {
162
    // Add permission to user search.
163
    $check = array(
164
      'search/node/%menu_tail',
165
      'search/user/%menu_tail',
166
      'user/autocomplete'
167
    );
168
    foreach ($check as $path) {
169
      if (isset($items[$path])) {
170
        $items[$path]['access callback'] = FALSE;
171
      }
172
    }
173
  }
174
  // If using content profile module (for user profiles) setup special
175
  // delete page.
176
  if (module_exists('content_profile')) {
177
    $items['node/%node/delete'] = array(
178
      'title' => 'Delete',
179
      'page callback' => 'drupal_get_form',
180
      'page arguments' => array('boinccore_delete_confirm', 1),
181
      'access callback' => 'node_access',
182
      'access arguments' => array('delete', 1),
183
      'module' => 'boinccore',
184
      'file' => 'includes/boinccore.forms.inc',
185
      'weight' => 1,
186
      'type' => MENU_CALLBACK,
187
    );
188
  }
189
190
  // 'Remove' menu paths for ignore_user and privatemsg
191
  // (pm_block_user) module which we have 'overridden' with
192
  // boincwork's own functions.
193
  if (module_exists('ignore_user')) {
194
    $check = array(
195
      'ignore_user/add',
196
      'ignore_user/remove',
197
    );
198
    foreach ($check as $path) {
199
      if (isset($items[$path])) {
200
        $items[$path]['access callback'] = FALSE;
201
      }
202
    }
203
204
    // Redirect user to privacy prefs page.
205
    $path1 = 'ignore_user/list';
206
    if (isset($items[$path1])) {
207
      $items[$path1]['page callback'] = 'drupal_goto';
208
      $items[$path1]['page arguments'] = array('account/prefs/privacy');
209
    }
210
  }
211
212
  if (module_exists('pm_block_user')) {
213
    $check = array(
214
      'messages/block/%user',
215
    );
216
    foreach ($check as $path) {
217
      if (isset($items[$path])) {
218
        $items[$path]['access callback'] = FALSE;
219
      }
220
    }
221
  }
222
}
223
224
/**
225
 * Implementation of hook_enable()
226
 */
227
function boinccore_enable() {
228
  // Automatically try to establish standard site content when this module is
229
  // enabled (e.g. Help and About Us pages)
230
  boinccore_admin_default_content_generate();
231
}
232
233
/**
234
 * Implementation of hook_boot()
235
 * Caching for anonymous users in Drupal 6 is not language specific, so using
236
 * the browser language without path prefix can result in mixed languages being
237
 * present in the cache for pages with the default (no language given) path.
238
 * As a workaround, redirect anonymous users to a language prefix if they are
239
 * on the default site path and the browser reports a non-default language.
240
 * See: https://www.drupal.org/node/339958#comment-3012662
241
 */
242
function boinccore_boot() {
243
  global $user, $language;
244
  $cache = variable_get('cache', CACHE_DISABLED);
245
  $language_negotiation = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
246
247
  // If we have an anonymous user, page cache is enabled, the URL has no prefix
248
  // and browser language negotiation is set, we perform a redirect to the
249
  // prefixed URL.
250
  if (empty($user->uid) && $cache != CACHE_DISABLED && $language_negotiation == LANGUAGE_NEGOTIATION_PATH) {
251
    $args = isset($_GET['q']) ? explode('/', $_GET['q']) : array();
252
    $prefix = array_shift($args);
253
254
    // Initialize language as we need the proper language negotiation to be
255
    // performed.
256
    drupal_bootstrap(DRUPAL_BOOTSTRAP_LANGUAGE);
257
258
    // But Drupal 6 language negotiation does not always work that well...
259
    // so call this backported Drupal 7 language negotation function, which
260
    // does both case insensitive and longest prefix matching
261
    if (function_exists('locale_language_from_browser')) {
262
      $language = locale_language_from_browser();
263
    }
264
265
    if (!empty($language->prefix) && $prefix != $language->prefix) {
266
      // We need full path support to perform the redirect.
267
      drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);
268
269
      require_once './includes/common.inc';
270
      $url = url($_GET['q'], array('query' => drupal_query_string_encode($_GET, array('q'))));
271
      $code = variable_get('locale_redirect_http_code', 302);
272
273
      // Since we are in a hook_boot() implementation cache mode is normal, so
274
      // we can safely call hook_exit().
275
      bootstrap_invoke_all('exit');
276
      header("Location: $url", TRUE, $code);
277
      exit;
278
    }
279
  }
280
}
281
282
283
if (!function_exists('locale_language_from_browser')) {
284
/**
285
 * Backport of locale_language_from_browser from Drupal 7
286
 *
287
 * The language_from_browser() function in Drupal 6 does not match the browser
288
 * language preference case-insensitively or by longest prefix
289
 *
290
 * Obsolete in Drupal 7...
291
 */
292
  function locale_language_from_browser() {
293
    if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
294
      return FALSE;
295
    }
296
297
    $languages = language_list('enabled');
298
    $languages = $languages[1];
299
300
    // The Accept-Language header contains information about the language
301
    // preferences configured in the user's browser / operating system.
302
    // RFC 2616 (section 14.4) defines the Accept-Language header as follows:
303
    //   Accept-Language = "Accept-Language" ":"
304
    //                  1#( language-range [ ";" "q" "=" qvalue ] )
305
    //   language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
306
    // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5"
307
    $browser_langcodes = array();
308
    if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']), $matches, PREG_SET_ORDER)) {
309
      foreach ($matches as $match) {
310
        // We can safely use strtolower() here, tags are ASCII.
311
        // RFC2616 mandates that the decimal part is no more than three digits,
312
        // so we multiply the qvalue by 1000 to avoid floating point comparisons.
313
        $langcode = strtolower($match[1]);
314
        $qvalue = isset($match[2]) ? (float) $match[2] : 1;
315
        $browser_langcodes[$langcode] = (int) ($qvalue * 1000);
316
      }
317
    }
318
319
    // We should take pristine values from the HTTP headers, but Internet Explorer
320
    // from version 7 sends only specific language tags (eg. fr-CA) without the
321
    // corresponding generic tag (fr) unless explicitly configured. In that case,
322
    // we assume that the lowest value of the specific tags is the value of the
323
    // generic language to be as close to the HTTP 1.1 spec as possible.
324
    // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 and
325
    // http://blogs.msdn.com/b/ie/archive/2006/10/17/accept-language-header-for-internet-explorer-7.aspx
326
    asort($browser_langcodes);
327
    foreach ($browser_langcodes as $langcode => $qvalue) {
328
      $generic_tag = strtok($langcode, '-');
329
      if (!isset($browser_langcodes[$generic_tag])) {
330
        $browser_langcodes[$generic_tag] = $qvalue;
331
      }
332
    }
333
334
    // Find the enabled language with the greatest qvalue, following the rules
335
    // of RFC 2616 (section 14.4). If several languages have the same qvalue,
336
    // prefer the one with the greatest weight.
337
    $best_match_language = FALSE;
338
    $max_qvalue = 0;
339
    foreach ($languages as $langcode => $language) {
340
      // Language tags are case insensitive (RFC2616, sec 3.10).
341
      $langcode = strtolower($langcode);
342
343
      // If nothing matches below, the default qvalue is the one of the wildcard
344
      // language, if set, or is 0 (which will never match).
345
      $qvalue = isset($browser_langcodes['*']) ? $browser_langcodes['*'] : 0;
346
347
      // Find the longest possible prefix of the browser-supplied language
348
      // ('the language-range') that matches this site language ('the language tag').
349
      $prefix = $langcode;
350
      do {
351
        if (isset($browser_langcodes[$prefix])) {
352
          $qvalue = $browser_langcodes[$prefix];
353
          break;
354
        }
355
      }
356
       while ($prefix = substr($prefix, 0, strrpos($prefix, '-')));
357
358
      // Find the best match.
359
      if ($qvalue > $max_qvalue) {
360
        $best_match_language = $language;
361
        $max_qvalue = $qvalue;
362
      }
363
    }
364
365
    return $best_match_language;
366
  }
367
}
368
369
/**
370
 * Implementation of hook_cron()
371
 */
372
function boinccore_cron() {
373
  // Notify moderators if there is site content that requires moderator action
374
  $items_in_queue = boincuser_moderation_queue_count('cron');
375
  $last_notification = variable_get('boinccore_last_content_moderation_reminder', 0);
376
  if ($items_in_queue AND $last_notification < time() - 24*60*60) {
377
    global $base_url;
378
    global $base_path;
379
    $site_name = variable_get('site_name', 'Drupal-BOINC');
380
    $site_url = $base_url . $base_path;
381
    $settings = array(
382
      'from' => '',
383
      'subject' => "Content at {$site_name} is awaiting moderation",
384
      'message' => ''
385
      . "Please visit the moderation queue page to review content that "
386
      . "requires moderator action: \n"
387
      . "\n"
388
      . "{$site_url}moderate",
389
    );
390
    boinccore_rules_action_mail_to_moderators($settings);
391
    variable_set('boinccore_last_content_moderation_reminder', time());
392
  }
393
394
  // Delete expired tokens in BOINC DB
395
  _boinccore_delete_expired_tokens();
396
}
397
398
/**
399
 * Implementation of hook_rules_action_info().
400
 */
401
function boinccore_rules_action_info() {
402
  return array(
403
    'boinccore_rules_action_mail_to_moderators' => array(
404
      'label' => t('Notify moderators via email'),
405
      'module' => 'BOINC core',
406
      'eval input' => array('subject', 'message', 'from'),
407
    ),
408
    'boinccore_rules_action_mark_content_for_moderation' => array(
409
      'label' => t('Mark content for moderation'),
410
      'arguments' => array(
411
        'node' => array('type' => 'node', 'label' => t('Content')),
412
      ),
413
      'module' => 'BOINC core',
414
    ),
415
    'boinccore_rules_action_mail_to_admins' => array(
416
      'label' => t('Notify admins via email'),
417
      'module' => 'BOINC core',
418
      'eval input' => array('subject', 'message', 'from'),
419
    ),
420
  );
421
}
422
423
/**
424
 * Implementation of hook_form_alter()
425
 */
426
function boinccore_form_alter(&$form, $form_state, $form_id) {
427
  global $user;
428
  $account = user_load($user->uid);
429
  switch ($form_id) {
430
  // Comment form
431
  case 'comment_form':
432
    $user_image = boincuser_get_user_profile_image($user->uid);
433
    $user_info = '<div class="user">';
434
    if ($user_image) {
435
      $user_info .= '  <div class="picture">';
436
      if (is_array($user_image) AND $user_image['image']['filepath']) {
437
        $user_info .= theme('imagefield_image', $user_image['image'], $user_image['alt'], $user_image['alt'], array(), false);
438
      }
439
      elseif (is_string($user_image)) {
440
        $user_info .= '<img src="' . $user_image . '"/>';
441
      }
442
      $user_info .= '  </div>';
443
    }
444
    $user_info .= '  <div class="name">' . theme('username', $account) . '</div>';
445
    if ($account->uid) {
446
      //$user_info .= '  <div class="join-date">Joined: ' . date('j M y', $account->created) . '</div>';
447
      //$user_info .= '  <div class="post-count">Posts: ' . $account->post_count . '</div>';
448
      //$user_info .= '  <div class="credit">Credit: ' . $account->boincuser_total_credit . '</div>';
449
      //$user_info .= '  <div class="rac">RAC: ' . $account->boincuser_expavg_credit . '</div>';
450
    }
451
    $user_info .= '</div>';
452
    array_unshift($form, array(
453
      'user_info' => array(
454
        '#value' => $user_info,
455
      ),
456
      'comment_form_prefix' => array(
457
        '#value' => '<div class="form-body">',
458
      ),
459
    ));
460
    $form['comment_form_suffix'] = array(
461
      '#value' => '</div>',
462
    );
463
464
    module_load_include('inc', 'bbcode', 'bbcode-help');
465
    $form['bbcode_help'] = array(
466
      '#title' => bts('BBcode help', array(), NULL, 'boinc:help-with-user-input-with-BBCode'),
467
      '#type' => 'fieldset',
468
      '#attributes' => array(
469
        'class' => 'bbcode_help',
470
      ),
471
      '#collapsible' => TRUE,
472
      '#collapsed' => TRUE,
473
      'content' => array(
474
        '#value' => _bbcode_filter_tip(),
475
      ),
476
    );
477
478
    // If a specific comment is being referenced, go back to it on cancel
479
    if ($comment_ref = $form['pid']['#value']) {
480
      $cancel_url = "goto/comment/{$comment_ref}";
481
    }
482
    else {
483
      $cancel_url = "node/{$form['nid']['#value']}";
484
    }
485
486
    // Wrap action buttons for styling consistency
487
    $form['buttons']['form control tabs prefix'] = array(
488
      '#value' => '<ul class="form-control tab-list">',
489
      '#weight' => 1001,
490
    );
491
    $form['buttons']['submit'] = $form['submit'];
492
    unset($form['submit']);
493
    $form['buttons']['submit']['#prefix'] = '<li class="first tab">';
494
    $form['buttons']['submit']['#value'] = bts('Post comment', array(), NULL, 'boinc:post-forum-comment');
495
    $form['buttons']['submit']['#suffix'] = '</li>';
496
    $form['buttons']['submit']['#weight'] = 1002;
497
    // We want all these buttons together under the "buttons" array, but the
498
    // default submit and preview buttons cannot both be unset or odd display
499
    // bugs result. Somehow the comment form ends up above the preview div in
500
    // this case. So... don't unset the preview button, just hide it
501
    $form['buttons']['preview'] = $form['preview'];
502
    //unset($form['preview']);
503
    $form['preview']['#attributes']['style'] = 'display: none;';
504
    $form['buttons']['preview']['#prefix'] = '<li class="tab">';
505
    $form['buttons']['preview']['#suffix'] = '</li>';
506
    $form['buttons']['preview']['#weight'] = 1003;
507
    $form['buttons']['cancel'] = array(
508
      '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), $cancel_url) . '</li>',
509
      '#weight' => 1004,
510
    );
511
    $form['buttons']['form control tabs suffix'] = array(
512
      '#value' => '</ul>',
513
      '#weight' => 1010,
514
    );
515
516
    // Remove redundant name field
517
    unset($form['_author']);
518
519
    // If user is role='community member' only, then user may not post
520
    // any comments in non-forum node-types, team_forums are also not
521
    // allowed.. This allows users who have site-wide comment
522
    // permission to comment on forums in special
523
    // circumstances. Additionally, any comments require a captcha.
524
    //
525
    $node = node_load($form['nid']['#value']);
526
    $community_role = array_search('community member', user_roles(true));
527
    $unrestricted_role = array_search('verified contributor', user_roles(true));
528
    if ( (isset($account->roles[$community_role])) and (!isset($account->roles[$unrestricted_role])) ) {
529
      if ($node->type == 'forum') {
530
        if (module_exists('captcha')) {
531
          $form['comment_captcha'] = array(
532
            '#type' => 'captcha',
533
            '#weight' => 1000,
534
          );
535
        }
536
      }
537
      else {
538
        $form = NULL;
539
        $form['from'] = array(
540
          '#type'  => 'item',
541
          '#value' => 'You do not have permission to post comments in this forum.',
542
        );
543
      }
544
    }
545
546
    break;
547
548
  // Forum node form
549
  case 'forum_node_form':
550
  case 'team_forum_node_form':
551
    $forum_id = key($form['#node']->taxonomy);
552
    $form['buttons']['separator_bottom'] = array(
553
      '#value' => '<div class="separator buttons"></div>',
554
      '#weight' => 999,
555
    );
556
557
    // Wrap action buttons for styling consistency
558
    $form['buttons']['form control tabs prefix'] = array(
559
      '#value' => '<ul class="form-control tab-list">',
560
      '#weight' => 1001,
561
    );
562
    $form['buttons']['submit']['#prefix'] = '<li class="first tab">';
563
    $form['buttons']['submit']['#value'] = bts('Post topic', array(), NULL, 'boinc:post-forum-comment');
564
    $form['buttons']['submit']['#suffix'] = '</li>';
565
    $form['buttons']['submit']['#weight'] = 1002;
566
    $form['buttons']['preview']['#prefix'] = '<li class="tab">';
567
    $form['buttons']['preview']['#suffix'] = '</li>';
568
    $form['buttons']['preview']['#weight'] = 1003;
569
    $form['buttons']['preview_changes']['#prefix'] = '<li class="tab">';
570
    $form['buttons']['preview_changes']['#suffix'] = '</li>';
571
    $form['buttons']['preview_changes']['#weight'] = 1004;
572
    $form['buttons']['cancel'] = array(
573
      '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), "community/forum/{$forum_id}") . '</li>',
574
      '#weight' => 1005,
575
    );
576
    $form['buttons']['form control tabs suffix'] = array(
577
      '#value' => '</ul>',
578
      '#weight' => 1010,
579
    );
580
581
    // Add captcha for role='community member'
582
    $community_role = array_search('community member', user_roles(true));
583
    $unrestricted_role = array_search('verified contributor', user_roles(true));
584
    if ( (isset($account->roles[$community_role])) and (!isset($account->roles[$unrestricted_role])) ) {
585
      if (module_exists('captcha')) {
586
        $form['comment_captcha'] = array(
587
          '#type' => 'captcha',
588
          '#weight' => 1000,
589
        );
590
      }
591
    }
592
593
    break;
594
  case 'boinccore_delete_confirm':
595
    // Wrap action buttons for styling consistency
596
    $form['actions']['#prefix'] = '<ul class="form-control tab-list">';
597
    $form['actions']['#suffix'] = '</ul>';
598
599
    $form['actions']['submit']['#prefix'] = '<li class="first tab">';
600
    $form['actions']['submit']['#suffix'] = '</li>';
601
    $form['actions']['cancel']['#prefix'] = '<li class="tab">';
602
    $form['actions']['cancel']['#suffix'] = '</li>';
603
    break;
604
  default:
605
  }
606
}
607
608
/**
609
 * Implementation of hook_link_alter()
610
 */
611
function boinccore_link_alter(&$links, $node, $comment = NULL) {
612
  //echo '<pre>' . print_r($links, true) . '</pre>';
613
  foreach ($links as $module => $link) {
614
    // Remove the ignore user link
615
    if (strstr($module, 'ignore_user')) {
616
      unset($links[$module]);
617
    }
618
  }
619
  // Node first, then comment: to be consistent with boinccore_link() function
620
  if (!($comment)) {
621
    // modify the comment_add link
622
    if (isset($links['comment_add'])) {
623
      $links['comment_add']['title'] = bts('reply', array(), NULL, 'boinc:forum-reply-to-comment');
624
      $links['comment_add']['attributes'] = array(
625
          'title' => bts('Reply to this comment', array(), NULL, 'boinc:forum-reply-to-comment')
626
      );
627
    }
628
    // modify quote link
629
    if (isset($links['quote'])) {
630
      $links['quote']['attributes'] = array(
631
          'title' => bts('Reply to this topic with a quote', array(), NULL, 'boinc:forum-reply-to-comment')
632
      );
633
    }
634
  }
635
  else {
636
    // Standard EDIT, DELETE, and REPLY links are created by Drupal, but we want to alter them
637
    if (isset($links['comment_delete'])) {
638
      $links['comment_delete']['attributes'] = array(
639
          'title' => bts('Delete this comment', array(), NULL, 'boinc:forum-delete-comment')
640
      );
641
    }
642
    if (isset($links['comment_edit'])) {
643
      $links['comment_edit']['attributes'] = array(
644
          'title' => bts('Edit this comment', array(), NULL, 'boinc:forum-edit-comment')
645
      );
646
    }
647
    if (isset($links['comment_reply'])) {
648
      $links['comment_reply']['attributes'] = array(
649
          'title' => bts('Reply to this comment', array(), NULL, 'boinc:forum-reply-to-comment')
650
      );
651
    }
652
  }// if !$comment
653
}
654
655
/**
656
 * Implementation of hook_locale().
657
 */
658
function boinccore_locale($op = 'groups', $group = NULL) {
659
  switch ($op) {
660
    case 'groups':
661
        return array('boinc' => 'BOINC');
662
    case 'info':
663
      //$info['boinc']['refresh callback'] = 'boinccore_locale_refresh';
664
      $info['boinc']['format'] = FALSE;
665
      return $info;
666
  }
667
}
668
669
670
/**
671
 * Implementation of hook_link()
672
 */
673
function boinccore_link($type, $object, $teaser = FALSE) {
674
  // Add custom links with this hook
675
676
  if ($type=='node') {
677
    if ( ($object->type=='forum') OR ($object->type=='team_forum') ) {
678
      // Add topic moderator controls
679
      if (user_access('edit any forum topic')) {
680
        $node_control = "node_control/{$object->nid}";
681
        if ($object->sticky) {
682
          $links['make_unsticky'] = array(
683
              'title' => bts('Make unsticky', array(), NULL, 'boinc:forum-unsticky-comment'),
684
              'href' => "{$node_control}/unsticky",
685
              'attributes' => array(
686
                  'title' => bts('Remove sticky status from this topic', array(), NULL, 'boinc:forum-unsticky-comment')
687
              )
688
          );
689
        }
690
        else {
691
          $links['make_sticky'] = array(
692
              'title' => bts('Make sticky', array(), NULL, 'boinc:forum-sticky-comment'),
693
              'href' => "{$node_control}/sticky",
694
              'attributes' => array(
695
                  'title' => bts('Make this topic sticky', array(), NULL, 'boinc:forum-sticky-comment')
696
              )
697
          );
698
        }
699
        if ($object->comment == COMMENT_NODE_READ_WRITE) {
700
          $links['lock'] = array(
701
              'title' => bts('Lock', array(), NULL, 'boinc:forum-lock-comment'),
702
              'href' => "{$node_control}/lock",
703
              'attributes' => array(
704
                  'title' => bts('Lock this thread for comments', array(), NULL, 'boinc:forum-lock-comment')
705
              )
706
          );
707
        }
708
        else {
709
          $links['unlock'] = array(
710
              'title' => bts('Unlock', array(), NULL, 'boinc:forum-unlock-comment'),
711
              'href' => "{$node_control}/unlock",
712
              'attributes' => array(
713
                  'title' => bts('Unlock this thread for comments', array(), NULL, 'boinc:forum-unlock-comment')
714
              )
715
          );
716
        }
717
        if ($object->status) {
718
          $links['hide'] = array(
719
              'title' => bts('Hide', array(), NULL, 'boinc:forum-hide-comment'),
720
              'href' => "{$node_control}/hide",
721
              'attributes' => array(
722
                  'title' => bts('Hide this topic', array(), NULL, 'boinc:forum-hide-comment')
723
              )
724
          );
725
        }
726
        else {
727
          $links['unhide'] = array(
728
              'title' => bts('Unhide', array(), NULL, 'boinc:forum-unhide-comment'),
729
              'href' => "{$node_control}/unhide",
730
              'attributes' => array(
731
                  'title' => bts('Unhide this topic', array(), NULL, 'boinc:forum-unhide-comment')
732
              )
733
          );
734
        }
735
      }// if user_access('edit any forum topic')
736
    }
737
  }
738
  else if ($type=='comment') {
739
    $node = node_load($object->nid);
740
    $nid = $object->nid;
741
    $cid = $object->cid;
742
743
    // QUOTE
744
    if ($node->comment == COMMENT_NODE_READ_WRITE) {
745
        $links['quote'] = array(
746
            'title' => bts('Quote', array(), NULL, 'boinc:forum-reply-to-comment-with-quote'),
747
            'href' => "comment/reply/{$nid}/{$cid}",
748
            'attributes' => array(
749
                'title' => bts('Reply to this comment with a quote', array(), NULL, 'boinc:forum-reply-to-comment')
750
            ),
751
            'fragment' => 'comment-form',
752
            'query' => 'quote=1',
753
        );
754
    }
755
    // HIDE and COVERT comment
756
    // The following are moderator only links
757
    if (user_access('administer comments')) {
758
      $comment_control = "comment_control/{$cid}";
759
      // Add link to convert comment into a new topic
760
      $reply_count = db_result(db_query(' SELECT COUNT(*) FROM comments WHERE pid = %d', $cid ));
761
      if ($reply_count == 0) {
762
        $links['convert'] = array(
763
            'title' => bts('Convert', array(), NULL, 'boinc:forum-convert-comment-to-topic'),
764
            'href' => "{$comment_control}/convert",
765
            'attributes' => array(
766
                'title' => bts('Convert this comment to a new topic', array(), NULL, 'boinc:forum-convert-comment-to-topic')
767
            )
768
        );
769
      }
770
      // Add hide link
771
      if ($object->status == 0) {
772
        $links['hide'] = array(
773
            'title' => bts('Hide', array(), NULL, 'boinc:forum-hide-comment'),
774
            'href' => "{$comment_control}/hide",
775
            'attributes' => array(
776
                'title' => bts('Hide this comment', array(), NULL, 'boinc:forum-hide-comment')
777
            )
778
        );
779
      }
780
      else {
781
        $links['unhide'] = array(
782
            'title' => bts('Unhide', array(), NULL, 'boinc:forum-unhide-comment'),
783
            'href' => "{$comment_control}/unhide",
784
            'attributes' => array(
785
                'title' => bts('Unhide this comment', array(), NULL, 'boinc:forum-unhide-comment')
786
            )
787
        );
788
      }
789
    }// if user_access('administer comments')
790
  }//if $type
791
792
  return $links;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $links does not seem to be defined for all execution paths leading up to this point.
Loading history...
793
}
794
795
/**
796
 * Implementation of hook_mail_alter()
797
 */
798
function boinccore_mail_alter(&$message) {
799
  /* This code alters the headers for all emails sent by the Drupal Web site to use
800
     'Quote-Printable' as the encoding, both altering the header and modifies the body to the
801
     new encoding.
802
  */
803
  $message['headers']['Content-Transfer-Encoding'] = 'Quoted-Printable';
804
  if (is_array($message['body'])) {
805
    $message['body'] = array_map( "quoted_printable_encode", $message['body'] );
806
  } else {
807
    $message['body'] = quoted_printable_encode($message['body']);
808
  }
809
}
810
811
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
812
 * Page callbacks from hook_menu()
813
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
814
815
/**
816
 * Controller for handling simple node status configuration.
817
 * Allow published, sticky, and comment status to be set on nodes by direct
818
 * link rather than through the node form.
819
 */
820
function boinccore_node_control($nid = NULL, $action = NULL) {
821
  if ((!$nid OR !$node = node_load($nid)) OR
822
      ($node->type == 'forum' AND !user_access('edit any forum topic')) OR
823
      ($node->type != 'forum' AND !user_access('administer nodes'))) {
824
    // What are you even doing here...
825
    return FALSE;
826
  }
827
  switch ($action) {
828
  case 'unhide':
829
    node_publish_action($node);
830
    break;
831
  case 'hide':
832
    node_unpublish_action($node);
833
    break;
834
  case 'sticky':
835
    node_make_sticky_action($node);
836
    break;
837
  case 'unsticky':
838
    node_make_unsticky_action($node);
839
    break;
840
  case 'lock':
841
    $node->comment = 1;
842
    watchdog('action', 'Locked comments on @type %title.', array(
843
      '@type' => node_get_types('name', $node), '%title' => $node->title));
844
    break;
845
  case 'unlock':
846
    $node->comment = 2;
847
    watchdog('action', 'Unlocked comments on @type %title.', array(
848
      '@type' => node_get_types('name', $node), '%title' => $node->title));
849
    break;
850
  default:
851
  }
852
  node_save($node);
853
  // If hiding a forum topic (node) and not an administrator, go to
854
  // the forum page. Otherwise the user will reach an access-denied
855
  // page.
856
  if (($action=="hide") and (!user_access('administer forums'))) {
857
    drupal_goto("community/forum/{$node->tid}");
858
  }
859
  drupal_goto("node/{$nid}");
860
}
861
862
/**
863
 * Controller for handling simple comment status configuration.
864
 * Allow published status to be set on comments by direct link rather than
865
 * through the comment edit form.
866
 */
867
function boinccore_comment_control($cid = NULL, $action = NULL) {
868
  if (!$cid OR !$comment = _comment_load($cid)) {
869
    // What are you even doing here...
870
    return FALSE;
871
  }
872
  $return_path = "node/{$comment->nid}";
873
  $return_anchor = "comment-{$cid}";
874
  switch ($action) {
875
  case 'unhide':
876
    comment_publish_action($comment);
877
    rules_invoke_event('boinccore_comment_unhidden', $comment);
878
    if (module_exists("boinc_solr_comments")) {
879
      boinc_solr_comments_publish($comment);
880
    }
881
    break;
882
  case 'hide':
883
    comment_unpublish_action($comment);
884
    rules_invoke_event('comment_unpublish', $comment);
885
    if (module_exists("boinc_solr_comments")) {
886
      boinc_solr_comments_unpublish($comment);
887
    }
888
    break;
889
  case 'convert':
890
    $node = new stdClass();
891
    $node->name = $comment->subject;
892
    $node->title = $node->name;
893
    $node->body = $comment->comment;
894
    $node->type = 'forum';
895
    $node->created = $comment->timestamp;
896
    $node->changed = $node->created;
897
    $node->promote = 0; // Display on front page?
898
    $node->sticky = 0;  // Display top of page?
899
    $node->status = 1;   // Published?
900
    $node->comment = 2;
901
    //$node->language = 'en';
902
    $node->uid = $comment->uid;
903
904
    // Preselect the parent's taxonomy ID
905
    $parent_node = node_load($comment->nid);
906
    $node->tid = $parent_node->tid;
907
908
    if (filter_access($comment->format)) {
909
      $node->format = $comment->format;
910
    }
911
912
    // Save the new node
913
    node_save($node);
914
    taxonomy_node_save($node, array($node->tid));
915
916
    // Delete the comment
917
    module_load_include('inc', 'comment', 'comment.admin');
918
    _comment_delete_thread($comment);
919
920
    rules_invoke_event('boinccore_comment_convert', $comment);
921
922
    $return_path = "node/{$node->nid}";
923
    $return_anchor = NULL;
924
    break;
925
  default:
926
  }
927
  drupal_goto($return_path, NULL, $return_anchor);
928
}
929
930
/**
931
 * Page callback for the look up account RPC (lookup_account.php).
932
 * Get the authenticator for a given account
933
 */
934
function boinccore_lookup_account() {
935
  include_boinc('user/lookup_account.php');
936
}
937
938
/**
939
 * Page callback for the account manager get info RPC (am_get_info.php).
940
 * Get assorted details for a given account
941
 */
942
function boinccore_am_get_info() {
943
  // Remove q from the GET request or BOINC will panic
944
  unset($_GET['q']);
945
  // Capture the XML output of the RPC so we can override things
946
  ob_start();
947
  include_boinc('user/am_get_info.php');
948
  $xml = ob_get_clean();
949
  $xml = load_configuration($xml);
950
  // See if the account has an approved profile in Drupal
951
  $uid = !empty($xml['am_get_info_reply']['id']) ? boincuser_lookup_uid($xml['am_get_info_reply']['id']) : 0;
952
  if ($uid) {
953
    $content_profile = content_profile_load('profile', $uid);
954
    $profile_is_approved = ($content_profile->status AND !$content_profile->moderate);
955
    $country = check_plain($content_profile->field_country[0]['value']);
956
    $website = '';
957
    if ($profile_is_approved) {
958
      $website = check_plain($content_profile->field_url[0]['value']);
959
    }
960
    // Override BOINC values with Drupal values as needed
961
    $xml['am_get_info_reply']['has_profile']['@value'] = ($profile_is_approved) ? 1 : 0;
962
    $xml['am_get_info_reply']['country']['@value'] = $country;
963
    $xml['am_get_info_reply']['url']['@value'] = $website;
964
  }
965
  print save_configuration($xml);
0 ignored issues
show
Bug introduced by
Are you sure save_configuration($xml) of type false|string can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

965
  print /** @scrutinizer ignore-type */ save_configuration($xml);
Loading history...
966
}
967
968
/**
969
 * Page callback for the account manager set info RPC (am_set_info.php).
970
 * Update assorted details for a given account
971
 */
972
function boinccore_am_set_info() {
973
  // Remove q from the GET request or BOINC will panic
974
  unset($_GET['q']);
975
  // Validate the XML prefs (in case BOINC does not)
976
  $global_prefs = !empty($_POST['global_prefs']) ? $_POST['global_prefs'] : (!empty($_GET['global_prefs']) ? $_GET['global_prefs'] : NULL);
977
  $project_prefs = !empty($_POST['project_prefs']) ? $_POST['project_prefs'] : (!empty($_GET['project_prefs']) ? $_GET['project_prefs'] : NULL);
978
  libxml_use_internal_errors(true);
979
  $xml = new DomDocument();
980
  if ($global_prefs) {
981
    $xml->loadXML($global_prefs, LIBXML_NOBLANKS);
982
    if ($errors = libxml_get_errors($xml)) {
0 ignored issues
show
Unused Code introduced by
The call to libxml_get_errors() has too many arguments starting with $xml. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

982
    if ($errors = /** @scrutinizer ignore-call */ libxml_get_errors($xml)) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
983
      $lines = explode("\r", $global_prefs);
984
      watchdog('am_set_info', "XML validation error in global_prefs: {$errors[0]->message} at line {$errors[0]->line}" .
985
        ': <br/>' . htmlentities($lines[$errors[0]->line - 1]), array(), WATCHDOG_ERROR);
986
    }
987
  }
988
  elseif ($project_prefs) {
989
    $xml->loadXML($project_prefs, LIBXML_NOBLANKS);
990
    if ($errors = libxml_get_errors($xml)) {
991
      $lines = explode("\r", $project_prefs);
992
      watchdog('am_set_info', "XML validation error in project_prefs: {$errors[0]->message} at line {$errors[0]->line}" .
993
        ': <br/>' . htmlentities($lines[$errors[0]->line - 1]), array(), WATCHDOG_ERROR);
994
    }
995
  }
996
  if (!$errors) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $errors does not seem to be defined for all execution paths leading up to this point.
Loading history...
997
    // Capture the XML output of the RPC so we can override things
998
    ob_start();
999
    include_boinc('user/am_set_info.php');
1000
    $xml = ob_get_clean();
1001
    $xml = load_configuration($xml);
1002
    if (isset($xml['am_set_info_reply']['success'])) {
1003
      // Find the account in Drupal
1004
      $boinc_auth = !empty($_POST['account_key']) ? $_POST['account_key'] : $_GET['account_key'];
1005
      db_set_active('boinc_rw');
1006
      $boinc_id = db_result(db_query("
1007
        SELECT id
1008
        FROM {user}
1009
        WHERE authenticator = '%s'",
1010
        $boinc_auth
1011
      ));
1012
      db_set_active('default');
1013
      $uid = boincuser_lookup_uid($boinc_id);
1014
1015
      // Apply any relevant updates to the Drupal account, also
1016
      $country = !empty($_POST['country']) ? $_POST['country'] : (!empty($_GET['country']) ? $_GET['country'] : NULL);
1017
      $url = !empty($_POST['url']) ? $_POST['url'] : (!empty($_GET['url']) ? $_GET['url'] : NULL);
1018
      $email_addr = !empty($_POST['email_addr']) ? $_POST['email_addr'] : (!empty($_GET['email_addr']) ? $_GET['email_addr'] : NULL);
1019
1020
      if ($email_addr) {
1021
        $account = user_load($uid);
1022
        user_save($account, array('mail' => $email_addr));
1023
      }
1024
      if ($country OR $url) {
1025
        $content_profile = content_profile_load('profile', $uid);
1026
        if ($country) $content_profile->field_country[0]['value'] = $country;
1027
        if ($url) $content_profile->field_url[0]['value'] = $url;
1028
        node_save($content_profile);
1029
      }
1030
    }
1031
  }
1032
  else {
1033
    $xml = array(
1034
      'error' => array(
1035
        'error_num' => -112,
1036
        'error_msg' => "{$errors[0]->message} at line {$errors[0]->line}" .
1037
        ': <br/>' . htmlentities($lines[$errors[0]->line - 1])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $lines does not seem to be defined for all execution paths leading up to this point.
Loading history...
1038
      ),
1039
    );
1040
  }
1041
  print save_configuration($xml);
0 ignored issues
show
Bug introduced by
Are you sure save_configuration($xml) of type false|string can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1041
  print /** @scrutinizer ignore-type */ save_configuration($xml);
Loading history...
1042
}
1043
1044
/**
1045
 * Page callback for the set host info RPC (am_set_host_info.php).
1046
 * Update the venue for the given host
1047
 */
1048
function boinccore_am_set_host_info() {
1049
  // Remove q from the GET request or BOINC will panic
1050
  unset($_GET['q']);
1051
  // Capture the XML output of the RPC so we can override things
1052
  ob_start();
1053
  include_boinc('user/am_set_host_info.php');
1054
  $xml = ob_get_clean();
1055
  $xml = load_configuration($xml);
1056
  if (isset($xml['am_set_host_info_reply']['success'])) {
1057
    // Override anything that needs overriding
1058
  }
1059
  print save_configuration($xml);
0 ignored issues
show
Bug introduced by
Are you sure save_configuration($xml) of type false|string can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1059
  print /** @scrutinizer ignore-type */ save_configuration($xml);
Loading history...
1060
}
1061
1062
/**
1063
 * Page callback for the show user RPC (show_user.php).
1064
 * Get assorted details for a given account
1065
 */
1066
function boinccore_show_user() {
1067
  // Remove q from the GET request or BOINC will panic
1068
  unset($_GET['q']);
1069
  // Capture the XML output of the RPC so we can override things
1070
  ob_start();
1071
  include_boinc('user/show_user.php');
1072
  $xml = ob_get_clean();
1073
  $xml = load_configuration($xml);
1074
  // See if the account has an approved profile in Drupal
1075
  $uid = !empty($xml['user']['id']) ? boincuser_lookup_uid($xml['user']['id']) : 0;
1076
  if ($uid) {
1077
    $content_profile = content_profile_load('profile', $uid);
1078
    $profile_is_approved = ($content_profile->status AND !$content_profile->moderate);
1079
    $country = check_plain($content_profile->field_country[0]['value']);
1080
    $website = '';
1081
    if ($profile_is_approved) {
1082
      $website = check_plain($content_profile->field_url[0]['value']);
1083
    }
1084
    // Override BOINC values with Drupal values as needed
1085
    $xml['user']['has_profile']['@value'] = ($profile_is_approved) ? 1 : 0;
1086
    $xml['user']['country']['@value'] = $country;
1087
    $xml['user']['url']['@value'] = $website;
1088
  }
1089
  print save_configuration($xml);
0 ignored issues
show
Bug introduced by
Are you sure save_configuration($xml) of type false|string can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1089
  print /** @scrutinizer ignore-type */ save_configuration($xml);
Loading history...
1090
}
1091
1092
/**
1093
 * Page callback for the pending credit RPC (pending.php).
1094
 * Get pending credit information for a given account
1095
 */
1096
function boinccore_pending_credit() {
1097
  // Remove q from the GET request or BOINC will panic
1098
  unset($_GET['q']);
1099
  include_boinc('user/pending.php');
1100
}
1101
1102
/**
1103
 * Page callback for the create team RPC (create_team.php).
1104
 * Create a team with the provided details
1105
 */
1106
function boinccore_create_team() {
1107
1108
  if (module_exists('boincteam')) {
1109
    module_load_include('module', 'boincteam', 'boincteam');
1110
1111
    $input_format = !empty($values['format']) ? $values['format'] : 4;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $values seems to never exist and therefore empty should always be true.
Loading history...
1112
    if (!empty($_GET['description'])) $_GET['description'] = check_markup($_GET['description'], $input_format);
1113
1114
    // Try to add the team to BOINC and capture the XML output of the RPC
1115
    ob_start();
1116
    include_boinc('user/create_team.php');
1117
    $xml = ob_get_clean();
1118
    $xml = load_configuration($xml);
1119
1120
    if (isset($xml['create_team_reply']['success'])) {
1121
      $boincteam_id = isset($xml['create_team_reply']['team_id']['@value']) ? $xml['create_team_reply']['team_id']['@value'] : 0;
1122
1123
      if ($boincteam_id) {
1124
1125
        $boincteam = boincteam_load($boincteam_id);
1126
        $team_owner_uid = boincuser_lookup_uid($boincteam->userid);
1127
1128
        // Create the team node in Drupal
1129
1130
        $values = array(
1131
          'name' => isset($_GET['name']) ? $_GET['name'] : '',
1132
          'description' => isset($_GET['description']) ? $_GET['description'] : '',
1133
          'type' => isset($_GET['type']) ? $_GET['type'] : '',
1134
        );
1135
        $teaser = node_teaser($values['description']);
1136
        $created_time = time();
1137
1138
        $node = array(
1139
          'type' => 'team',
1140
          'title' => $values['name'],
1141
          'body' => $values['description'],
1142
          'teaser' => $teaser,
1143
          'uid' => $team_owner_uid,
1144
          'path' => null,
1145
          'status' => 1,  // published or not - always publish
1146
          'promote' => 0,
1147
          'created' => $created_time,
1148
          'comment' => 0,  // comments disabled
1149
          'moderate' => 0,
1150
          'sticky' => 0,
1151
          'format' => $input_format
1152
        );
1153
1154
        // Use pathauto function, if available, to clean up the path
1155
        if (module_exists('pathauto')) {
1156
          module_load_include('inc', 'pathauto', 'pathauto');
1157
          $node['path'] = pathauto_cleanstring($values['name']);
1158
1159
          $node = (object) $node; // node_save requires an object form
1160
          $team_categories = taxonomy_get_term_by_name($values['type']);
1161
          $node->taxonomy[] = $team_categories[0];
1162
1163
          // Save the team node
1164
          node_save($node);
1165
          // Save the team IDs to a BOINC <--> Drupal reference table.
1166
          db_query('INSERT INTO {boincteam} (team_id, nid) VALUES (%d, %d)', $boincteam_id, $node->nid);
1167
        }
1168
        else {
1169
          $xml['create_team_reply']['warning'] = t(
1170
            'There was a problem integrating this team into Drupal. Please
1171
            contact @project administrators!', array('@project' => PROJECT)
1172
          );
1173
          watchdog(
1174
            'BOINC team',
1175
            'BOINC teams require the Pathauto module. Team cannot be created in
1176
              Drupal via create_team.php RPC.',
1177
            array(),
1178
            WATCHDOG_ERROR
1179
          );
1180
          // Delete from the BOINC DB if we can't sync with Drupal
1181
          $boincteam::delete();
1182
        }
1183
      }
1184
      else {
1185
        $xml['create_team_reply']['warning'] = t(
1186
          'There was a problem integrating this team into Drupal. Please
1187
          contact @project administrators!', array('@project' => PROJECT)
1188
        );
1189
        watchdog(
1190
          'BOINC team',
1191
          'Team cannot be created in Drupal via create_team.php RPC because no
1192
            BOINC team ID was returned in the XML.',
1193
          array(),
1194
          WATCHDOG_ERROR
1195
        );
1196
      }
1197
    }
1198
  }
1199
  else {
1200
    $xml = array(
1201
      'error' => array(
1202
        'error_num' => -1,
1203
        'error_msg' => t(
1204
          'Teams are not enabled for this project'
1205
        ),
1206
      ),
1207
    );
1208
    watchdog(
1209
      'BOINC team',
1210
      'Team cannot be created in Drupal via create_team.php RPC because the
1211
        BOINC team module is not enabled.',
1212
      array(),
1213
      WATCHDOG_ERROR
1214
    );
1215
  }
1216
  print save_configuration($xml);
0 ignored issues
show
Bug introduced by
Are you sure save_configuration($xml) of type false|string can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1216
  print /** @scrutinizer ignore-type */ save_configuration($xml);
Loading history...
1217
}
1218
1219
/**
1220
 * Page callback for the team lookup RPC (team_lookup.php).
1221
 * Get info on a team by ID or a list of teams that match a given name
1222
 */
1223
function boinccore_team_lookup() {
1224
  // Remove q from the GET request or BOINC will panic
1225
  unset($_GET['q']);
1226
  include_boinc('user/team_lookup.php');
1227
}
1228
1229
/**
1230
 * Page callback for the team email list RPC (team_email_list.php).
1231
 * Get members of a given team
1232
 */
1233
function boinccore_team_email_list() {
1234
  // See if the account has an approved profile in Drupal
1235
  $boincteam_id = !empty($_POST['teamid']) ? $_POST['teamid'] : $_GET['teamid'];
1236
  $credit_only = !empty($_POST['creditonly']) ? $_POST['creditonly'] : $_GET['creditonly'];
1237
  $show_xml = !empty($_POST['xml']) ? $_POST['xml'] : $_GET['xml'];
1238
  if (!$show_xml) {
1239
      // creditonly does not affect non xml output in BOINC
1240
      $credit_only = FALSE;
1241
  }
1242
  $xml = array();
1243
1244
  if ($boincteam_id && is_numeric($boincteam_id)) {
1245
    if ($credit_only) {
1246
      db_set_active('boinc_rw');
1247
      $result = db_query("
1248
        SELECT
1249
          u.id, u.name, u.cross_project_id, u.email_addr, u.total_credit, u.expavg_credit, u.expavg_time
1250
        FROM {user} u
1251
        WHERE u.teamid = %d and u.total_credit > 0",
1252
        $boincteam_id
1253
      );
1254
      db_set_active('default');
1255
1256
      $xml = array('users' => array());
1257
      while ($member = db_fetch_object($result)) {
1258
        $team_member = array(
1259
          'id' => $member->id,
1260
          'cpid' => md5($member->cross_project_id.$member->email_addr),
1261
          'name' => htmlspecialchars($member->name),
1262
          'total_credit' => round($member->total_credit),
1263
          'expavg_credit' => round($member->expavg_credit),
1264
          'expavg_time' => round($member->expavg_time),
1265
        );
1266
        $xml['users']['user'][] = $team_member;
1267
      }
1268
    }
1269
    else {
1270
      // Query BOINC database user table
1271
      db_set_active('boinc_rw');
1272
      $result = db_query("
1273
        SELECT
1274
          u.id, u.name, u.cross_project_id, u.create_time, u.email_addr, u.total_credit, u.expavg_credit, u.expavg_time
1275
        FROM {user} u
1276
        WHERE u.teamid = %d ORDER BY u.email_addr ASC",
1277
        $boincteam_id
1278
      );
1279
      db_set_active('default');
1280
1281
      // Extract information from BOINC database for team members.
1282
      $team_members = array();
1283
      while ($member = db_fetch_object($result)) {
1284
        $team_members[$member->id] = array(
1285
          'id' => $member->id,
1286
          'cpid' => md5($member->cross_project_id.$member->email_addr),
1287
          'create_time' => $member->create_time,
1288
          'name' => htmlspecialchars($member->name),
1289
          'country' => NULL,
1290
          'total_credit' => round($member->total_credit),
1291
          'expavg_credit' => round($member->expavg_credit),
1292
          'expavg_time' => round($member->expavg_time),
1293
          'url' => NULL,
1294
          'has_profile' => 0,
1295
        );
1296
      }
1297
1298
      // Query Drupal database, multiple tables
1299
      $sql1 = "
1300
         SELECT
1301
           bu.boinc_id, du.uid, du.name, n.nid, n.type, n.field_country_value, n.field_url_value
1302
         FROM {boincuser} AS bu
1303
         INNER JOIN {users} AS du ON bu.uid=du.uid
1304
         LEFT JOIN (
1305
           SELECT node.nid, node.uid, node.type, p.field_country_value, p.field_url_value
1306
           FROM {node}
1307
           INNER JOIN {content_type_profile} AS p ON node.nid=p.nid
1308
           WHERE node.type='profile' ) n ON du.uid=n.uid
1309
         WHERE bu.boinc_id IN (%s)";
1310
      $member_id_list = implode(',', array_keys($team_members));
1311
      if (!$member_id_list) {
1312
        $member_id_list = '-1';
1313
      }
1314
      $result = db_query($sql1, $member_id_list);
1315
      while ($member = db_fetch_object($result)) {
1316
        $team_members[$member->boinc_id]['country'] = $member->field_country_value;
1317
        $team_members[$member->boinc_id]['url'] = $member->field_url_value;
1318
        $team_members[$member->boinc_id]['has_profile'] = isset($member->nid) ? 1:  0;
1319
        $xml['users']['user'][] = $team_members[$member->boinc_id];
1320
      }
1321
    } // end if credit_only
1322
  }
1323
  else {
1324
    $xml = array(
1325
      'error' => array(
1326
        'error_num' => -136,
1327
        'error_msg' => 'Not found',
1328
      ),
1329
    );
1330
  } // end if boincteam_id
1331
  print xml_to_text(array_to_xml($xml), TRUE, TRUE);
1332
}
1333
1334
/**
1335
 * Page callback for the forum prefs RPC (edit_forum_preferences_action.php).
1336
 * Edit the forum preferences for a given user
1337
 */
1338
function boinccore_edit_forum_preferences() {
1339
  // Do not pass through to BOINC in this case as BOINC forums are no longer
1340
  // relevant -- use Drupal data only
1341
1342
  $account_key = !empty($_POST['account_key']) ? $_POST['account_key'] : (!empty($_GET['account_key']) ? $_GET['account_key'] : NULL);
1343
1344
  require_boinc('boinc_db');
1345
  $boincuser = BoincUser::lookup_auth($account_key);
1346
  if ($boincuser) {
1347
    $uid = boincuser_lookup_uid($boincuser->id);
1348
    if ($uid AND $account = user_load($uid)) {
1349
      // Currently supported preferences
1350
      $avatar_url = isset($_POST['avatar_url']) ? $_POST['avatar_url'] : (isset($_GET['avatar_url']) ? $_GET['avatar_url'] : NULL);
1351
      $hide_signatures = isset($_POST['forum_hide_signatures']) ? $_POST['forum_hide_signatures'] : (isset($_GET['forum_hide_signatures']) ? $_GET['forum_hide_signatures'] : NULL);
1352
      $signature = isset($_POST['signature']) ? $_POST['signature'] : (isset($_GET['signature']) ? $_GET['signature'] : NULL);
1353
      $post_order = isset($_POST['thread_sort']) ? $_POST['thread_sort'] : (isset($_GET['thread_sort']) ? $_GET['thread_sort'] : NULL);
1354
      // Update preferences as needed
1355
      if ($avatar_url) {
1356
        $avatar_image = file_get_contents($avatar_url);
1357
        if ($avatar_image) {
1358
          $image_dir = 'profiles';
1359
          $image_path = "{$image_dir}/{$boincuser->id}_avatar.jpg";
1360
          $file = file_save_data($avatar_image, $image_path, FILE_EXISTS_REPLACE);
1361
          if ($file) {
0 ignored issues
show
introduced by
$file is of type A, thus it always evaluated to true.
Loading history...
1362
            $profile = new stdClass();
1363
            $profile->type = 'profile';
1364
            $profile->language = NULL;
1365
            if ($profile_nid = content_profile_profile_exists($profile, $account->uid)) {
1366
              $profile_node = node_load($profile_nid);
1367
              if ($profile_node) {
1368
                $avatar_image = get_cck_image_object(file_directory_path() . '/' . $image_path, 'field_image', 'profile', TRUE);
1369
                if ($avatar_image) {
1370
                  $profile_node->field_image[0] = $avatar_image;
1371
                  node_save($profile_node);
1372
                }
1373
                else {
1374
                  $error = 'Error saving avatar to profile';
1375
                }
1376
              }
1377
              else {
1378
                $error = 'Unable to load user profile';
1379
              }
1380
            }
1381
            else {
1382
              $error = 'User has no profile, so avatar could not be added';
1383
            }
1384
          }
1385
          else {
1386
            $error = 'Unable to save remote image';
1387
          }
1388
        }
1389
        else {
1390
          $error = 'Could not find avatar image at URL';
1391
        }
1392
      }
1393
      if ($hide_signatures !== NULL) {
1394
        user_save($account, array('hide_signatures' => ($hide_signatures ? 1 : 0)));
1395
      }
1396
      if ($signature !== NULL) {
1397
        $signature = check_markup($signature);
1398
        user_save($account, array('signature' => $signature));
1399
      }
1400
      if ($post_order) {
1401
        require_boinc('forum');
1402
        $post_order_map = array(
1403
          CREATE_TIME_OLD => 2,
1404
          CREATE_TIME_NEW => 1,
1405
        );
1406
        $drupal_post_order = isset($post_order_map[$post_order]) ? $post_order_map[$post_order] : 2;
1407
        user_save($account, array('sort' => $drupal_post_order));
1408
      }
1409
      if (!$error) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error does not seem to be defined for all execution paths leading up to this point.
Loading history...
1410
        // Success
1411
        $xml = array(
1412
          'edit_forum_preferences' => array(
1413
            'success' => NULL,
1414
          ),
1415
        );
1416
      }
1417
      else {
1418
        // Failure
1419
        $xml = array(
1420
          'error' => array(
1421
            'error_num' => -1,
1422
            'error_msg' => $error,
1423
          ),
1424
        );
1425
      }
1426
    }
1427
    else {
1428
      // Drupal user not found
1429
      $xml = array(
1430
        'error' => array(
1431
          'error_num' => -1,
1432
          'error_msg' => 'Unknown error',
1433
        ),
1434
      );
1435
    }
1436
  }
1437
  else {
1438
    // BOINC user not found
1439
    $xml = array(
1440
      'error' => array(
1441
        'error_num' => -136,
1442
        'error_msg' => 'Not found',
1443
      ),
1444
    );
1445
  }
1446
  print xml_to_text(array_to_xml($xml), TRUE, TRUE);
1447
}
1448
1449
/**
1450
 * Page callback for the user forum activity RPC (forum_get_data.php).
1451
 * Get the last comments OR threads made by a given user
1452
 */
1453
function boinccore_forum_get_data() {
1454
  // Do not pass through to BOINC in this case as BOINC forums are no longer
1455
  // relevant -- use Drupal data only
1456
1457
  $xml = array();
1458
  $boinc_id = !empty($_POST['userid']) ? $_POST['userid'] : (!empty($_GET['userid']) ? $_GET['userid'] : NULL);
1459
  $uid = boincuser_lookup_uid($boinc_id);
1460
1461
  if ($uid) {
1462
    $method = !empty($_POST['method']) ? $_POST['method'] : (!empty($_GET['method']) ? $_GET['method'] : NULL);
1463
    $count = !empty($_POST['count']) ? $_POST['count'] : (!empty($_GET['count']) ? $_GET['count'] : NULL);
1464
    if (!$count) $count = 10;
1465
1466
    switch ($method) {
1467
    case 'user_posts':
1468
      $content_length = !empty($_POST['content_length']) ? $_POST['content_length'] : (!empty($_GET['content_length']) ? $_GET['content_length'] : NULL);
1469
      $posts = db_query("
1470
        SELECT
1471
          c.cid,
1472
          n.nid,
1473
          c.uid,
1474
          n.title,
1475
          c.comment,
1476
          c.timestamp
1477
        FROM comments c
1478
        INNER JOIN node n ON c.nid = n.nid
1479
        WHERE (n.status = 1) AND (c.uid = '%d')
1480
        ORDER BY timestamp DESC
1481
        LIMIT %d",
1482
        $uid, (int) $count
1483
      );
1484
      $xml = array(
1485
        'rpc_response' => array(
1486
          'count' => 0,
1487
          'posts' => array(),
1488
        ),
1489
      );
1490
      $post_count = 0;
1491
      while ($post = db_fetch_object($posts)) {
1492
        $xml['rpc_response']['posts']['post'][] = array(
1493
          'id' => $post->cid,
1494
          'threadid' => $post->nid,
1495
          'threadtitle' => $post->title,
1496
          'timestamp' => $post->timestamp,
1497
          'content' => ($content_length ? substr($post->comment, 0, $content_length) : $post->comment),
1498
        );
1499
        $post_count++;
1500
      }
1501
      $xml['rpc_response']['count'] = $post_count;
1502
      break;
1503
1504
    case 'user_threads':
1505
      $threads = db_query("
1506
        SELECT
1507
          n.nid,
1508
          n.uid,
1509
          n.title,
1510
          nc.totalcount AS views,
1511
          n.changed,
1512
          n.title,
1513
          tn.tid,
1514
          (
1515
            SELECT COUNT(*)
1516
            FROM {comments} c
1517
            WHERE c.nid = n.nid
1518
          ) AS replies
1519
        FROM {node} n
1520
        LEFT JOIN {node_counter} nc ON nc.nid = n.nid
1521
        LEFT JOIN {term_node} tn ON tn.nid = n.nid
1522
        WHERE (n.status = 1) AND (n.uid = '%d')
1523
        ORDER BY changed DESC
1524
        LIMIT %d",
1525
        $uid, (int) $count
1526
      );
1527
      $xml = array(
1528
        'rpc_response' => array(
1529
          'count' => 0,
1530
          'threads' => array(),
1531
        ),
1532
      );
1533
      $thread_count = 0;
1534
      while ($thread = db_fetch_object($threads)) {
1535
        $xml['rpc_response']['threads']['thread'][] = array(
1536
          'id' => $thread->nid,
1537
          'forumid' => $thread->tid,
1538
          'replies' => $thread->replies,
1539
          'views' => $thread->views,
1540
          'timestamp' => $thread->changed,
1541
          'title' => $thread->title,
1542
        );
1543
        $thread_count++;
1544
      }
1545
      $xml['rpc_response']['count'] = $thread_count;
1546
      break;
1547
    default:
1548
      $xml = array(
1549
        'error' => array(
1550
          'error_num' => -1,
1551
          'error_msg' => 'Unknown error',
1552
        ),
1553
      );
1554
    }
1555
  }
1556
  else {
1557
    $xml = array(
1558
      'error' => array(
1559
        'error_num' => -136,
1560
        'error_msg' => 'Not found',
1561
      ),
1562
    );
1563
  }
1564
  print xml_to_text(array_to_xml($xml), TRUE, TRUE);
1565
}
1566
1567
/**
1568
 * Page callback for the applications RPC (apps.php).
1569
 * Get information on applications in the system
1570
 */
1571
function boinccore_apps() {
1572
  // Remove q from the GET request or BOINC will panic
1573
  unset($_GET['q']);
1574
  include_boinc('user/apps.php');
1575
}
1576
1577
/**
1578
 * Controller for handling direct linking to paginated content.
1579
 * Because pagination settings are user configurable, it is impossible to know
1580
 * in advance on which page a given comment will appear. Link instead to this
1581
 * controller function, which can compute the page based on the user's settings
1582
 */
1583
function boinccore_url_pagination_handler($type, $object_id = NULL) {
1584
  global $user;
1585
  $path = NULL;
1586
  $params = array();
1587
  switch ($type) {
1588
  case 'boinc-forum':
1589
    // Redirect requests to a BOINC forum to the Drupal forum
1590
    $forum_id = db_result(db_query('
1591
      SELECT tid
1592
      FROM {boincimport_temp_forum}
1593
      WHERE forum_id = %d',
1594
      $object_id
1595
    ));
1596
    if ($forum_id) {
1597
      drupal_goto("community/forum/{$forum_id}");
1598
    }
1599
    break;
1600
  case 'boinc-forum-index':
1601
    // Redirect requests to the top level BOINC forum to Drupal forums
1602
    drupal_goto("community/forum");
1603
    break;
1604
  case 'boinc-forum-post':
1605
    // Redirect requests to a BOINC forum post to the Drupal comment
1606
    $cid = db_result(db_query('
1607
      SELECT cid
1608
      FROM {boincimport_temp_post}
1609
      WHERE post_id = %d',
1610
      $object_id
1611
    ));
1612
    if ($cid) {
1613
      drupal_goto("goto/comment/{$cid}");
1614
    }
1615
    break;
1616
  case 'boinc-forum-topic':
1617
    // Redirect requests to a BOINC forum topic to the Drupal node
1618
    $nid = db_result(db_query('
1619
      SELECT nid
1620
      FROM {boincimport_temp_topic}
1621
      WHERE topic_id = %d',
1622
      $object_id
1623
    ));
1624
    if ($nid) {
1625
      drupal_goto("node/{$nid}");
1626
    }
1627
    break;
1628
  case 'boinc-host':
1629
    // Redirect requests to BOINC host details to the host page in Drupal
1630
    drupal_goto("host/{$object_id}");
1631
    break;
1632
  case 'boinc-hosts-user':
1633
    // Redirect requests to a BOINC user host list to the host list in Drupal
1634
    $uid = boincuser_lookup_uid($object_id);
1635
    if ($uid) {
1636
      drupal_goto("account/{$uid}/computers");
1637
    }
1638
    break;
1639
  case 'boinc-result':
1640
    // Redirect requests to BOINC task details to the task page in Drupal
1641
    drupal_goto("task/{$object_id}");
1642
  case 'boinc-results-host':
1643
    // Redirect requests to BOINC tasks by host to the host task page in Drupal
1644
    drupal_goto("host/{$object_id}/tasks");
1645
    break;
1646
  case 'boinc-results-user':
1647
    // Redirect requests to a BOINC user's tasks to the Drupal account tasks
1648
    drupal_goto("account/tasks");
1649
    break;
1650
  case 'boinc-user':
1651
    // Redirect requests to a BOINC user ID to the Drupal profile
1652
    $uid = boincuser_lookup_uid($object_id);
1653
    if ($uid) {
1654
      drupal_goto("account/{$uid}");
1655
    }
1656
    break;
1657
  case 'boinc-workunit':
1658
    // Redirect requests to BOINC workunits to the workunit page in Drupal
1659
    drupal_goto("workunit/{$object_id}");
1660
    break;
1661
  case 'comment':
1662
    $object = _comment_load($object_id);
1663
    if ($object) {
1664
      $path = "node/{$object->nid}";
1665
      // Get the sort order
1666
      $gt_lt = '<';
1667
      $comment_order = (isset($user->sort)) ? $user->sort : variable_get('comment_default_order_forum', 2);
1668
      if ($comment_order == COMMENT_ORDER_NEWEST_FIRST) {
1669
        $gt_lt = '>';
1670
      }
1671
      // don't filter hidden comments for admins/mods
1672
      $include_hidden = '';
1673
      if (in_array('administrator', array_values($user->roles)) ||
1674
          in_array('moderator', array_values($user->roles))) {
1675
        $include_hidden = 'OR status = 1';
1676
      }
1677
      // See how many comments there are before (or after) this comment...
1678
      $comment_offset = db_result(db_query('
1679
        SELECT COUNT(*) FROM {comments}
1680
        WHERE nid = %d AND (status = 0 %s) AND timestamp %s %d',
1681
        $object->nid, $include_hidden, $gt_lt, $object->timestamp));
1682
      if ($comment_offset) {
1683
        // Get the number of comments per page
1684
        if ($user->comments_per_page) {
1685
          $comments_per_page = $user->comments_per_page;
1686
        }
1687
        else {
1688
          $node = node_load($object->nid);
1689
          $comments_per_page = variable_get(
1690
            "comment_default_per_page_{$node->type}", 50
1691
          );
1692
        }
1693
        // Determine which page to display in order to show the given comment
1694
        $page = floor($comment_offset / $comments_per_page);
1695
        if ($page) {
1696
          $params = array('page' => $page);
1697
        }
1698
      }
1699
    }
1700
    if ($path) {
1701
      drupal_goto($path, $params, "comment-{$object->cid}");
1702
    }
1703
    break;
1704
  case 'friend-requests':
1705
    // Check for a login, then redirect to the user's friend requests page
1706
    if ($user->uid) {
1707
      drupal_goto("account/{$user->uid}/friends/pending");
1708
    }
1709
    else {
1710
      drupal_goto('user/login', array(
1711
        'destination' => 'goto/friend-requests'
1712
      ));
1713
    }
1714
    break;
1715
  default:
1716
  }
1717
  drupal_not_found();
1718
}
1719
1720
/*
1721
 * Fetch an array of all countries
1722
 */
1723
function boinccore_get_country_list() {
1724
  return array(
1725
    'None' => 'None',
1726
    'International' => 'International',
1727
    'Afghanistan' => 'Afghanistan',
1728
    'Albania' => 'Albania',
1729
    'Algeria' => 'Algeria',
1730
    'American Samoa' => 'American Samoa',
1731
    'Andorra' => 'Andorra',
1732
    'Angola' => 'Angola',
1733
    'Anguilla' => 'Anguilla',
1734
    'Antarctica' => 'Antarctica',
1735
    'Antigua and Barbuda' => 'Antigua and Barbuda',
1736
    'Argentina' => 'Argentina',
1737
    'Armenia' => 'Armenia',
1738
    'Aruba' => 'Aruba',
1739
    'Australia' => 'Australia',
1740
    'Austria' => 'Austria',
1741
    'Azerbaijan' => 'Azerbaijan',
1742
    'Bahamas, The' => 'Bahamas, The',
1743
    'Bahrain' => 'Bahrain',
1744
    'Bangladesh' => 'Bangladesh',
1745
    'Barbados' => 'Barbados',
1746
    'Belarus' => 'Belarus',
1747
    'Belgium' => 'Belgium',
1748
    'Belize' => 'Belize',
1749
    'Benin' => 'Benin',
1750
    'Bermuda' => 'Bermuda',
1751
    'Bhutan' => 'Bhutan',
1752
    'Bolivia' => 'Bolivia',
1753
    'Bosnia and Herzegovina' => 'Bosnia and Herzegovina',
1754
    'Botswana' => 'Botswana',
1755
    'Brazil' => 'Brazil',
1756
    'British Virgin Islands' => 'British Virgin Islands',
1757
    'Brunei' => 'Brunei',
1758
    'Bulgaria' => 'Bulgaria',
1759
    'Burkina Faso' => 'Burkina Faso',
1760
    'Burma' => 'Burma',
1761
    'Burundi' => 'Burundi',
1762
    'Cambodia' => 'Cambodia',
1763
    'Cameroon' => 'Cameroon',
1764
    'Canada' => 'Canada',
1765
    'Cape Verde' => 'Cape Verde',
1766
    'Cayman Islands' => 'Cayman Islands',
1767
    'Central African Republic' => 'Central African Republic',
1768
    'Chad' => 'Chad',
1769
    'Channel Islands' => 'Channel Islands',
1770
    'Chile' => 'Chile',
1771
    'China' => 'China',
1772
    'Colombia' => 'Colombia',
1773
    'Comoros' => 'Comoros',
1774
    'Congo, Democratic Republic of the' => 'Congo, Democratic Republic of the',
1775
    'Congo, Republic of the' => 'Congo, Republic of the',
1776
    'Cook Islands' => 'Cook Islands',
1777
    'Costa Rica' => 'Costa Rica',
1778
    'Cote d\'Ivoire' => 'Cote d\'Ivoire',
1779
    'Croatia' => 'Croatia',
1780
    'Cuba' => 'Cuba',
1781
    'Cyprus' => 'Cyprus',
1782
    'Czech Republic' => 'Czech Republic',
1783
    'Denmark' => 'Denmark',
1784
    'Djibouti' => 'Djibouti',
1785
    'Dominica' => 'Dominica',
1786
    'Dominican Republic' => 'Dominican Republic',
1787
    'East Timor' => 'East Timor',
1788
    'Ecuador' => 'Ecuador',
1789
    'Egypt' => 'Egypt',
1790
    'El Salvador' => 'El Salvador',
1791
    'Equatorial Guinea' => 'Equatorial Guinea',
1792
    'Eritrea' => 'Eritrea',
1793
    'Estonia' => 'Estonia',
1794
    'Ethiopia' => 'Ethiopia',
1795
    'Falkland Islands' => 'Falkland Islands',
1796
    'Faroe Islands' => 'Faroe Islands',
1797
    'Fiji' => 'Fiji',
1798
    'Finland' => 'Finland',
1799
    'France' => 'France',
1800
    'French Guiana' => 'French Guiana',
1801
    'French Polynesia' => 'French Polynesia',
1802
    'Gabon' => 'Gabon',
1803
    'Gambia, The' => 'Gambia, The',
1804
    'Gaza Strip' => 'Gaza Strip',
1805
    'Georgia' => 'Georgia',
1806
    'Germany' => 'Germany',
1807
    'Ghana' => 'Ghana',
1808
    'Gibraltar' => 'Gibraltar',
1809
    'Greece' => 'Greece',
1810
    'Greenland' => 'Greenland',
1811
    'Grenada' => 'Grenada',
1812
    'Guadeloupe' => 'Guadeloupe',
1813
    'Guam' => 'Guam',
1814
    'Guatemala' => 'Guatemala',
1815
    'Guinea' => 'Guinea',
1816
    'Guinea-Bissau' => 'Guinea-Bissau',
1817
    'Guyana' => 'Guyana',
1818
    'Haiti' => 'Haiti',
1819
    'Holy See (Vatican City)' => 'Holy See (Vatican City)',
1820
    'Honduras' => 'Honduras',
1821
    'Hong Kong' => 'Hong Kong',
1822
    'Hungary' => 'Hungary',
1823
    'Iceland' => 'Iceland',
1824
    'India' => 'India',
1825
    'Indonesia' => 'Indonesia',
1826
    'Iran' => 'Iran',
1827
    'Iraq' => 'Iraq',
1828
    'Ireland' => 'Ireland',
1829
    'Isle of Man' => 'Isle of Man',
1830
    'Israel' => 'Israel',
1831
    'Italy' => 'Italy',
1832
    'Jamaica' => 'Jamaica',
1833
    'Japan' => 'Japan',
1834
    'Jordan' => 'Jordan',
1835
    'Kazakhstan' => 'Kazakhstan',
1836
    'Korea, North' => 'Korea, North',
1837
    'Korea, South' => 'Korea, South',
1838
    'Kenya' => 'Kenya',
1839
    'Kiribati' => 'Kiribati',
1840
    'Kuwait' => 'Kuwait',
1841
    'Kyrgyzstan' => 'Kyrgyzstan',
1842
    'Laos' => 'Laos',
1843
    'Latvia' => 'Latvia',
1844
    'Lebanon' => 'Lebanon',
1845
    'Lesotho' => 'Lesotho',
1846
    'Liberia' => 'Liberia',
1847
    'Libya' => 'Libya',
1848
    'Liechtenstein' => 'Liechtenstein',
1849
    'Lithuania' => 'Lithuania',
1850
    'Luxembourg' => 'Luxembourg',
1851
    'Macau' => 'Macau',
1852
    'Macedonia' => 'Macedonia',
1853
    'Madagascar' => 'Madagascar',
1854
    'Malawi' => 'Malawi',
1855
    'Malaysia' => 'Malaysia',
1856
    'Maldives' => 'Maldives',
1857
    'Mali' => 'Mali',
1858
    'Malta' => 'Malta',
1859
    'Marshall Islands' => 'Marshall Islands',
1860
    'Martinique' => 'Martinique',
1861
    'Mauritania' => 'Mauritania',
1862
    'Mauritius' => 'Mauritius',
1863
    'Mexico' => 'Mexico',
1864
    'Micronesia' => 'Micronesia',
1865
    'Moldova' => 'Moldova',
1866
    'Monaco' => 'Monaco',
1867
    'Mongolia' => 'Mongolia',
1868
    'Montenegro' => 'Montenegro',
1869
    'Montserrat' => 'Montserrat',
1870
    'Morocco' => 'Morocco',
1871
    'Mozambique' => 'Mozambique',
1872
    'Namibia' => 'Namibia',
1873
    'Nauru' => 'Nauru',
1874
    'Nepal' => 'Nepal',
1875
    'Netherlands' => 'Netherlands',
1876
    'Netherlands Antilles' => 'Netherlands Antilles',
1877
    'New Caledonia' => 'New Caledonia',
1878
    'New Zealand' => 'New Zealand',
1879
    'Nicaragua' => 'Nicaragua',
1880
    'Niger' => 'Niger',
1881
    'Nigeria' => 'Nigeria',
1882
    'Niue' => 'Niue',
1883
    'Northern Mariana Islands' => 'Northern Mariana Islands',
1884
    'Norway' => 'Norway',
1885
    'Oman' => 'Oman',
1886
    'Pakistan' => 'Pakistan',
1887
    'Palau' => 'Palau',
1888
    'Panama' => 'Panama',
1889
    'Papua New Guinea' => 'Papua New Guinea',
1890
    'Paraguay' => 'Paraguay',
1891
    'Peru' => 'Peru',
1892
    'Philippines' => 'Philippines',
1893
    'Pitcairn Islands' => 'Pitcairn Islands',
1894
    'Poland' => 'Poland',
1895
    'Portugal' => 'Portugal',
1896
    'Puerto Rico' => 'Puerto Rico',
1897
    'Qatar' => 'Qatar',
1898
    'Reunion' => 'Reunion',
1899
    'Romania' => 'Romania',
1900
    'Russia' => 'Russia',
1901
    'Rwanda' => 'Rwanda',
1902
    'Saint Kitts and Nevis' => 'Saint Kitts and Nevis',
1903
    'Saint Lucia' => 'Saint Lucia',
1904
    'Saint Pierre and Miquelon' => 'Saint Pierre and Miquelon',
1905
    'Saint Vincent and the Grenadines' => 'Saint Vincent and the Grenadines',
1906
    'Samoa' => 'Samoa',
1907
    'San Marino' => 'San Marino',
1908
    'Sao Tome and Principe' => 'Sao Tome and Principe',
1909
    'Saudi Arabia' => 'Saudi Arabia',
1910
    'Senegal' => 'Senegal',
1911
    'Serbia' => 'Serbia',
1912
    'Seychelles' => 'Seychelles',
1913
    'Sierra Leone' => 'Sierra Leone',
1914
    'Singapore' => 'Singapore',
1915
    'Slovakia' => 'Slovakia',
1916
    'Slovenia' => 'Slovenia',
1917
    'Solomon Islands' => 'Solomon Islands',
1918
    'Somalia' => 'Somalia',
1919
    'South Africa' => 'South Africa',
1920
    'Spain' => 'Spain',
1921
    'Sri Lanka' => 'Sri Lanka',
1922
    'Sudan' => 'Sudan',
1923
    'Suriname' => 'Suriname',
1924
    'Swaziland' => 'Swaziland',
1925
    'Sweden' => 'Sweden',
1926
    'Switzerland' => 'Switzerland',
1927
    'Syria' => 'Syria',
1928
    'Taiwan' => 'Taiwan',
1929
    'Tajikistan' => 'Tajikistan',
1930
    'Tanzania' => 'Tanzania',
1931
    'Thailand' => 'Thailand',
1932
    'Togo' => 'Togo',
1933
    'Tokelau' => 'Tokelau',
1934
    'Tonga' => 'Tonga',
1935
    'Trinidad and Tobago' => 'Trinidad and Tobago',
1936
    'Tunisia' => 'Tunisia',
1937
    'Turkey' => 'Turkey',
1938
    'Turkmenistan' => 'Turkmenistan',
1939
    'Turks and Caicos Islands' => 'Turks and Caicos Islands',
1940
    'Tuvalu' => 'Tuvalu',
1941
    'Uganda' => 'Uganda',
1942
    'Ukraine' => 'Ukraine',
1943
    'United Arab Emirates' => 'United Arab Emirates',
1944
    'United Kingdom' => 'United Kingdom',
1945
    'United States' => 'United States',
1946
    'Uruguay' => 'Uruguay',
1947
    'Uzbekistan' => 'Uzbekistan',
1948
    'Vanuatu' => 'Vanuatu',
1949
    'Venezuela' => 'Venezuela',
1950
    'Vietnam' => 'Vietnam',
1951
    'Virgin Islands' => 'Virgin Islands',
1952
    'Wallis and Futuna' => 'Wallis and Futuna',
1953
    'West Bank' => 'West Bank',
1954
    'Western Sahara' => 'Western Sahara',
1955
    'Yemen' => 'Yemen',
1956
    'Zambia' => 'Zambia',
1957
    'Zimbabwe' => 'Zimbabwe',
1958
  );
1959
}
1960
1961
1962
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1963
 * Functions related to rules module
1964
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1965
1966
/**
1967
 * Action: Mark node for moderation
1968
 */
1969
function boinccore_rules_action_mark_content_for_moderation($node) {
1970
  $node->moderate = 1;
1971
  return array('node' => $node);
1972
}
1973
1974
/**
1975
 * Action: Send mail to moderators.
1976
 */
1977
function boinccore_rules_action_mail_to_moderators($settings) {
1978
  module_load_include('inc', 'rules', 'modules/system.rules');
1979
  $mailing_list = variable_get('boinc_moderator_mailing_list', '');
1980
  $force_individual_notifications = variable_get('boinc_moderator_force_individual_notifications', 0);
1981
1982
  if (!$mailing_list OR $force_individual_notifications) {
1983
    // Send individual emails to all moderators
1984
    $roles = user_roles();
1985
    $moderator_rid = array_search('moderator', $roles);
1986
    if ($moderator_rid !== FALSE) {
1987
      $settings['recipients'] = array($moderator_rid);
1988
      rules_action_mail_to_users_of_role($settings);
1989
    }
1990
    else {
1991
      watchdog(
1992
        'boinccore',
1993
        'Unable to identify members of the moderator role to send moderator notifications!',
1994
        array(),
1995
        WATCHDOG_ERROR
1996
      );
1997
    }
1998
  }
1999
  if ($mailing_list) {
2000
    $settings['to'] = $mailing_list;
2001
    rules_action_mail($settings);
2002
  }
2003
}
2004
/**
2005
 * Action "Send mail to moderators" configuration form
2006
 */
2007
function boinccore_rules_action_mail_to_moderators_form($settings = array(), &$form) {
2008
  // Select only non-anonymous user roles because anonymous users won't have emails.
2009
  rules_action_mail_to_user_form($settings, $form);
2010
}
2011
2012
2013
/**
2014
 * Action: Send mail to admins.
2015
 */
2016
function boinccore_rules_action_mail_to_admins($settings) {
2017
  module_load_include('inc', 'rules', 'modules/system.rules');
2018
  $mailing_list = variable_get('boinc_admin_mailing_list', '');
2019
  if (empty($mailing_list)) {
2020
    $mailing_list = variable_get('site_mail', '');
2021
    if (empty($mailing_list)) {
2022
      watchdog('boinccore',
2023
        'Attempting to email administrators, but there is no admin email list or site email to send to.', array(),
2024
        WATCHDOG_ERROR
2025
      );
2026
      return FALSE;
2027
    }
2028
  }
2029
  $settings['to'] = $mailing_list;
2030
  rules_action_mail($settings);
2031
}
2032
2033
/**
2034
 * Action "Send mail to admins" configuration form
2035
 */
2036
function boinccore_rules_action_mail_to_admins_form($settings = array(), &$form) {
2037
  rules_action_mail_to_user_form($settings, $form);
2038
}
2039
2040
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2041
 * BOINC Translation functions
2042
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
2043
2044
/*
2045
 * BOINC wrapper for string translation
2046
 */
2047
function bts($string, $args = array(), $langcode = NULL, $context = 'boinc: ', $update = TRUE) {
2048
  if (function_exists('i18nstrings_ts')) {
2049
    $string = i18nstrings_ts($context, $string, $langcode, $update);
2050
  }
2051
  if (empty($args)) {
2052
    return $string;
2053
  }
2054
  else {
2055
    // Transform arguments before inserting them.
2056
    foreach ($args as $key => $value) {
2057
      switch ($key [0]) {
2058
        case '@':
2059
          // Escaped only.
2060
          $args [$key] = check_plain($value);
2061
          break;
2062
2063
        case '%':
2064
        default:
2065
          // Escaped and placeholder.
2066
          $args [$key] = theme('placeholder', $value);
2067
          break;
2068
2069
        case '!':
2070
          // Pass-through.
2071
      }
2072
    }
2073
    return strtr($string, $args);
2074
  }
2075
}
2076
2077
2078
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2079
 * Pane content for panels
2080
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
2081
2082
/**
2083
 * Overview of moderation queues
2084
 */
2085
function boinccore_moderation_overview_panel() {
2086
  $output = '<h2 class="pane-title">' . bts('Moderation', array(), NULL, 'boinc:moderate-profiles') . '</h2>';
2087
  $output .= '<ul class="tab-list action-list">';
2088
  if (module_exists('user_profiles')) {
2089
    $profile_count = db_result(db_query("
2090
      SELECT COUNT(DISTINCT(n.nid))
2091
      FROM {node} n
2092
      WHERE n.type = 'profile' AND n.moderate = 1"
2093
    ));
2094
    $output .= '<li class="tab primary">';
2095
    $output .= l(bts('Unvetted profiles', array(), NULL, 'boinc:moderate-profiles'), 'moderate/profiles');
2096
    $output .= '<div class="item-count-wrapper">';
2097
    $output .= '<span class="item-count">' . $profile_count . '</span>';
0 ignored issues
show
Bug introduced by
Are you sure $profile_count of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2097
    $output .= '<span class="item-count">' . /** @scrutinizer ignore-type */ $profile_count . '</span>';
Loading history...
2098
    $output .= '</div>';
2099
    $output .= '</li>';
2100
  }
2101
  $output .= '</ul>';
2102
  return $output;
2103
}
2104
2105
2106
/**
2107
 * Utility function to delete expired tokens in the BOINC database,
2108
 * token table.
2109
 *
2110
 */
2111
function  _boinccore_delete_expired_tokens() {
2112
  require_boinc('boinc_db');
2113
2114
  $num_deleted = BoincToken::delete_expired();
2115
  if ($num_deleted>0) {
2116
    watchdog('boinccore', "Deleted ${num_deleted} tokens from table token", WATCHDOG_NOTICE);
2117
  }
2118
}
2119