boincimport_posts_op()   F
last analyzed

Complexity

Conditions 17
Paths 322

Size

Total Lines 181
Code Lines 97

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 97
nc 322
nop 3
dl 0
loc 181
rs 2.3521
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
// Drupal forums are represented as a hierarchy of terms in a vocabulary. This
5
// is accomplished through the taxonomy concept (see: http://drupal.org/node/774892).
6
// The forum vocabulary has categories as terms (e.g. "Discussion", "Help Desk")
7
// and subsequent sub terms that belong to one of these parent terms. This allows
8
// an arbitrary number of layers to exist in forum organization. BOINC forums map
9
// to Drupal as follows:
10
//
11
//   Category -> Root level term in the vocabulary
12
//   Topic / forum -> Term in the vocabulary with parent term
13
//   Thread -> Content node
14
//   Post -> Comment
15
16
ini_set('memory_limit', '256M');
17
18
/**
19
 * Implementation of hook_menu()
20
 */
21
function boincimport_menu() {
22
  $items = array();
23
24
  $items['admin/boinc/import'] = array(
25
    'title' => 'Environment: Data import',
26
    'description' => 'Overview of the BOINC data import process.',
27
    'access callback' => 'user_access',
28
    'access arguments' => array('import boinc data'),
29
    'page callback' => 'boincimport_main',
30
    'file' => 'boincimport.pages.inc',
31
    'type' => MENU_NORMAL_ITEM,
32
  );
33
  $items['admin/boinc/import/post_configuration'] = array(
34
    'title' => 'Post-migration configuration',
35
    'description' => 'Tie up a few odds and ends in the system configuration
36
      after data importation is complete.',
37
    'access callback' => 'user_access',
38
    'access arguments' => array('import boinc data'),
39
    'page callback' => 'boincimport_post_configuration',
40
    'file' => 'boincimport.pages.inc',
41
    'type' => MENU_CALLBACK,
42
  );
43
  $items['admin/boinc/import/cleanup'] = array(
44
    'title' => 'Cleanup',
45
    'access callback' => 'user_access',
46
    'access arguments' => array('import boinc data'),
47
    'page callback' => 'boincimport_cleanup',
48
    'type' => MENU_CALLBACK,
49
  );
50
  $items['admin/boinc/import/complete/%'] = array(
51
    'title' => 'Complete',
52
    'access callback' => 'user_access',
53
    'access arguments' => array('import boinc data'),
54
    'page callback' => 'boincimport_complete',
55
    'page arguments' => array(4),
56
    'type' => MENU_CALLBACK,
57
  );
58
  $items['admin/boinc/import/process'] = array(
59
    'title' => 'Execute migration',
60
    'access callback' => 'user_access',
61
    'access arguments' => array('import boinc data'),
62
    'page callback' => 'boincimport_process',
63
    'type' => MENU_CALLBACK,
64
  );
65
  $items['admin/boinc/import/reset'] = array(
66
    'title' => 'Reset BOINC database URL',
67
    'access callback' => 'user_access',
68
    'access arguments' => array('import boinc data'),
69
    'page callback' => 'boincimport_reset',
70
    'type' => MENU_CALLBACK,
71
  );
72
  $items['admin/boinc/import/unlock'] = array(
73
    'title' => 'Unlock BOINC import process',
74
    'access callback' => 'user_access',
75
    'access arguments' => array('import boinc data'),
76
    'page callback' => 'boincimport_unlock',
77
    'type' => MENU_CALLBACK,
78
  );
79
  $items['admin/boinc/import/settings'] = array(
80
    'title' => 'BOINC data import settings',
81
    'description' => 'Configure the BOINC data import process in preparation
82
      for pulling user accounts, teams, and forums into Drupal.',
83
    'access callback' => 'user_access',
84
    'access arguments' => array('import boinc data'),
85
    'page callback' => 'drupal_get_form',
86
    'page arguments' => array('boincimport_admin_settings'),
87
    'file' => 'boincimport.pages.inc',
88
    'type' => MENU_CALLBACK,
89
  );
90
  return $items;
91
}
92
93
/**
94
 * Implementation of hook_perm()
95
 */
96
function boincimport_perm() {
97
  return array('import boinc data');
98
}
99
100
/**
101
 * Callback admin/boinc/import/reset
102
 */
103
function boincimport_reset() {
104
  global $db_url;
105
  $boinc_db_url = (is_array($db_url)) ? (isset($db_url['boinc_rw']) ? $db_url['boinc_rw'] : $db_url['default']) : $db_url;
106
  variable_set('boincimport_db_url', $boinc_db_url);
107
  variable_set('boincimport_ready', 0);
108
  return '<p>'. t('The BOINC database URL has been reset. You may now <a href="@configlink">go back to the configuration page</a>.',
109
      array('@configlink' => url('admin/boinc/import/settings'))) .'</p>';
110
}
111
112
/**
113
 * Callback admin/boinc/import/unlock
114
 */
115
function boincimport_unlock() {
116
  variable_del('boincimport_process_locked');
117
  return '<p>'. t('The BOINC data import process has been unlocked. You may
118
    now !proceed_with_import.', array(
119
      '!proceed_with_import' => l(t('proceed with the import'),
120
        'admin/boinc/import/process')
121
    )) .'</p>';
122
}
123
124
/**
125
 * Callback admin/boinc/import/cleanup
126
 */
127
function boincimport_cleanup() {
128
  return boincimport_process_cleanup() .'<p>'. t('Drupal database cleaned.') .'</p>';
0 ignored issues
show
Bug introduced by
Are you sure the usage of boincimport_process_cleanup() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
129
}
130
131
/**
132
 * Set database connection for boincimport
133
 *
134
 * @return
135
 *   1 if can connect to BOINC database.
136
 *
137
 * BEWARE: if you test using db_connect and the connection
138
 * fails, the process will die() which is a bit too much since we only
139
 * want to test. Therefore, the test part of the code is not used, now.
140
 */
141
function _boincimport_db_connect($test= 0) {
142
  global $db_url;
143
  $db_ready = variable_get('boincimport_db_configured', 1);
144
  if (!$db_ready) {
145
    if (is_array($db_url)) {
146
      $db_url2 = $db_url;
147
    } else {
148
      $db_url2['default'] = $db_url;
149
    }
150
    $db_url2['boinc_rw'] = variable_get('boincimport_db_url', $db_url);
151
    $GLOBALS['db_url'] =& $db_url2;
152
    if ($test) {
153
      if (!db_connect($db_url2['boinc_rw'])) {
154
        return 0;
155
      }
156
    }
157
  }
158
  return 1;
159
160
}
161
162
/**
163
 * Check if the module is enabled.
164
 *
165
 * @return array
166
 *    $out['html'] = formatted html.
167
 *    $out['result'] = boolean.
168
 */
169
function _boincimport_check_module($module) {
170
  $out['html'] = '<ul>';
171
  $result = module_exists($module);
172
  $out['result'] = $result;
173
  if ($result == 1) {
174
    $out['html'] .= '<li>'. t('Module %module is enabled. OK!', array('%module' => $module)) .'</li>';
175
  }
176
  else {
177
    $out['html'] .= '<li><span class="marker">'. t('Module %module is disabled.', array('%module' => $module)) .'</span></li>';
178
  }
179
  $out['html'] .= '</ul>';
180
  return $out;
181
}
182
183
/**
184
 * Check if the sql tables are installed.
185
 *
186
 * @return array
187
 *   $out['html'] = formatted html.
188
 *   $out['result'] = boolean.
189
 */
190
function _boincimport_check_tables($tables = array(), $db = 'default' , $prefix = 1) {
191
  _boincimport_db_connect();
192
193
  $out['html'] = '<ul>';
194
  $out['result']= 1;
195
  foreach ($tables as $table) {
196
    if ($prefix) {
197
      $table = db_prefix_tables('{'. $table .'}');
198
    }
199
200
    db_set_active($db);
201
    if ($GLOBALS['db_type'] == 'pgsql') {
202
      // adapt from db_table_exists in database.pgsql.inc
203
      $result = (bool) db_result(db_query("SELECT COUNT(*) FROM pg_class WHERE relname = '%s'", $table));
204
    }
205
    else {
206
      // adapt from db_table_exists in database.mysql.inc
207
      $result = (bool) db_fetch_object(db_query("SHOW TABLES LIKE '%s'", $table));
208
    }
209
    db_set_active('default');
210
    if ($result) {
211
      $out['html'] .= '<li>'. t('Table %table: OK!', array('%table' => $table)) .'</li>';
212
    }
213
    else {
214
      $out['html'] .= '<li><span class="marker">'. t('Table <strong>%table</strong> does not exist!', array('%table' => $table)) .'</span></li>';
215
      $out['result']= 0;
216
    }
217
  }
218
  $out['html'] .= '</ul>';
219
  return $out;
220
}
221
222
223
224
function boincimport_process() {
225
  // Start with a quick sanity check on the BOINC environment
226
  boinc_get_path();
227
228
  if (!variable_get('boincimport_ready', 0)) {
229
    return '<p>'. t('You cannot import the data now. Please <a href="@settings">complete the setup first</a>', array('@settings' => url('admin/boinc/import/settings'))) .'</p>';
230
  }
231
232
  $output = 'BOINC import process form';
233
  $output .= drupal_get_form('boincimport_process_form');
234
  return $output;
235
}
236
237
function boincimport_process_form() {
238
  $form = array();
239
  _boincimport_db_connect() ;
240
  // Causes problems with form api redirect
241
  //ini_set('display_errors', TRUE);
242
243
  // Adjust how long you want the script to run...
244
  if (!ini_get('safe_mode')) {
245
    // This will always be set on PHP7, but not on PHP5 with safe mode
246
    set_time_limit(variable_get('boincimport_time_limit', 0));
247
  }
248
249
  // Check for a lock on the import process
250
  if (variable_get('boincimport_process_locked', 0)) {
251
    drupal_set_message(t('The import process is locked. If you are sure that
252
      it is no longer running, you may !unlock_it',
253
      array('!unlock_it' => l(t('release the lock'),
254
        'admin/boinc/import/unlock')
255
      )), 'warning');
256
    watchdog('boincimport', 'The import process is locked. If you are sure that
257
      it is no longer running, you may !unlock_it',
258
      array('!unlock_it' => l(t('release the lock'),
259
        'admin/boinc/import/unlock')
260
      ), WATCHDOG_WARNING);
261
  }
262
  else {
263
    $boincimport_functions = array(
264
      'users' => t('Import users'),
265
      'teams' => t('Import teams'),
266
      'friends' => t('Import friendships'),
267
      'preferences' => t('Import user preferences'),
268
      'private messages' => t('Import private messages'),
269
      'categories' => t('Import forum containers'),
270
      'topics' => t('Import topics'),
271
      'posts' => t('Import posts'),
272
      'team forums' => t('Import team forums'),
273
      'team topics' => t('Import team topics'),
274
      'team posts' => t('Import team posts'),
275
      'url' => t('Transform URLs'),
276
    );
277
278
    $form['import'] = array(
279
      '#type' => 'select',
280
      '#title' => t('Next import to perform'),
281
      '#default_value' => $_SESSION['boincimport_stage_selected'],
282
      '#options' => $boincimport_functions,
283
    );
284
    $form[] = array(
285
      '#type' => 'submit',
286
      '#value' => t('Import'),
287
    );
288
  }
289
  return $form;
290
}
291
292
function boincimport_process_form_submit($form, $form_state) {
293
294
  // Lock the import process
295
  if (!variable_get('boincimport_process_locked', 0)) {
296
    variable_set('boincimport_process_locked', 1);
297
  }
298
  else {
299
    watchdog('boincimport', 'The import process is locked, but another process
300
      is trying to access it...', array(), WATCHDOG_WARNING);
301
  }
302
303
  switch ($form_state['values']['import']) {
304
    case 'users':
305
      boincimport_users();
306
      break;
307
308
    case 'teams':
309
      boincimport_teams();
310
      if (!variable_get('boincimport_import_team_successful', 0)) {
311
        $_SESSION['boincimport_stage_selected'] = 'teams';
312
      }
313
      else {
314
        $_SESSION['boincimport_stage_selected'] = 'friends';
315
      }
316
      break;
317
318
    case 'friends':
319
      boincimport_friends();
320
      if (!variable_get('boincimport_import_friend_successful', 0)) {
321
        $_SESSION['boincimport_stage_selected'] = 'friends';
322
      }
323
      else {
324
        $_SESSION['boincimport_stage_selected'] = 'preferences';
325
      }
326
      break;
327
328
    case 'preferences':
329
      boincimport_preferences();
330
      if (!variable_get('boincimport_import_preferences_successful', 0)) {
331
        $_SESSION['boincimport_stage_selected'] = 'preferences';
332
      }
333
      else {
334
        $_SESSION['boincimport_stage_selected'] = 'private messages';
335
      }
336
      break;
337
338
    case 'private messages':
339
      boincimport_private_msgs();
340
      if (!variable_get('boincimport_import_private_msg_successful', 0)) {
341
        $_SESSION['boincimport_stage_selected'] = 'private messages';
342
      }
343
      else {
344
        $_SESSION['boincimport_stage_selected'] = 'categories';
345
      }
346
      break;
347
348
    case 'categories':
349
      boincimport_forum_categories();
350
      if (!variable_get('boincimport_import_category_successful', 0)) {
351
        $_SESSION['boincimport_stage_selected'] = 'categories';
352
      }
353
      else {
354
        $_SESSION['boincimport_stage_selected'] = 'topics';
355
      }
356
      break;
357
358
    case 'topics':
359
      boincimport_forum_topics();
360
      if (!variable_get('boincimport_import_topic_successful', 0)) {
361
        $_SESSION['boincimport_stage_selected'] = 'topics';
362
      }
363
      else {
364
        $_SESSION['boincimport_stage_selected'] = 'posts';
365
      }
366
      break;
367
368
    case 'posts':
369
      boincimport_forum_posts();
370
      if (!variable_get('boincimport_import_post_successful', 0)) {
371
        $_SESSION['boincimport_stage_selected'] = 'posts';
372
      }
373
      else {
374
        $_SESSION['boincimport_stage_selected'] = 'url';
375
      }
376
      break;
377
378
    case 'team forums':
379
      boincimport_team_forums();
380
      if (!variable_get('boincimport_team_forum_successful', 0)) {
381
        $_SESSION['boincimport_stage_selected'] = 'team forums';
382
      }
383
      else {
384
        $_SESSION['boincimport_stage_selected'] = 'team topics';
385
      }
386
      break;
387
388
    case 'team topics':
389
      boincimport_team_forum_topics();
390
      if (!variable_get('boincimport_team_topic_successful', 0)) {
391
        $_SESSION['boincimport_stage_selected'] = 'team topics';
392
      }
393
      else {
394
        $_SESSION['boincimport_stage_selected'] = 'team posts';
395
      }
396
      break;
397
398
    case 'team posts':
399
      boincimport_team_forum_posts();
400
      if (!variable_get('boincimport_team_post_successful', 0)) {
401
        $_SESSION['boincimport_stage_selected'] = 'team posts';
402
      }
403
      else {
404
        $_SESSION['boincimport_stage_selected'] = 'url';
405
      }
406
      break;
407
408
    case 'url':
409
      boincimport_replace_urls();
410
      if (!variable_get('boincimport_replace_url_successful', 0)) {
411
        $_SESSION['boincimport_stage_selected'] = 'url';
412
      }
413
      else {
414
        drupal_set_message('Congratulations.  Import Finished');
415
        drupal_set_message('Please visit the '. l('Post migration configuration', 'admin/boinc/import/post_configuration') .' page');
416
        watchdog('boincimport', 'Import process is complete', array(), WATCHDOG_INFO);
417
        unset($_SESSION['boincimport_stage_selected']);
418
      }
419
      break;
420
    default:
421
      $_SESSION['boincimport_stage_selected'] = 'users';
422
      break;
423
  }
424
}
425
426
function boincimport_complete($section) {
427
  switch ($section) {
428
  case 'users':
429
    // Set the user import successful flag in the variable table
430
    variable_set('boincimport_import_user_successful', '1');
431
    $_SESSION['boincimport_stage_selected'] = 'teams';
432
    break;
433
  case 'teams':
434
435
    break;
436
437
  default:
438
  }
439
440
  // Release the lock on the import process
441
  variable_del('boincimport_process_locked');
442
443
  drupal_goto('admin/boinc/import/process');
444
}
445
446
447
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
448
 * Users
449
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
450
451
/**
452
 * Import users (at least those required for further data import)
453
 */
454
function boincimport_users() {
455
  // Check whether the user table has been successfully imported already
456
  if (variable_get('boincimport_import_user_successful', 0)) {
457
    drupal_set_message(t('Note: user import has already run successfully'));
458
    watchdog(
459
      'boincimport', 'Note: user import has already run successfully',
460
      array(), WATCHDOG_INFO
461
    );
462
  }
463
464
  if (!variable_get('boincimport_import_user_started', 0)) {
465
    // Could prepare database tables, if new fields are necessary, etc.
466
    variable_set('boincimport_import_user_started', 1);
467
  }
468
469
  $pre = variable_get('boincimport_table_prefix', '');
470
  $import_lurkers = variable_get('boincimport_import_lurkers', 1);
471
472
  // Determine which users need to be processed
473
  db_set_active('boinc_rw');
474
  if ($import_lurkers) {
475
    // Import all users, even those who have no community participation; other
476
    // users will be imported when they first try to log into the drupal site
477
    $boinc_accounts = db_query('
478
      SELECT id FROM {user}
479
      ORDER BY id ASC'
480
    );
481
    $user_count = mysqli_num_rows($boinc_accounts);
0 ignored issues
show
Bug introduced by
$boinc_accounts of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

481
    $user_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boinc_accounts);
Loading history...
482
  }
483
  else {
484
    // Need to import any user who is currently ignored in order to keep them
485
    // ignored... not particularly clean (ignored users are stored in a string)
486
    $ignored_user_list = array(0);
487
    $ignoring_users = db_query("
488
      SELECT ignorelist
489
      FROM forum_preferences
490
      WHERE ignorelist <> ''
491
      ORDER BY userid ASC"
492
    );
493
    while ($ignoring_user = db_fetch_object($ignoring_users)) {
494
      $ignored_user_list = $ignored_user_list + array_fill_keys(explode('|', trim($ignoring_user->ignorelist, '|')), 1);
495
    }
496
    $ignored_user_list = array_keys($ignored_user_list);
497
    // Get IDs for all users who will need to be imported now
498
    $boinc_accounts = db_query("
499
      SELECT id FROM
500
      (
501
        (SELECT id FROM {user} WHERE teamid > 0 OR id IN(%s)) UNION
502
        (SELECT DISTINCT user FROM {post}) UNION
503
        (SELECT DISTINCT userid FROM {subscriptions}) UNION
504
        (SELECT DISTINCT user_src FROM {friend} WHERE reciprocated = 1) UNION
505
        (SELECT DISTINCT user_dest FROM {friend} WHERE reciprocated = 1) UNION
506
        (SELECT DISTINCT userid FROM {forum_preferences} WHERE ignorelist <> '') UNION
507
        (SELECT DISTINCT userid FROM {private_messages}) UNION
508
        (SELECT DISTINCT senderid FROM {private_messages})
509
      ) AS usersToImport",
510
      implode(',', $ignored_user_list)
511
    );
512
    $user_count = mysqli_num_rows($boinc_accounts);
513
  }
514
  db_set_active('default');
515
516
  if (!$user_count) {
517
    drupal_set_message(
518
      t('There were no users found: Aborting script'), 'error'
519
    );
520
    watchdog('boincimport',
521
      'There were no users found: Aborting script', array(), WATCHDOG_INFO
522
    );
523
    // Release the lock on the import process
524
    variable_del('boincimport_process_locked');
525
    return t('There were no users found: Aborting script.');
526
  }
527
528
  watchdog('boincimport',
529
    'Found %user_count users: Beginning import',
530
    array('%user_count' => $user_count), WATCHDOG_INFO
531
  );
532
533
  // User import relies on Drupal and BOINC APIs to manage data being read
534
  // from one database and saved to the other. This approach keeps things
535
  // clean and simple, but since a sizable user base will wreak havoc on system
536
  // resources, the job is broken into batches here and each batch is processed
537
  // by a separate process.
538
539
  //$batch_size = variable_get('boincimport_user_batch_size', 50);
540
  //$batch_count = $user_count - ($user_count % $batch_size) + $batch_size;
541
  $operations = array();
542
  $existing_users = array();
543
  $duplicates = array();
544
545
  // Get the list of users already in Drupal to be sure we're not importing
546
  // any twice
547
  $result = db_query('
548
    SELECT uid, boinc_id FROM {boincuser}'
549
  );
550
  while ($row = db_fetch_object($result)) {
551
    $existing_users[$row->boinc_id] = $row->uid;
552
  }
553
554
  // Create batches to process
555
  while ($boinc_account = db_fetch_object($boinc_accounts)) {
556
     if (isset($existing_users[$boinc_account->id])) {
557
      // This user has already been imported
558
      $duplicates[] = $boinc_account->id;
559
    }
560
    else {
561
      $operations[] = array(
562
        'boincimport_users_op', array(
563
          $boinc_account->id
564
        )
565
      );
566
    }
567
  }
568
569
  if ($duplicates) {
570
    drupal_set_message(t(
571
      'Skipped @count accounts that were already imported',
572
      array('@count' => count($duplicates))
573
    ));
574
    watchdog('boincimport',
575
      'Skipped @count accounts that were already imported',
576
      array('@count' => count($duplicates)), WATCHDOG_INFO
577
    );
578
  }
579
580
  $batch = array(
581
    'operations' => $operations,
582
    'finished' => 'boincimport_users_finished',
583
    'title' => t('Importing users'),
584
    'init_message' => t('Beginning user import...'),
585
    'progress_message' => t('Processed @current out of @total users.'),
586
    'error_message' => t('User import has encountered an error.'),
587
  );
588
589
  batch_set($batch);
590
}
591
592
/**
593
 * Batch operation for importing users
594
 */
595
function boincimport_users_op($boinc_id, &$context) {
596
597
  // Use the $context['sandbox'] to store information needed to track progress
598
  // between successive calls.
599
  if (!isset($context['sandbox']['progress'])) {
600
    $context['sandbox']['progress'] = 0;
601
    $context['sandbox']['current_user'] = 0;
602
    $context['sandbox']['max'] = 1;
603
  }
604
605
  // Note about batch size: When a batch is processed, the batch update engine
606
  // determines whether it should continue processing in the same request or
607
  // provide progress feedback to the user and wait for the next request.
608
609
  // Grab the BOINC user object and create a Drupal user from it
610
  $account = boincuser_register_make_drupal_user($boinc_id);
611
  $message = '';
612
  if ($account) {
613
    // Store some result for post-processing in the finished callback.
614
    $context['results']['success'][] = $boinc_id;
615
    $message = "Successfully imported user {$boinc_id}";
616
  }
617
  else {
618
    $context['results']['failure'][] = $boinc_id;
619
    $message = "Failed to import user {$boinc_id}!";
620
    watchdog('boincimport',
621
      'Failed to import user @id!',
622
      array('@id' => $boinc_id), WATCHDOG_WARNING
623
    );
624
  }
625
626
  // Update our progress information.
627
  $context['sandbox']['progress']++;
628
  $context['sandbox']['current_user'] = $boinc_id;
629
  $context['message'] = $message;
630
631
  // Update the progress for the batch engine
632
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
633
    $context['finished'] = 1;
634
  }
635
  else {
636
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
637
  }
638
}
639
640
/**
641
 * Batch 'finished' callback
642
 */
643
function boincimport_users_finished($success, $results, $operations) {
644
  if ($success) {
645
    // Let's count our successes
646
    $total_imported = count($results['success']);
647
    $total_failures = count($results['failure']);
648
    $message = t(
649
      'Successfully imported @count users (@fail_count failures)',
650
      array('@count' => $total_imported, '@fail_count' => $total_failures)
651
    );
652
    watchdog('boincimport',
653
      'Successfully imported @count users (@fail_count failures).',
654
      array('@count' => $total_imported, '@fail_count' => $total_failures),
655
      WATCHDOG_INFO
656
    );
657
    // Set the user import successful flag in the variable table
658
    variable_set('boincimport_import_user_successful', '1');
659
    $_SESSION['boincimport_stage_selected'] = 'teams';
660
  }
661
  else {
662
    // An error occurred.
663
    // $operations contains the operations that remained unprocessed.
664
    $error_operation = reset($operations);
665
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

665
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
666
  }
667
  drupal_set_message($message);
668
669
  // Release the lock on the import process
670
  variable_del('boincimport_process_locked');
671
  drupal_goto('admin/boinc/import/process');
672
}
673
674
675
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
676
 * Teams
677
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
678
679
/**
680
 * Create teams and assign members
681
 */
682
function boincimport_teams() {
683
684
  // Check whether the team table has been successfully imported already
685
  if (variable_get('boincimport_import_team_successful', 0)) {
686
    drupal_set_message(t('Note: team import has already run successfully'));
687
    watchdog(
688
      'boincimport', 'Note: team import has already run successfully',
689
      array(), WATCHDOG_INFO
690
    );
691
  }
692
693
  if (!variable_get('boincimport_import_team_started', 0)) {
694
    // Could prepare database tables, if new fields are necessary, etc.
695
    variable_set('boincimport_import_team_started', 1);
696
  }
697
698
  // Initialize the map of BOINC team types to taxonomy IDs, if needed
699
  $team_type_map = variable_get('boincimport_team_types', array());
700
  if (!$team_type_map) {
701
    // Import team types from BOINC to a Drupal vocabulary
702
    require_boinc('team_types');
703
    global $team_types;
704
705
    // Create vocabulary if it isn't set
706
    $team_vid = db_result(db_query('SELECT vid FROM {vocabulary} WHERE name="%s"', 'Teams'));
707
    if (!$team_vid) {
708
      $team_vocab = array(
709
        'name' => t('Teams'),
710
        'description' => t('Types of BOINC teams'),
711
      );
712
      taxonomy_save_vocabulary($team_vocab);
713
      $team_vid = db_result(db_query('SELECT vid FROM {vocabulary} WHERE name="%s"', 'Teams'));
714
    }
715
716
    foreach ($team_types as $boinc_type_id => $name) {
717
      // Check for an existing term in the vocabulary
718
      $team_type_id = db_result(db_query("SELECT tid FROM {term_data} WHERE vid = '{$team_vid}' AND LOWER(name) = LOWER('%s')", trim($name)));
719
      if ($team_type_id) {
720
        $team_type = array(
721
          'tid' => $team_type_id
722
        );
723
      }
724
      else {
725
        if (!$name) continue;
726
        $team_type = array(
727
          'name' => strip_tags($name),
728
          'vid' => $team_vid,
729
          'description' => '',
730
          'parent' => 0
731
        );
732
        taxonomy_save_term($team_type);
733
      }
734
      // Note the taxonomy ID for mapping forums to categories
735
      $team_type_map[$boinc_type_id] = $team_type['tid'];
736
    }
737
    variable_set('boincimport_team_types', $team_type_map);
738
  }
739
740
  $pre = variable_get('boincimport_table_prefix', '');
741
742
  // Get the list of teams to import
743
  db_set_active('boinc_rw');
744
  $boinc_teams = db_query('
745
    SELECT id, name, description, userid, create_time
746
    FROM %steam',
747
    $pre
748
  );
749
  $team_count = mysqli_num_rows($boinc_teams);
0 ignored issues
show
Bug introduced by
$boinc_teams of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

749
  $team_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boinc_teams);
Loading history...
750
  db_set_active('default');
751
752
  if (!$team_count) {
753
    drupal_set_message(
754
      t('There were no teams found: Aborting script'), 'error'
755
    );
756
    watchdog('boincimport',
757
      'There were no teams found: Aborting script', array(), WATCHDOG_INFO
758
    );
759
    // Release the lock on the import process
760
    variable_del('boincimport_process_locked');
761
    return t('There were no teams found: Aborting script.');
762
  }
763
764
  watchdog('boincimport',
765
    'Found %team_count teams: Beginning Import',
766
    array('%team_count' => $team_count), WATCHDOG_INFO
767
  );
768
769
  $operations = array();
770
  $existing_teams = array();
771
  $duplicates = array();
772
773
  // Get the list of teams already in Drupal to be sure we're not importing
774
  // any twice
775
  $result = db_query('
776
    SELECT nid, team_id FROM {boincteam}'
777
  );
778
  while ($row = db_fetch_object($result)) {
779
    $existing_teams[$row->team_id] = $row->nid;
780
  }
781
782
  // Create batches to process
783
  while ($boinc_team = db_fetch_object($boinc_teams)) {
784
     if (isset($existing_teams[$boinc_team->id])) {
785
      // This team has already been imported
786
      $duplicates[] = $boinc_team->id;
787
    }
788
    else {
789
      $operations[] = array(
790
        'boincimport_teams_op', array(
791
          $boinc_team
792
        )
793
      );
794
    }
795
  }
796
797
  if ($duplicates) {
798
    drupal_set_message(t(
799
      'Skipped @count teams that were already imported',
800
      array('@count' => count($duplicates))
801
    ));
802
  }
803
804
  $batch = array(
805
    'operations' => $operations,
806
    'finished' => 'boincimport_teams_finished',
807
    'title' => t('Importing teams'),
808
    'init_message' => t('Beginning team import...'),
809
    'progress_message' => t('Processed @current out of @total teams.'),
810
    'error_message' => t('Team import has encountered an error.'),
811
  );
812
813
  batch_set($batch);
814
}
815
816
/**
817
 * Batch operation for importing teams
818
 * Create a Drupal node from the given BOINC team object
819
 */
820
function boincimport_teams_op($boincteam, &$context) {
821
822
  $success = boincteam_import($boincteam);
823
824
  $message = '';
825
  if ($success) {
826
    // Store some result for post-processing in the finished callback.
827
    $context['results']['success'][] = $boincteam->id;
828
    $message = "Successfully imported team {$boincteam->id}";
829
  }
830
  else {
831
    $context['results']['failure'][] = $boincteam->id;
832
    $message = "Failed to import team {$boincteam->id}!";
833
    watchdog('boincimport',
834
      'Failed to import team @id!',
835
      array('@id' => $boincteam->id), WATCHDOG_WARNING
836
    );
837
  }
838
839
  // Update our progress information.
840
  $context['sandbox']['progress']++;
841
  $context['sandbox']['current_team'] = $boincteam->id;
842
  $context['message'] = $message;
843
844
  // Update the progress for the batch engine
845
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
846
    $context['finished'] = 1;
847
  }
848
  else {
849
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
850
  }
851
}
852
853
/**
854
 * Batch 'finished' callback
855
 */
856
function boincimport_teams_finished($success, $results, $operations) {
857
  if ($success) {
858
    // Let's count our successes
859
    $total_imported = count($results['success']);
860
    $message = t(
861
      'Successfully imported @count teams',
862
      array('@count' => $total_imported)
863
    );
864
    watchdog('boincimport',
865
      'Successfully imported @count teams.',
866
      array('@count' => $total_imported), WATCHDOG_INFO
867
    );
868
    // Set the team import successful flag in the variable table
869
    variable_set('boincimport_import_team_successful', '1');
870
    $_SESSION['boincimport_stage_selected'] = 'friends';
871
  }
872
  else {
873
    // An error occurred.
874
    // $operations contains the operations that remained unprocessed.
875
    $error_operation = reset($operations);
876
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

876
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
877
  }
878
  drupal_set_message($message);
879
880
  // Release the lock on the import process
881
  variable_del('boincimport_process_locked');
882
  drupal_goto('admin/boinc/import/process');
883
}
884
885
886
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
887
 * Friends
888
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
889
890
/**
891
 * Create friend relationships between users
892
 */
893
function boincimport_friends() {
894
895
  // Check whether friendships have been successfully imported already
896
  if (variable_get('boincimport_import_friend_successful', 0)) {
897
    drupal_set_message(t('Note: Friends import has already run successfully'));
898
    watchdog(
899
      'boincimport', 'Note: Friends import has already run successfully',
900
      array(), WATCHDOG_INFO
901
    );
902
  }
903
904
  if (!variable_get('boincimport_import_friend_started', 0)) {
905
    // Could prepare database tables, if new fields are necessary, etc.
906
    variable_set('boincimport_import_friend_started', 1);
907
  }
908
909
  $pre = variable_get('boincimport_table_prefix', '');
910
911
  // Get stuff to import
912
  db_set_active('boinc_rw');
913
  $friendships = db_query('
914
    SELECT
915
      f1.user_src,
916
      f1.user_dest,
917
      f1.create_time
918
    FROM %sfriend f1
919
    LEFT JOIN %sfriend f2
920
      ON f2.user_src = f1.user_dest
921
      AND f2.user_dest = f1.user_src
922
      AND f2.user_src <> f2.user_dest
923
    WHERE f1.reciprocated = 1
924
      AND (f2.user_src IS NULL OR f1.create_time < f2.create_time)
925
    ORDER BY create_time',
926
    $pre, $pre
927
  );
928
  $friendship_count = mysqli_num_rows($friendships);
0 ignored issues
show
Bug introduced by
$friendships of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

928
  $friendship_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $friendships);
Loading history...
929
  db_set_active('default');
930
931
  if (!$friendship_count) {
932
    drupal_set_message(
933
      t('There were no friendships found: Aborting script'), 'error'
934
    );
935
    watchdog('boincimport',
936
      'There were no friendships found: Aborting script', array(), WATCHDOG_INFO
937
    );
938
    // Release the lock on the import process
939
    variable_del('boincimport_process_locked');
940
    return t('There were no friendships found: Aborting script.');
941
  }
942
943
  watchdog('boincimport',
944
    'Found %count friend relationships: Beginning Import',
945
    array('%count' => $friendship_count), WATCHDOG_INFO
946
  );
947
948
  $operations = array();
949
950
  // It doesn't matter if a friend relationship has already been imported, just
951
  // do it again if so
952
953
  // Create batches to process
954
  while ($friendship = db_fetch_object($friendships)) {
955
    $operations[] = array(
956
      'boincimport_friends_op', array(
957
        $friendship
958
      )
959
    );
960
  }
961
962
  $batch = array(
963
    'operations' => $operations,
964
    'finished' => 'boincimport_friends_finished',
965
    'title' => t('Importing friend relationships'),
966
    'init_message' => t('Beginning friend import...'),
967
    'progress_message' => t('Processed @current out of @total friendships.'),
968
    'error_message' => t('Friend import has encountered an error.'),
969
  );
970
971
  batch_set($batch);
972
}
973
974
/**
975
 * Batch operation for importing friendships
976
 * Create Drupal flags from the given BOINC friend relationship
977
 */
978
function boincimport_friends_op($friendship, &$context) {
979
980
  $input_format = variable_get('boincimport_input_format', 0);
981
  $success = FALSE;
982
  $message = '';
983
984
  // Convert BOINC friends to Drupal friends
985
  $uid = boincuser_lookup_uid($friendship->user_src);
986
  $friend_uid = boincuser_lookup_uid($friendship->user_dest);
987
  if ($uid AND $friend_uid) {
988
    $success = db_query("
989
      INSERT IGNORE INTO {flag_friend}
990
      SET uid = '%d', friend_uid = '%d', created = '%d'",
991
      $uid, $friend_uid, $friendship->create_time
992
    );
993
  }
994
  else {
995
    $boinc_id = ($uid) ? $friendship->user_dest : $friendship->user_src;
996
    $message = "No Drupal account exists for BOINC user {$boinc_id}!";
997
  }
998
999
  if ($success) {
1000
    // Store some result for post-processing in the finished callback.
1001
    $context['results']['success'][] = $uid;
1002
    $message = "Successfully made users {$uid} and {$friend_uid} friends";
1003
  }
1004
  else {
1005
    $context['results']['failure'][] = $uid;
1006
    if (!$message) {
1007
      $message = "Failed to make users {$uid} and {$friend_uid} friends!";
1008
    }
1009
    watchdog('boincimport', $message, array(), WATCHDOG_WARNING);
1010
  }
1011
1012
  // Update our progress information.
1013
  $context['sandbox']['progress']++;
1014
  $context['sandbox']['current_user'] = $uid;
1015
  $context['message'] = $message;
1016
1017
  // Update the progress for the batch engine
1018
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
1019
    $context['finished'] = 1;
1020
  }
1021
  else {
1022
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
1023
  }
1024
}
1025
1026
/**
1027
 * Batch 'finished' callback
1028
 */
1029
function boincimport_friends_finished($success, $results, $operations) {
1030
  if ($success) {
1031
    // Let's count our successes
1032
    $total_imported = count($results['success']);
1033
    $failures = count($results['failure']);
1034
    $message = t(
1035
      'Successfully imported @count friendships (@failed failures)',
1036
      array(
1037
        '@count' => $total_imported,
1038
        '@failed' => $failures,
1039
      )
1040
    );
1041
    watchdog('boincimport', $message, array(), WATCHDOG_INFO);
1042
    // Set the friend import successful flag in the variable table
1043
    variable_set('boincimport_import_friend_successful', '1');
1044
    $_SESSION['boincimport_stage_selected'] = 'preferences';
1045
  }
1046
  else {
1047
    // An error occurred.
1048
    // $operations contains the operations that remained unprocessed.
1049
    $error_operation = reset($operations);
1050
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

1050
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
1051
  }
1052
  drupal_set_message($message);
1053
1054
  // Release the lock on the import process
1055
  variable_del('boincimport_process_locked');
1056
  drupal_goto('admin/boinc/import/process');
1057
}
1058
1059
1060
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1061
 * Community preferences
1062
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1063
1064
/**
1065
 * Import community preferences for users
1066
 */
1067
function boincimport_preferences() {
1068
1069
  // Check whether preferences have been successfully imported already
1070
  if (variable_get('boincimport_import_preferences_successful', 0)) {
1071
    drupal_set_message(t('Note: preferences import has already run successfully'));
1072
    watchdog(
1073
      'boincimport', 'Note: preferences import has already run successfully',
1074
      array(), WATCHDOG_INFO
1075
    );
1076
  }
1077
1078
  if (!variable_get('boincimport_import_preferences_started', 0)) {
1079
    // Could prepare database tables, if new fields are necessary, etc.
1080
    variable_set('boincimport_import_preferences_started', 1);
1081
  }
1082
1083
  $pre = variable_get('boincimport_table_prefix', '');
1084
1085
  // Currently the only preferences being imported are BOINC "filtered users"
1086
  // This concept of users blocking other users when they don't get along maps
1087
  // to the Drupal ignore users module
1088
1089
  // Find users who are involved in quarrels
1090
  db_set_active('boinc_rw');
1091
  $quarrelers = db_query("
1092
    SELECT userid, ignorelist
1093
    FROM %sforum_preferences
1094
    WHERE ignorelist <> ''",
1095
    $pre
1096
  );
1097
  $quarreler_count = mysqli_num_rows($quarrelers);
0 ignored issues
show
Bug introduced by
$quarrelers of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

1097
  $quarreler_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $quarrelers);
Loading history...
1098
  db_set_active('default');
1099
1100
  if (!$quarreler_count) {
1101
    drupal_set_message(
1102
      t('There were no quarrels found: Moving on...')
1103
    );
1104
    watchdog('boincimport',
1105
      'There were no quarrels found: Moving on...', array(), WATCHDOG_INFO
1106
    );
1107
    // Release the lock on the import process
1108
    variable_del('boincimport_process_locked');
1109
    return t('There were no quarrels found: Moving on...');
1110
  }
1111
1112
  watchdog('boincimport',
1113
    'Found %count quarreling users: Beginning Import',
1114
    array('%count' => $quarreler_count), WATCHDOG_INFO
1115
  );
1116
1117
  $operations = array();
1118
1119
  // It doesn't matter if a filtered user preference has already been imported,
1120
  // just do it again if so
1121
1122
  // Create batches to process
1123
  while ($quarreler = db_fetch_object($quarrelers)) {
1124
    $operations[] = array(
1125
      'boincimport_quarrels_op', array(
1126
        $quarreler
1127
      )
1128
    );
1129
  }
1130
1131
  $batch = array(
1132
    'operations' => $operations,
1133
    'finished' => 'boincimport_preferences_finished',
1134
    'title' => t('Importing preferences'),
1135
    'init_message' => t('Beginning preference import...'),
1136
    'progress_message' => t('Processed @current out of @total preferences.'),
1137
    'error_message' => t('Preference import has encountered an error.'),
1138
  );
1139
1140
  batch_set($batch);
1141
}
1142
1143
/**
1144
 * Batch operation for importing ignored user settings
1145
 * Convert BOINC ignored users to Drupal ignored users
1146
 */
1147
function boincimport_quarrels_op($boinc_user, &$context) {
1148
1149
  $success = FALSE;
1150
  $uid = boincuser_lookup_uid($boinc_user->userid);
1151
  $ignored_users = explode('|', trim($boinc_user->ignorelist, '|'));
1152
  foreach ($ignored_users as $ignored_user) {
1153
    $ignored_user_uid = boincuser_lookup_uid($ignored_user);
1154
    if (!$ignored_user_uid) {
1155
      $context['results']['warning'][] = "{$uid}:{$ignored_user_uid}";
1156
      watchdog('boincimport',
1157
        'Error adding to ignore list of user @uid: No Drupal ID found for BOINC user @boinc_id',
1158
        array('@boinc_id' => $ignored_user, '@uid' => $uid),
1159
        WATCHDOG_WARNING
1160
      );
1161
      continue;
1162
    }
1163
    $user_ignored = db_query("
1164
      INSERT IGNORE INTO {ignore_user}
1165
      SET uid = '%d', iuid = '%d'",
1166
      $uid, $ignored_user_uid
1167
    );
1168
    if ($user_ignored) {
1169
      $success = TRUE;
1170
    }
1171
    else {
1172
      $context['results']['warning'][] = "{$uid}:{$ignored_user_uid}";
1173
      watchdog('boincimport',
1174
        'Could not add user @ignored_uid to the ignore list of user @uid',
1175
        array('@ignored_uid' => $ignored_user_uid, '@uid' => $uid),
1176
        WATCHDOG_WARNING
1177
      );
1178
    }
1179
  }
1180
1181
  $message = '';
1182
  if ($success) {
1183
    // Store some result for post-processing in the finished callback.
1184
    $context['results']['success'][] = $uid;
1185
    $message = "Successfully imported ignored users for user {$uid}";
1186
  }
1187
  else {
1188
    $context['results']['failure'][] = $uid;
1189
    $message = "Failed to import any user filter preferences for user {$uid}!";
1190
    watchdog('boincimport',
1191
      'Failed to import any user filter preferences for user @id!',
1192
      array('@id' => $uid), WATCHDOG_WARNING
1193
    );
1194
  }
1195
1196
  // Update our progress information.
1197
  $context['sandbox']['progress']++;
1198
  $context['sandbox']['current_user'] = $uid;
1199
  $context['message'] = $message;
1200
1201
  // Update the progress for the batch engine
1202
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
1203
    $context['finished'] = 1;
1204
  }
1205
  else {
1206
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
1207
  }
1208
}
1209
1210
/**
1211
 * Batch 'finished' callback
1212
 */
1213
function boincimport_preferences_finished($success, $results, $operations) {
1214
  if ($success) {
1215
    // Let's count our successes
1216
    $total_imported = count($results['success']);
1217
    $total_warnings = count($results['warning']);
1218
    $message = t(
1219
      'Successfully imported preferences for @count users (with @warn warnings)',
1220
      array('@count' => $total_imported, '@warn' => $total_warnings)
1221
    );
1222
    watchdog('boincimport',
1223
      'Successfully imported preferences for @count users (with @warn warnings)',
1224
      array('@count' => $total_imported, '@warn' => $total_warnings),
1225
      WATCHDOG_INFO
1226
    );
1227
    // Set the preference import successful flag in the variable table
1228
    variable_set('boincimport_import_preferences_successful', '1');
1229
    $_SESSION['boincimport_stage_selected'] = 'private messages';
1230
  }
1231
  else {
1232
    // An error occurred.
1233
    // $operations contains the operations that remained unprocessed.
1234
    $error_operation = reset($operations);
1235
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

1235
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
1236
  }
1237
  drupal_set_message($message);
1238
1239
  // Release the lock on the import process
1240
  variable_del('boincimport_process_locked');
1241
  drupal_goto('admin/boinc/import/process');
1242
}
1243
1244
1245
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1246
 * Private messages
1247
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1248
1249
/**
1250
 * Import private messages from BOINC
1251
 */
1252
function boincimport_private_msgs() {
1253
1254
  // Check whether private messages have been successfully imported already
1255
  if (variable_get('boincimport_import_private_msg_successful', 0)) {
1256
    drupal_set_message(t('Private message import has already run successfully -- repeating this process could result in duplicate messages!'), 'warning');
1257
    watchdog(
1258
      'boincimport', 'Private message import has already run successfully',
1259
      array(), WATCHDOG_WARNING
1260
    );
1261
    return;
1262
  }
1263
1264
  if (!variable_get('boincimport_import_private_msg_started', 0)) {
1265
    // Could prepare database tables, if new fields are necessary, etc.
1266
    variable_set('boincimport_import_private_msg_started', 1);
1267
  }
1268
1269
  $pre = variable_get('boincimport_table_prefix', '');
1270
1271
  // Get stuff to import
1272
  db_set_active('boinc_rw');
1273
  $boinc_private_msgs = db_query('
1274
    SELECT id, subject, content, userid, senderid, date, opened
1275
    FROM %sprivate_messages',
1276
    $pre
1277
  );
1278
  $private_msg_count = mysqli_num_rows($boinc_private_msgs);
0 ignored issues
show
Bug introduced by
$boinc_private_msgs of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

1278
  $private_msg_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boinc_private_msgs);
Loading history...
1279
  db_set_active('default');
1280
1281
  if (!$private_msg_count) {
1282
    drupal_set_message(
1283
      t('There were no private messages found: Moving on...')
1284
    );
1285
    watchdog('boincimport',
1286
      'There were no private messages found: Moving on...', array(), WATCHDOG_INFO
1287
    );
1288
    // Release the lock on the import process
1289
    variable_del('boincimport_process_locked');
1290
    return t('There were no private messages found: Moving on...');
1291
  }
1292
1293
  watchdog('boincimport',
1294
    'Found %count private messages: Beginning Import',
1295
    array('%count' => $private_msg_count), WATCHDOG_INFO
1296
  );
1297
1298
  $operations = array();
1299
1300
  // We don't know if a given private message has been imported already or not;
1301
  // if this is needed, a relation table must be added to the Drupal DB
1302
1303
  // Create batches to process
1304
  while ($boinc_private_msg = db_fetch_object($boinc_private_msgs)) {
1305
    $operations[] = array(
1306
      'boincimport_private_msgs_op', array(
1307
        $boinc_private_msg
1308
      )
1309
    );
1310
  }
1311
1312
  $batch = array(
1313
    'operations' => $operations,
1314
    'finished' => 'boincimport_private_msgs_finished',
1315
    'title' => t('Importing private messages'),
1316
    'init_message' => t('Beginning private message import...'),
1317
    'progress_message' => t('Processed @current out of @total private messages.'),
1318
    'error_message' => t('Private message import has encountered an error.'),
1319
  );
1320
1321
  batch_set($batch);
1322
}
1323
1324
/**
1325
 * Batch operation for importing private messages
1326
 * Create a Drupal message from the given BOINC message object
1327
 */
1328
function boincimport_private_msgs_op($pm, &$context) {
1329
1330
  $input_format = variable_get('boincimport_input_format', 0);
1331
1332
  $uid = boincuser_lookup_uid($pm->userid);
1333
  $sender_uid = boincuser_lookup_uid($pm->senderid);
1334
1335
  $pm->content = _boincimport_strip_bbcode($pm->content);
1336
  $pm->content = _boincimport_text_sanitize($pm->content);
1337
1338
  // First save the message
1339
  $message_added = db_query("
1340
    INSERT INTO {pm_message} (subject, author, body, format, timestamp)
1341
    VALUES ('%s', %d, '%s', %d, %d)",
1342
    $pm->subject, $sender_uid, $pm->content, $input_format, $pm->date
1343
  );
1344
  $mid = db_last_insert_id('pm_message', 'mid');
1345
1346
  // Then attach recipients and set status (note that threads are not a BOINC
1347
  // feature, so just consider every message to be a new thread)
1348
  $recipient_added = db_query("
1349
    INSERT INTO {pm_index} (mid, thread_id, uid, is_new, deleted)
1350
    VALUES (%d, %d, %d, %d, 0)",
1351
    $mid, $mid, $uid, !$pm->opened
1352
  );
1353
  // In Drupal, the sender should be attached as well
1354
  $sender_added = db_query("
1355
    INSERT INTO {pm_index} (mid, thread_id, uid, is_new, deleted)
1356
    VALUES (%d, %d, %d, %d, 0)",
1357
    $mid, $mid, $sender_uid, 0
1358
  );
1359
1360
  $message = '';
1361
  if ($message_added AND $recipient_added AND $sender_added) {
1362
    // Store some result for post-processing in the finished callback.
1363
    $context['results']['success'][] = $pm->id;
1364
    $message = "Successfully imported private message {$pm->id}";
1365
  }
1366
  else {
1367
    $context['results']['failure'][] = $pm->id;
1368
    $message = "Failed to import private message {$pm->id}!";
1369
    watchdog('boincimport',
1370
      'Failed to import private message @id!',
1371
      array('@id' => $pm->id), WATCHDOG_WARNING
1372
    );
1373
  }
1374
1375
  // Update our progress information.
1376
  $context['sandbox']['progress']++;
1377
  $context['sandbox']['current_pm'] = $pm->id;
1378
  $context['message'] = $message;
1379
1380
  // Update the progress for the batch engine
1381
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
1382
    $context['finished'] = 1;
1383
  }
1384
  else {
1385
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
1386
  }
1387
}
1388
1389
/**
1390
 * Batch 'finished' callback
1391
 */
1392
function boincimport_private_msgs_finished($success, $results, $operations) {
1393
  if ($success) {
1394
    // Let's count our successes
1395
    $total_imported = count($results['success']);
1396
    $message = t(
1397
      'Successfully imported @count private messages',
1398
      array('@count' => $total_imported)
1399
    );
1400
    watchdog('boincimport',
1401
      'Successfully imported @count private messages.',
1402
      array('@count' => $total_imported), WATCHDOG_INFO
1403
    );
1404
    // Set the private message import successful flag in the variable table
1405
    variable_set('boincimport_import_private_msg_successful', '1');
1406
    $_SESSION['boincimport_stage_selected'] = 'categories';
1407
  }
1408
  else {
1409
    // An error occurred.
1410
    // $operations contains the operations that remained unprocessed.
1411
    $error_operation = reset($operations);
1412
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

1412
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
1413
  }
1414
  drupal_set_message($message);
1415
1416
  // Release the lock on the import process
1417
  variable_del('boincimport_process_locked');
1418
  drupal_goto('admin/boinc/import/process');
1419
}
1420
1421
1422
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1423
 * Forums and containers
1424
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1425
1426
/**
1427
 * Create forum containers and forums
1428
 */
1429
function boincimport_forum_categories() {
1430
1431
  // Check whether forums have been successfully imported already
1432
  if (variable_get('boincimport_import_forum_category_successful', 0)) {
1433
    drupal_set_message(t('Note: forum container import has already run successfully'));
1434
    watchdog(
1435
      'boincimport', 'Note: forum container import has already run successfully',
1436
      array(), WATCHDOG_INFO
1437
    );
1438
  }
1439
1440
  if (!variable_get('boincimport_import_forum_category_started', 0)) {
1441
    // Could prepare database tables, if new fields are necessary, etc.
1442
    variable_set('boincimport_import_forum_category_started', 1);
1443
  }
1444
1445
  $pre = variable_get('boincimport_table_prefix', '');
1446
1447
  // Retrieve the vocabulary vid named "Forums"
1448
  //$forum_vid = variable_get('forum_nav_vocabulary', 0);
1449
  $forum_vid = db_result(db_query('
1450
    SELECT vid FROM {vocabulary}
1451
    WHERE name="%s"',
1452
    'Forums'
1453
  ));
1454
  if (!$forum_vid) {
1455
    $forum_vocab = array(
1456
      'name' => t('Forums'),
1457
      'description' => t('The different forum categories / containers'),
1458
    );
1459
    taxonomy_save_vocabulary($forum_vocab);
1460
    $forum_vid = db_result(db_query('
1461
      SELECT vid FROM {vocabulary}
1462
      WHERE name="%s"',
1463
      'Forums'
1464
    ));
1465
  }
1466
1467
  // Get both categories and forums from BOINC
1468
  db_set_active('boinc_rw');
1469
  $boinc_forum_categories = db_query('
1470
    SELECT id, name
1471
    FROM %scategory
1472
    ORDER BY orderID',
1473
    $pre
1474
  );
1475
  $forum_category_count = mysqli_num_rows($boinc_forum_categories);
0 ignored issues
show
Bug introduced by
$boinc_forum_categories of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

1475
  $forum_category_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boinc_forum_categories);
Loading history...
1476
  $boinc_forums = db_query('
1477
    SELECT id, category, title, description, orderID
1478
    FROM %sforum
1479
    WHERE parent_type = 0
1480
    ORDER BY category',
1481
    $pre
1482
  );
1483
  $forum_count = mysqli_num_rows($boinc_forums);
1484
  db_set_active('default');
1485
1486
  if (!$forum_category_count) {
1487
    drupal_set_message(
1488
      t('There were no forum containers found: Aborting script'), 'warning'
1489
    );
1490
    watchdog('boincimport',
1491
      'There were no forum containers found: Aborting script', array(), WATCHDOG_WARNING
1492
    );
1493
    // Release the lock on the import process
1494
    variable_del('boincimport_process_locked');
1495
    return t('There were no forum containers found: Aborting script.');
1496
  }
1497
  if (!$forum_count) {
1498
    drupal_set_message(
1499
      t('There were no forums found: Aborting script'), 'warning'
1500
    );
1501
    watchdog('boincimport',
1502
      'There were no forums found: Aborting script', array(), WATCHDOG_WARNING
1503
    );
1504
    // Release the lock on the import process
1505
    variable_del('boincimport_process_locked');
1506
    return t('There were no forums found: Aborting script.');
1507
  }
1508
1509
  watchdog('boincimport',
1510
    'Found %forum_count forums in %category_count containers: Beginning Import',
1511
    array(
1512
      '%forum_count' => $forum_count,
1513
      '%category_count' => $forum_category_count,
1514
    ), WATCHDOG_INFO
1515
  );
1516
1517
  $operations = array();
1518
  $existing_categories = array();
1519
  $existing_forums = array();
1520
  $duplicate_categories = array();
1521
  $duplicate_forums = array();
1522
  $category_map = array();
1523
1524
  // Get the list of categories already in Drupal so as not to import any twice
1525
  $category_tree = taxonomy_get_tree($forum_vid, 0, -1, 1);
1526
  foreach ($category_tree as $term) {
1527
    $existing_categories[] = $term->name;
1528
  }
1529
1530
  // Get the list of forums already in Drupal
1531
  $result = db_query('
1532
    SELECT forum_id, tid FROM {boincimport_temp_forum}'
1533
  );
1534
  while ($row = db_fetch_object($result)) {
1535
    $existing_forums[$row->forum_id] = $row->tid;
1536
  }
1537
1538
  // Create batches to process
1539
1540
  // Set up the "hidden" category, if necessary
1541
  // This is to support automatic hiding of empty categories
1542
  $hidden_forum_tid = db_result(db_query('
1543
    SELECT tid FROM {term_data}
1544
    WHERE vid = %d
1545
    AND name = "%s"',
1546
    $forum_vid, 'Hidden'
1547
  ));
1548
  if (!$hidden_forum_tid) {
1549
    $operations[] = array(
1550
      'boincimport_forum_categories_op', array(
1551
        NULL, $forum_vid, $pre, TRUE
1552
      )
1553
    );
1554
  }
1555
1556
  // Import categories
1557
  while ($boinc_forum_category = db_fetch_object($boinc_forum_categories)) {
1558
    if (in_array($boinc_forum_category->name, $existing_categories)) {
1559
      // This category has already been imported
1560
      $duplicate_categories[] = $boinc_forum_category->name;
1561
    }
1562
    else {
1563
      $operations[] = array(
1564
        'boincimport_forum_categories_op', array(
1565
          $boinc_forum_category, $forum_vid, $pre, FALSE
1566
        )
1567
      );
1568
    }
1569
  }
1570
1571
  // Import forums
1572
  while ($boinc_forum = db_fetch_object($boinc_forums)) {
1573
     if (isset($existing_forums[$boinc_forum->id])) {
1574
      // This forum has already been imported
1575
      $duplicates[] = $boinc_forum->id;
1576
    }
1577
    else {
1578
      $operations[] = array(
1579
        'boincimport_forums_op', array(
1580
          $boinc_forum, $forum_vid, $pre
1581
        )
1582
      );
1583
    }
1584
  }
1585
1586
  // Report any duplicates that were skipped
1587
  $skipped_message = array();
1588
  $categories_skipped = count($duplicate_categories);
1589
  $forums_skipped = count($duplicate_forums);
1590
  if ($categories_skipped) {
1591
    $skipped_message[] = format_plural(
1592
      $categories_skipped,
1593
      '1 container',
1594
      '@count containers'
1595
    );
1596
  }
1597
  if ($forums_skipped) {
1598
    $skipped_message[] = format_plural(
1599
      $forums_skipped,
1600
      '1 forum',
1601
      '@count forums'
1602
    );
1603
  }
1604
  if ($skipped_message) {
1605
    drupal_set_message(t('Skipped @forums that were already imported',
1606
      array('@forums' => implode(' and ', $skipped_message))
1607
    ));
1608
  }
1609
1610
  // Create and run the batch
1611
  $batch = array(
1612
    'operations' => $operations,
1613
    'finished' => 'boincimport_forums_finished',
1614
    'title' => t('Importing forums'),
1615
    'init_message' => t('Beginning forum import...'),
1616
    'progress_message' => t('Processed @current out of @total forums.'),
1617
    'error_message' => t('Forum import has encountered an error.'),
1618
  );
1619
1620
  batch_set($batch);
1621
}
1622
1623
/**
1624
 * Batch operation for importing categories
1625
 * Create a Drupal taxonomy term from the given BOINC category object
1626
 */
1627
function boincimport_forum_categories_op($category, $forum_vid, $pre, $create_hidden, &$context) {
1628
1629
  // Set term parameters for categories
1630
  $forum_id = 0;
1631
  $parent_id = 0;
1632
  $description = '';
1633
  $weight = 0;
1634
  $hidden = FALSE;
1635
1636
  $category_map = variable_get('boincimport_forum_category_map', array());
1637
1638
  if (!$category AND $create_hidden) {
1639
    // Create the special "hidden" container
1640
    $category = new stdClass();
1641
    $category->name = 'Hidden';
1642
    $category->id = 0;
1643
    $hidden = TRUE;
1644
  }
1645
  else {
1646
    // If this container is empty, put it into the hidden container
1647
    db_set_active('boinc_rw');
1648
    $forums_contained = db_result(db_query('
1649
      SELECT count(*) FROM %sforum
1650
      WHERE parent_type = 0
1651
      AND category = %d',
1652
      $pre, $category->id));
1653
    db_set_active('default');
1654
    if (!$forums_contained) {
1655
      $parent_id = $category_map[0];
1656
      $hidden = TRUE;
1657
    }
1658
  }
1659
1660
  $forum = array(
1661
    'name' => $category->name,
1662
    'vid' => $forum_vid,
1663
    'description' => $description,
1664
    'parent' => $parent_id,
1665
    'weight' => $weight,
1666
  );
1667
  $forum['description'] = strip_tags($forum['description']);
1668
1669
  taxonomy_save_term($forum);
1670
  $success = isset($forum['tid']);
1671
1672
  // Serialize the forum containers
1673
  $containers = variable_get('forum_containers', array());
1674
  $containers[] = $forum['tid'];
1675
  variable_set('forum_containers', $containers);
1676
1677
  // Note the taxonomy ID for mapping forums to categories
1678
  $category_map[$category->id] = $forum['tid'];
1679
  variable_set('boincimport_forum_category_map', $category_map);
1680
1681
  boincimport_forum_set_permissions($forum, $hidden);
1682
1683
  $message = '';
1684
  if ($success) {
1685
    // Store some result for post-processing in the finished callback.
1686
    if (!$category AND $create_hidden) {
1687
      $message = "Created special hidden container";
1688
    }
1689
    else {
1690
      $context['results']['categories']['success'][] = $category->id;
1691
      $message = "Successfully imported container {$category->id}";
1692
    }
1693
  }
1694
  else {
1695
    $context['results']['categories']['failure'][] = $category->id;
1696
    $message = "Failed to import container {$category->id}!";
1697
    watchdog('boincimport',
1698
      'Failed to import container @id!',
1699
      array('@id' => $category->id), WATCHDOG_WARNING
1700
    );
1701
  }
1702
1703
  // Update our progress information.
1704
  $context['sandbox']['progress']++;
1705
  $context['sandbox']['current_category'] = $category->id;
1706
  $context['message'] = $message;
1707
1708
  // Update the progress for the batch engine
1709
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
1710
    $context['finished'] = 1;
1711
  }
1712
  else {
1713
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
1714
  }
1715
}
1716
1717
/**
1718
 * Batch operation for importing forums
1719
 * Create a Drupal taxonomy term from the given BOINC forum object
1720
 */
1721
function boincimport_forums_op($boincforum, $forum_vid, $pre = '', &$context) {
1722
1723
  $hidden_forum = FALSE;
1724
  $open_forum = FALSE;
1725
  $category_map = variable_get('boincimport_forum_category_map', array());
1726
1727
  // Set term parameters for forums
1728
  $forum_id = $boincforum->id;
1729
  $parent_id = isset($category_map[$boincforum->category]) ? $category_map[$boincforum->category] : $category_map[0];
1730
  $name = $boincforum->title;
1731
  $description = $boincforum->description;
1732
  $weight = $boincforum->orderID;
1733
  if ($parent_id == $category_map[0]) {
1734
    // If this forum is hidden, flag for appropriate access controls
1735
    $hidden_forum = TRUE;
1736
  }
1737
  if ($name == 'Getting Started') {
1738
    // Must allow users to post in this forum even if they have no credit!
1739
    $open_forum = TRUE;
1740
  }
1741
1742
  // Try to detect a BOINC news forum and flag it so that news can be
1743
  // imported into a Drupal news content type later
1744
  if ($name == 'News') {
1745
    // Save the ID of the News forum for later import
1746
    variable_set('boincimport_news_forum_id', $forum_id);
1747
    $success = TRUE;
1748
  }
1749
  else {
1750
    // Save all other forums as taxonomy terms
1751
    $forum = array(
1752
      'name' => $name,
1753
      'vid' => $forum_vid,
1754
      'description' => $description,
1755
      'parent' => $parent_id,
1756
      'weight' => $weight,
1757
    );
1758
    $forum['description'] = strip_tags($forum['description']);
1759
1760
    taxonomy_save_term($forum);
1761
    $success = isset($forum['tid']);
1762
1763
    // Save the forum ID to a temporary reference table - yes this is hackish.
1764
    db_query('INSERT INTO {boincimport_temp_forum} (forum_id, tid) VALUES (%d, %d)', $boincforum->id, $forum['tid']);
1765
1766
    // Set access controls
1767
    boincimport_forum_set_permissions($forum, $hidden_forum, $open_forum);
1768
  }
1769
1770
  $message = '';
1771
  if ($success) {
1772
    // Store some result for post-processing in the finished callback.
1773
    $context['results']['forums']['success'][] = $forum_id;
1774
    $message = "Successfully imported forum {$forum_id}";
1775
  }
1776
  else {
1777
    $context['results']['forums']['failure'][] = $forum_id;
1778
    $message = "Failed to import forum {$forum_id}!";
1779
  }
1780
1781
  // Update our progress information.
1782
  $context['sandbox']['progress']++;
1783
  $context['sandbox']['current_forum'] = $forum_id;
1784
  $context['message'] = $message;
1785
1786
  // Update the progress for the batch engine
1787
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
1788
    $context['finished'] = 1;
1789
  }
1790
  else {
1791
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
1792
  }
1793
}
1794
1795
/**
1796
 * Helper function to set permissions on forums upon import
1797
 */
1798
function boincimport_forum_set_permissions($forum, $hidden = FALSE, $open = FALSE) {
1799
1800
  // Set access controls
1801
  $forum_perms = array();
1802
  $role_map = array_flip(user_roles());
1803
  $forum_perms[$role_map['anonymous user']] = array(
1804
    'view' => (int) !$hidden,
1805
    'update' => 0,
1806
    'delete' => 0,
1807
    'create' => 0,
1808
  );
1809
  $forum_perms[$role_map['authenticated user']] = array(
1810
    'view' => (int) !$hidden,
1811
    'update' => 0,
1812
    'delete' => 0,
1813
    'create' => 0,
1814
  );
1815
  $forum_perms[$role_map['community member']] = array(
1816
    'view' => (int) !$hidden,
1817
    'update' => 0,
1818
    'delete' => 0,
1819
    'create' => (int) $open,
1820
  );
1821
  $forum_perms[$role_map['verified contributor']] = array(
1822
    'view' => (int) !$hidden,
1823
    'update' => 0,
1824
    'delete' => 0,
1825
    'create' => (int) !$hidden,
1826
  );
1827
  $forum_perms[$role_map['moderator']] = array(
1828
    'view' => (int) !$hidden,
1829
    'update' => (int) !$hidden,
1830
    'delete' => 0,
1831
    'create' => (int) !$hidden,
1832
  );
1833
  $forum_perms[$role_map['administrator']] = array(
1834
    'view' => 1,
1835
    'update' => 1,
1836
    'delete' => 1,
1837
    'create' => 1,
1838
  );
1839
  foreach ($forum_perms as $role => $perm) {
1840
    db_query('
1841
      INSERT INTO {forum_access}
1842
      SET  tid = %d, rid = %d,
1843
        grant_view = %d, grant_update = %d,
1844
        grant_delete = %d, grant_create = %d
1845
      ON DUPLICATE KEY UPDATE
1846
        grant_view = %d, grant_update = %d,
1847
        grant_delete = %d, grant_create = %d',
1848
      $forum['tid'], $role,
1849
      $perm['view'], $perm['update'],
1850
      $perm['delete'], $perm['create'],
1851
      $perm['view'], $perm['update'],
1852
      $perm['delete'], $perm['create']);
1853
  }
1854
}
1855
1856
/**
1857
 * Batch 'finished' callback
1858
 */
1859
function boincimport_forums_finished($success, $results, $operations) {
1860
  if ($success) {
1861
    // Let's count our successes
1862
    $categories_imported = count($results['categories']['success']);
1863
    $forums_imported = count($results['forums']['success']);
1864
1865
    $success_message = array();
1866
    if ($categories_imported) {
1867
      $success_message[] = format_plural(
1868
        $categories_imported,
1869
        '1 container',
1870
        '@count containers'
1871
      );
1872
    }
1873
    if ($forums_imported) {
1874
      $success_message[] = format_plural(
1875
        $forums_imported,
1876
        '1 forum',
1877
        '@count forums'
1878
      );
1879
    }
1880
    $message = t(
1881
      'Successfully imported @forums',
1882
      array('@forums' => implode(' and ', $success_message))
1883
    );
1884
    watchdog('boincimport',
1885
      'Successfully imported @forums',
1886
      array('@forums' => implode(' and ', $success_message)), WATCHDOG_INFO
1887
    );
1888
    // Set the forum import successful flag in the variable table
1889
    variable_set('boincimport_import_forum_successful', '1');
1890
    $_SESSION['boincimport_stage_selected'] = 'topics';
1891
  }
1892
  else {
1893
    // An error occurred.
1894
    // $operations contains the operations that remained unprocessed.
1895
    $error_operation = reset($operations);
1896
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

1896
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
1897
  }
1898
  drupal_set_message($message);
1899
1900
  // Release the lock on the import process
1901
  variable_del('boincimport_process_locked');
1902
  drupal_goto('admin/boinc/import/process');
1903
}
1904
1905
1906
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1907
 * Forum topics
1908
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1909
/**
1910
 * Import BOINC topics as Drupal forum nodes
1911
 */
1912
function boincimport_forum_topics() {
1913
1914
  // Check whether topics have been successfully imported already
1915
  if (variable_get('boincimport_import_topic_successful', 0)) {
1916
    drupal_set_message(t('Topic import has already run successfully'), 'warning');
1917
    watchdog(
1918
      'boincimport', 'Topic import has already run successfully',
1919
      array(), WATCHDOG_WARNING
1920
    );
1921
    // Release the lock on the import process
1922
    variable_del('boincimport_process_locked');
1923
    return;
1924
  }
1925
1926
  if (!variable_get('boincimport_import_topic_started', 0)) {
1927
    // Could prepare database tables, if new fields are necessary, etc.
1928
    variable_set('boincimport_import_topic_started', 1);
1929
  }
1930
1931
  $pre = variable_get('boincimport_table_prefix', '');
1932
1933
  // Get the count of non-team topics to import
1934
  db_set_active('boinc_rw');
1935
  $topic_count = db_result(db_query('
1936
    SELECT COUNT(DISTINCT t.id)
1937
    FROM %sthread t
1938
    JOIN %sforum f ON f.id = t.forum
1939
    JOIN %spost p ON p.thread = t.id
1940
    WHERE f.parent_type = 0',
1941
    $pre, $pre, $pre
1942
  ));
1943
  db_set_active('default');
1944
1945
  if (!$topic_count) {
1946
    drupal_set_message(
1947
      t('There were no topics found: Aborting script'), 'warning'
1948
    );
1949
    watchdog('boincimport',
1950
      'There were no topics found: Aborting script', array(), WATCHDOG_WARNING
1951
    );
1952
    // Release the lock on the import process
1953
    variable_del('boincimport_process_locked');
1954
    return t('There were no topics found: Aborting script.');
1955
  }
1956
1957
  watchdog('boincimport',
1958
    'Found %count topics: Beginning Import',
1959
    array('%count' => $topic_count), WATCHDOG_INFO
1960
  );
1961
1962
  $operations = array();
1963
  $batch_size = 100;
1964
1965
  // Create batches to process
1966
  for ($offset = 0; $offset < $topic_count; $offset+=$batch_size) {
1967
    $topics_per_batch = $batch_size;
1968
    if ($offset + $batch_size > $topic_count) {
1969
      $topics_per_batch = $topic_count - $offset;
1970
    }
1971
    $operations[] = array(
1972
      'boincimport_topics_op', array(
1973
        $offset, $topics_per_batch, $pre
1974
      )
1975
    );
1976
  }
1977
1978
  $batch = array(
1979
    'operations' => $operations,
1980
    'finished' => 'boincimport_topics_finished',
1981
    'title' => t('Importing topics'),
1982
    'init_message' => t('Beginning topic import...'),
1983
    'progress_message' => t('Processed @current out of @total batches (@size topics per batch).', array(
1984
      '@size' => $batch_size,
1985
    )),
1986
    'error_message' => t('Topic import has encountered an error.'),
1987
  );
1988
1989
  batch_set($batch);
1990
}
1991
1992
/**
1993
 * Batch operation for importing topics
1994
 * Create a Drupal node from the given BOINC topic object
1995
 */
1996
function boincimport_topics_op($offset, $batch_size, $pre = '', &$context) {
1997
  // Initialize the batch, if needed
1998
  if (!isset($context['sandbox']['progress'])) {
1999
    $context['sandbox']['progress'] = 0;
2000
    $context['sandbox']['max'] = $batch_size;
2001
  }
2002
2003
  $input_format = variable_get('boincimport_input_format', 0);
2004
  $news_forum_id = variable_get('boincimport_news_forum_id', 0);
2005
2006
  // Get the topic to import
2007
  db_set_active('boinc_rw');
2008
  $topics = db_query('
2009
    SELECT DISTINCT t.id, t.title, t.owner, t.forum, t.locked, t.hidden,
2010
        t.sticky, t.timestamp, t.create_time
2011
    FROM %sthread t
2012
    JOIN %sforum f ON f.id = t.forum
2013
    JOIN %spost p ON p.thread = t.id
2014
    WHERE f.parent_type = 0
2015
    ORDER BY t.id ASC
2016
    LIMIT %d,%d',
2017
    $pre, $pre, $pre, $offset, $batch_size
2018
  );
2019
  db_set_active('default');
2020
2021
  while ($topic = db_fetch_object($topics)) {
2022
2023
    $error_detail = '';
2024
2025
    db_set_active('boinc_rw');
2026
2027
    // Get the content of the post that started the topic
2028
    $post = db_fetch_object(db_query('
2029
      SELECT id, content
2030
      FROM %spost
2031
      WHERE thread = %d
2032
      ORDER BY timestamp ASC
2033
      LIMIT 1',
2034
      $pre, $topic->id
2035
    ));
2036
    db_set_active('default');
2037
2038
    $duplicate = db_result(db_query('
2039
      SELECT COUNT(*) FROM {boincimport_temp_topic}
2040
      WHERE topic_id = %d',
2041
      $topic->id
2042
    ));
2043
2044
    if ($duplicate OR !$post) {
2045
      $success = FALSE;
2046
    }
2047
2048
    else {
2049
      // Get the user and term IDs along with other data to define the topic
2050
      $uid = boincuser_lookup_uid($topic->owner);
2051
      $tid = db_result(db_query('
2052
        SELECT tid FROM {boincimport_temp_forum}
2053
        WHERE forum_id = %d',
2054
        $topic->forum
2055
      ));
2056
      if (!$topic->owner) {
2057
        $uid = 0;
2058
      }
2059
2060
      $node_type = 'forum';
2061
      $promote = 0;
2062
      $comment = ($topic->locked) ? 1 : 2;
2063
2064
      $post->content = _boincimport_strip_bbcode($post->content);
2065
      $post->content = _boincimport_text_sanitize($post->content);
2066
      $teaser = node_teaser($post->content);
2067
2068
      if ($topic->timestamp < $topic->create_time) {
2069
        $topic->timestamp = $topic->create_time;
2070
      }
2071
2072
      // If dealing with a News topic, be sure it is imported as such
2073
      if ($news_forum_id AND $topic->forum == $news_forum_id) {
2074
        $node_type = 'news';
2075
        $promote = 1;
2076
      }
2077
2078
      // Construct the thread as a forum topic node
2079
      $node = array(
2080
        'type' => $node_type,
2081
        'title' => $topic->title,
2082
        'uid' => $uid,
2083
        'status' => ($topic->hidden) ? 0 : 1,  // published or not
2084
        'promote' => $promote,
2085
        'created' => $topic->create_time,
2086
        'changed' => $topic->timestamp,
2087
        'comment' => $comment,
2088
        'moderate' => 0,
2089
        'body' => $post->content,
2090
        'sticky' => $topic->sticky,
2091
        'format' => $input_format,
2092
        'teaser' => $teaser,
2093
      );
2094
      $node['tid'] = $tid;
2095
2096
      // Save the topic node
2097
      $node = (object) $node; // node_save requires an object form
2098
      node_save($node);
2099
      taxonomy_node_save($node, array($tid));
2100
      $success = ($node->nid) ? TRUE : FALSE;
2101
      if ($success) {
2102
        $success = db_query('
2103
          INSERT INTO {boincimport_temp_topic} (topic_id, post_id, nid)
2104
          VALUES (%d, %d, %d)', $topic->id, $post->id, $node->nid
2105
        );
2106
        if ($success) {
2107
          // Hack to keep the topics in correct order
2108
          $success = db_query('UPDATE {node_comment_statistics} SET last_comment_timestamp = %d WHERE nid = %d', $node->created, $node->nid);
2109
          if (!$success) {
2110
            $error_detail = 'topic imported, but failed to set last comment timestamp';
2111
          }
2112
        }
2113
        else {
2114
          $error_detail = 'topic node saved, but failed to link in boincimport_temp_topic table';
2115
        }
2116
      }
2117
      else {
2118
        $error_detail = 'failed to save topic node to database';
2119
      }
2120
    }
2121
2122
    // See if the import worked
2123
    $message = '';
2124
    if ($success) {
2125
      // Store some result for post-processing in the finished callback.
2126
      $context['results']['success'][] = $topic->id;
2127
      $message = "Successfully imported topic {$topic->id}";
2128
    }
2129
    elseif ($duplicate) {
2130
      $context['results']['duplicate'][] = $topic->id;
2131
      $message = "Topic {$topic->id} was already imported";
2132
    }
2133
    elseif (!$post) {
2134
      $context['results']['empty'][] = $topic->id;
2135
      $message = "Skipping topic {$topic->id} as empty";
2136
    }
2137
    else {
2138
      $context['results']['failure'][] = $topic->id;
2139
      $message = "Failed to import topic {$topic->id}!";
2140
      watchdog('boincimport',
2141
        'Failed to import topic @id! (@error)',
2142
        array(
2143
          '@id' => $topic->id,
2144
          '@error' => $error_detail,
2145
        ),
2146
        WATCHDOG_WARNING
2147
      );
2148
    }
2149
2150
    // Update our progress information.
2151
    $context['sandbox']['progress']++;
2152
    $context['sandbox']['current_topic'] = $topic->id;
2153
    $context['message'] = $message;
2154
2155
    // Update the progress for the batch engine
2156
    if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
2157
      $context['finished'] = 1;
2158
    }
2159
    else {
2160
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
2161
    }
2162
  }
2163
}
2164
2165
/**
2166
 * Batch 'finished' callback
2167
 */
2168
function boincimport_topics_finished($success, $results, $operations) {
2169
  if ($success) {
2170
    // Let's count our successes
2171
    $total_imported = count($results['success']);
2172
    $duplicates = count($results['duplicate']);
2173
    $empty_topics = count($results['empty']);
2174
    $message = t(
2175
      'Successfully imported @count topics (skipped @duplicates already imported, @abandoned empty topics)',
2176
      array(
2177
        '@count' => $total_imported,
2178
        '@duplicates' => $duplicates,
2179
        '@abandoned' => $empty_topics,
2180
      )
2181
    );
2182
    watchdog('boincimport',
2183
      'Successfully imported @count topics (skipped @duplicates already imported, @abandoned empty topics).',
2184
      array(
2185
        '@count' => $total_imported,
2186
        '@duplicates' => $duplicates,
2187
        '@abandoned' => $empty_topics,
2188
      ), WATCHDOG_INFO
2189
    );
2190
    // Set the topic import successful flag in the variable table
2191
    variable_set('boincimport_import_topic_successful', '1');
2192
    $_SESSION['boincimport_stage_selected'] = 'posts';
2193
  }
2194
  else {
2195
    // An error occurred.
2196
    // $operations contains the operations that remained unprocessed.
2197
    $error_operation = reset($operations);
2198
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

2198
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
2199
  }
2200
  drupal_set_message($message);
2201
2202
  // Release the lock on the import process
2203
  variable_del('boincimport_process_locked');
2204
  drupal_goto('admin/boinc/import/process');
2205
}
2206
2207
2208
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2209
 * Forum posts
2210
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
2211
2212
/**
2213
 * Import BOINC forum posts as Drupal comments
2214
 */
2215
function boincimport_forum_posts() {
2216
2217
  // Check whether forum posts have been successfully imported already
2218
  if (variable_get('boincimport_import_post_successful', 0)) {
2219
    drupal_set_message(t('Forum post import has already run successfully'), 'warning');
2220
    watchdog(
2221
      'boincimport', 'Forum post import has already run successfully',
2222
      array(), WATCHDOG_WARNING
2223
    );
2224
    // Release the lock on the import process
2225
    variable_del('boincimport_process_locked');
2226
    return;
2227
  }
2228
2229
  if (!variable_get('boincimport_import_post_started', 0)) {
2230
    // Could prepare database tables, if new fields are necessary, etc.
2231
    variable_set('boincimport_import_post_started', 1);
2232
  }
2233
2234
  $pre = variable_get('boincimport_table_prefix', '');
2235
2236
  // Get the BOINC threads and get a count of posts to import
2237
  db_set_active('boinc_rw');
2238
  $topic_count = db_result(db_query("
2239
    SELECT COUNT(DISTINCT t.id) FROM %sthread t
2240
    JOIN %sforum f ON f.id = t.forum
2241
    JOIN %spost p ON p.thread = t.id
2242
    WHERE f.parent_type = 0", $pre, $pre, $pre
2243
  ));
2244
  $total_post_count = db_result(db_query("
2245
    SELECT COUNT(p.id) FROM %spost p
2246
    JOIN %sthread t ON t.id = p.thread
2247
    JOIN %sforum f ON f.id = t.forum
2248
    WHERE f.parent_type = 0", $pre, $pre, $pre
2249
  ));
2250
  $post_count = $total_post_count - $topic_count;
2251
  db_set_active('default');
2252
2253
  if ($post_count <= 0) {
2254
    drupal_set_message(
2255
      t('There were no posts found: Aborting script'), 'warning'
2256
    );
2257
    watchdog('boincimport',
2258
      'There were no posts found: Aborting script', array(), WATCHDOG_WARNING
2259
    );
2260
    // Release the lock on the import process
2261
    variable_del('boincimport_process_locked');
2262
    return t('There were no posts found: Aborting script.');
2263
  }
2264
2265
  watchdog('boincimport',
2266
    'Found %count posts: Beginning Import',
2267
    array('%count' => $post_count), WATCHDOG_INFO
2268
  );
2269
2270
  $operations = array();
2271
  $batch_size = 100;
2272
2273
  // Create batches to process
2274
  for ($offset = 0; $offset < $topic_count; $offset+=$batch_size) {
2275
    $topics_per_batch = $batch_size;
2276
    if ($offset + $batch_size > $topic_count) {
2277
      $topics_per_batch = $topic_count - $offset;
2278
    }
2279
    $operations[] = array(
2280
      'boincimport_posts_op', array(
2281
        $offset, $topics_per_batch
2282
      )
2283
    );
2284
  }
2285
2286
  $batch = array(
2287
    'operations' => $operations,
2288
    'finished' => 'boincimport_posts_finished',
2289
    'title' => t('Importing posts'),
2290
    'init_message' => t('Beginning post import...'),
2291
    'progress_message' => t(
2292
      'Processed posts in @current out of @total batches (@size topics per batch).',
2293
      array(
2294
        '@size' => $batch_size,
2295
        // @current and @total are managed by the batch API
2296
      )
2297
    ),
2298
    'error_message' => t('Post import has encountered an error.'),
2299
  );
2300
2301
  batch_set($batch);
2302
}
2303
2304
/**
2305
 * Batch operation for importing posts
2306
 * Create a Drupal comment from the given BOINC post object
2307
 */
2308
function boincimport_posts_op($offset, $batch_size, &$context) {
2309
  // Initialize the batch, if needed
2310
  if (!isset($context['sandbox']['progress'])) {
2311
    $context['sandbox']['progress'] = 0;
2312
    $context['sandbox']['max'] = $batch_size;
2313
  }
2314
2315
  $input_format = variable_get('boincimport_input_format', 0);
2316
2317
 // Get the topics with posts to import
2318
  db_set_active('boinc_rw');
2319
  $boinc_topic_ids = db_query('
2320
    SELECT DISTINCT t.id FROM %sthread t
2321
    JOIN %sforum f ON f.id = t.forum
2322
    JOIN %spost p ON p.thread = t.id
2323
    WHERE f.parent_type = 0
2324
    ORDER BY t.id
2325
    LIMIT %d,%d',
2326
    $pre, $pre, $pre, $offset, $batch_size
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pre seems to be never defined.
Loading history...
2327
  );
2328
  db_set_active('default');
2329
2330
  while ($boinc_topic = db_fetch_object($boinc_topic_ids)) {
2331
    // Get the posts in this topic
2332
    db_set_active('boinc_rw');
2333
    $boinc_posts = db_query('
2334
      SELECT id, user, thread, timestamp, content, parent_post, hidden
2335
      FROM %spost WHERE thread = %d ORDER BY id ASC', $pre, $boinc_topic->id);
2336
    db_set_active('default');
2337
2338
    $first_post = true;
2339
    $topic_has_responses = FALSE;
2340
    $success = FALSE;
2341
    $posts_imported = 0;
2342
    $empty_posts = 0;
2343
    $error_posts = 0;
2344
    $duplicate_posts = 0;
2345
2346
    while ($post = db_fetch_object($boinc_posts)) {
2347
2348
      // Skip the first post as it has already been imported as a topic
2349
      if ($first_post) {
2350
        $first_post = false;
2351
        continue;
2352
      }
2353
2354
      // Making it this far confirms that there are posts to import
2355
      $topic_has_responses = TRUE;
2356
2357
      $is_duplicate = db_result(db_query('
2358
        SELECT COUNT(*) FROM {boincimport_temp_post}
2359
        WHERE post_id = %d',
2360
        $post->id
2361
      ));
2362
      if ($is_duplicate) {
2363
        // This post has already been imported
2364
        $context['results']['posts']['duplicate'][] = $post->id;
2365
        $duplicate_posts++;
2366
        continue;
2367
      }
2368
2369
      // Make sure the post is valid
2370
      if ($post->content) {
2371
2372
        // Get user, node, and parent IDs for the post and sanitize
2373
        $uid = boincuser_lookup_uid($post->user);
2374
        $node = db_fetch_object(db_query('
2375
          SELECT nr.nid, nr.title
2376
          FROM {boincimport_temp_topic} btt
2377
          LEFT JOIN {node_revisions} AS nr ON btt.nid = nr.nid
2378
          WHERE btt.topic_id = %d',
2379
          $post->thread
2380
        ));
2381
        $nid = $node->nid;
2382
        $pid = db_result(db_query('
2383
          SELECT cid
2384
          FROM {boincimport_temp_post}
2385
          WHERE post_id = %d',
2386
          $post->parent_post));
2387
        if (is_null($pid)) $pid = 0;
2388
        if (!$uid) $uid = 0;
2389
2390
        $post->content = _boincimport_strip_bbcode($post->content);
2391
        $post->content = _boincimport_text_sanitize($post->content);
2392
2393
        $topic_reply = db_result(db_query('
2394
          SELECT COUNT(*)
2395
          FROM {comments}
2396
          WHERE nid = %d',
2397
          $nid
2398
        ));
2399
        $post_reply = $pid;
2400
2401
        if ($post_reply OR $topic_reply) {
2402
          // Create a subject for the post from the post content. The body may be in
2403
          // any format, so we:
2404
          //  1) Filter it into HTML
2405
          //  2) Strip out all HTML tags
2406
          //  3) Convert entities back to plain-text.
2407
          // Note: format is checked by check_markup().
2408
          $subject = truncate_utf8(trim(decode_entities(strip_tags(check_markup($post->content, $input_format)))), 29, TRUE);
2409
          // Replace "Quote:" with "RE:"
2410
          $subject = str_replace('Quote:', 'RE: ', $subject);
2411
          // Fringe cases where the comment body is populated only by HTML tags
2412
          // will require a default subject...
2413
          if ($subject === '')
2414
            $subject = "RE: {$node->title}";
2415
        } else {
2416
          // This is the first post in the topic
2417
          $subject = $node->title;
2418
        }
2419
2420
        // Construct the post as a Drupal comment
2421
        $comment = array(
2422
          'pid' => $pid,
2423
          'nid' => $nid,
2424
          'uid' => $uid,
2425
          'subject' => $subject,
2426
          'comment' => $post->content,
2427
          'timestamp' => $post->timestamp,
2428
          'status' => $post->hidden,
2429
          'format' => $input_format
2430
        );
2431
2432
        // Save the comment
2433
        if (boincimport_forum_comment_save($comment)) {
2434
          $success = db_query('
2435
            INSERT INTO {boincimport_temp_post} (post_id, cid)
2436
            VALUES (%d, %d)',
2437
            $post->id, $comment['cid']
2438
          );
2439
          if ($success) {
2440
            $posts_imported++;
2441
            $context['results']['posts']['success'][] = $post->id;
2442
          }
2443
          else {
2444
            $context['results']['posts']['failure'][] = $post->id;
2445
            $error_posts++;
2446
          }
2447
        }
2448
        else {
2449
          $context['results']['posts']['failure'][] = $post->id;
2450
          $error_posts++;
2451
        }
2452
      }
2453
      else {
2454
        $context['results']['posts']['empty'][] = $post->id;
2455
        $empty_posts++;
2456
      }
2457
    }
2458
2459
    $message = '';
2460
    if ($success OR !$topic_has_responses) {
2461
      // Store some result for post-processing in the finished callback.
2462
      $context['results']['success'][] = $boinc_topic->id;
2463
      $message = "Imported {$posts_imported} post(s) for topic {$boinc_topic->id}";
2464
    }
2465
    else {
2466
      $context['results']['failure'][] = $boinc_topic->id;
2467
      $message = "Failed to import any posts for topic {$boinc_topic->id} (excluded {$error_posts} errors, {$duplicate_posts} duplicates, and {$empty_posts} empty)";
2468
      watchdog('boincimport', 'Failed to import any posts for topic @id (excluded @error_posts errors, @duplicate_posts duplicates, and @empty_posts empty)',
2469
        array(
2470
          '@id' => $boinc_topic->id,
2471
          '@error_posts' => $error_posts,
2472
          '@duplicate_posts' => $duplicate_posts,
2473
          '@empty_posts' => $empty_posts,
2474
        ), WATCHDOG_WARNING
2475
      );
2476
    }
2477
2478
    // Update our progress information.
2479
    $context['sandbox']['progress']++;
2480
    $context['sandbox']['current_topic'] = $boinc_topic->id;
2481
    $context['message'] = $message;
2482
2483
    // Update the progress for the batch engine
2484
    if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
2485
      $context['finished'] = 1;
2486
    }
2487
    else {
2488
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
2489
    }
2490
  }
2491
}
2492
2493
/**
2494
 * Batch 'finished' callback
2495
 */
2496
function boincimport_posts_finished($success, $results, $operations) {
2497
  if ($success) {
2498
    // Let's count our successes
2499
    $posts_imported = count($results['posts']['success']);
2500
    $topic_count = count($results['success']);
2501
    $topics_skipped = count($results['failure']);
2502
    $duplicates = count($results['posts']['duplicate']);
2503
    $empty_posts = count($results['posts']['empty']);
2504
    $failed_posts = count($results['posts']['failure']);
2505
    $message = t(
2506
      'Successfully imported @post_count posts in @topic_count topics ' .
2507
      '(@skipped topics either had no replies or all replies were already imported, ' .
2508
      '@duplicates posts were skipped as already imported, ' .
2509
      '@empty_posts had no content, ' .
2510
      'and @error_posts encountered errors during import)',
2511
      array(
2512
        '@post_count' => $posts_imported,
2513
        '@topic_count' => $topic_count,
2514
        '@skipped' => $topics_skipped,
2515
        '@duplicates' => $duplicates,
2516
        '@empty_posts' => $empty_posts,
2517
        '@error_posts' => $failed_posts,
2518
      )
2519
    );
2520
    watchdog('boincimport',
2521
      $message,
2522
      array(), WATCHDOG_INFO
2523
    );
2524
    // Set the post import successful flag in the variable table
2525
    variable_set('boincimport_import_post_successful', '1');
2526
    $_SESSION['boincimport_stage_selected'] = 'team forums';
2527
  }
2528
  else {
2529
    // An error occurred.
2530
    // $operations contains the operations that remained unprocessed.
2531
    $error_operation = reset($operations);
2532
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

2532
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
2533
  }
2534
  drupal_set_message($message);
2535
2536
  // Release the lock on the import process
2537
  variable_del('boincimport_process_locked');
2538
  drupal_goto('admin/boinc/import/process');
2539
}
2540
2541
2542
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2543
 * Team forums
2544
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
2545
2546
/**
2547
 * Import team forums
2548
 */
2549
function boincimport_team_forums() {
2550
2551
  // Check whether team forums have been successfully imported already
2552
  if (variable_get('boincimport_import_team_forum_successful', 0)) {
2553
    drupal_set_message(t('Team forum import has already run successfully'), 'warning');
2554
    watchdog(
2555
      'boincimport', 'Team forum import has already run successfully',
2556
      array(), WATCHDOG_WARNING
2557
    );
2558
  }
2559
2560
  if (!variable_get('boincimport_import_team_forum_started', 0)) {
2561
    // Could prepare database tables, if new fields are necessary, etc.
2562
    variable_set('boincimport_import_team_forum_started', 1);
2563
  }
2564
2565
  $pre = variable_get('boincimport_table_prefix', '');
2566
2567
  // Get team forums from BOINC database
2568
  db_set_active('boinc_rw');
2569
  $boincteam_forums = db_query('
2570
    SELECT id, title, description, category, timestamp, post_min_interval,
2571
      post_min_total_credit, post_min_expavg_credit
2572
    FROM %sforum
2573
    WHERE parent_type = 1
2574
    ORDER BY id ASC',
2575
    $pre
2576
  );
2577
  $team_forum_count = mysqli_num_rows($boincteam_forums);
0 ignored issues
show
Bug introduced by
$boincteam_forums of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

2577
  $team_forum_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boincteam_forums);
Loading history...
2578
  db_set_active('default');
2579
2580
  if (!$team_forum_count) {
2581
    drupal_set_message(
2582
      t('There were no team forums found: Aborting script'), 'warning'
2583
    );
2584
    watchdog('boincimport',
2585
      'There were no team forums found: Aborting script', array(), WATCHDOG_WARNING
2586
    );
2587
    // Release the lock on the import process
2588
    variable_del('boincimport_process_locked');
2589
    return t('There were no BLAH found: Aborting script.');
2590
  }
2591
2592
  watchdog('boincimport',
2593
    'Found %count team forums: Beginning Import',
2594
    array('%count' => $team_forum_count), WATCHDOG_INFO
2595
  );
2596
2597
  $operations = array();
2598
  $existing_team_forums = array();
2599
  $duplicates = array();
2600
2601
  // Get the list of team forums already in Drupal to be sure we're not
2602
  // importing any twice
2603
  $result = db_query('
2604
    SELECT nid, boinc_id FROM {boincteam_forum}'
2605
  );
2606
  while ($row = db_fetch_object($result)) {
2607
    $existing_team_forums[$row->boinc_id] = $row->nid;
2608
  }
2609
2610
  // Create batches to process
2611
  while ($boincteam_forum = db_fetch_object($boincteam_forums)) {
2612
     if (isset($existing_team_forums[$boincteam_forum->id])) {
2613
      // This team has already been imported
2614
      $duplicates[] = $boincteam_forum->id;
2615
    }
2616
    else {
2617
      $operations[] = array(
2618
        'boincimport_team_forums_op', array(
2619
          $boincteam_forum
2620
        )
2621
      );
2622
    }
2623
  }
2624
2625
  if ($duplicates) {
2626
    drupal_set_message(t(
2627
      'Skipped @count team forums that were already imported',
2628
      array('@count' => count($duplicates))
2629
    ));
2630
  }
2631
2632
  $batch = array(
2633
    'operations' => $operations,
2634
    'finished' => 'boincimport_team_forums_finished',
2635
    'title' => t('Importing team forums'),
2636
    'init_message' => t('Beginning team forum import...'),
2637
    'progress_message' => t('Processed @current out of @total team forums.'),
2638
    'error_message' => t('Team forum import has encountered an error.'),
2639
  );
2640
2641
  batch_set($batch);
2642
}
2643
2644
/**
2645
 * Batch operation for importing team forums
2646
 * Create an entry in the boincteam_forum table for the given BOINC team forum
2647
 * object
2648
 */
2649
function boincimport_team_forums_op($boincteam_forum, &$context) {
2650
2651
  $input_format = variable_get('boincimport_input_format', 0);
2652
2653
  // Set term parameters for forums
2654
  $forum_id = $boincteam_forum->id;
2655
  $team_id = boincteam_lookup_nid($boincteam_forum->category);
2656
  $name = $boincteam_forum->title;
2657
  $description = strip_tags($boincteam_forum->description);
2658
2659
  $success = db_query("
2660
    INSERT INTO {boincteam_forum} SET
2661
      boinc_id = %d,
2662
      nid = %d,
2663
      title = '%s',
2664
      description = '%s',
2665
      created = %d,
2666
      updated = %d,
2667
      public = %d,
2668
      min_time_between_posts = %d,
2669
      min_total_credit_to_post = %d,
2670
      min_avg_credit_to_post = %d",
2671
    $forum_id, $team_id, $name, $description, $boincteam_forum->timestamp,
2672
    time(), 0, $boincteam_forum->post_min_interval,
2673
    $boincteam_forum->post_min_total_credit,
2674
    $boincteam_forum->post_min_expavg_credit
2675
  );
2676
2677
  $message = '';
2678
  if ($success) {
2679
    // Store some result for post-processing in the finished callback.
2680
    $context['results']['success'][] = $forum_id;
2681
    $message = "Successfully imported team forum {$forum_id}";
2682
  }
2683
  else {
2684
    $context['results']['failure'][] = $forum_id;
2685
    $message = "Failed to import team forum {$forum_id}!";
2686
    watchdog('boincimport',
2687
      'Failed to import team forum @id!',
2688
      array('@id' => $forum_id), WATCHDOG_WARNING
2689
    );
2690
  }
2691
2692
  // Update our progress information.
2693
  $context['sandbox']['progress']++;
2694
  $context['sandbox']['current_forum'] = $forum_id;
2695
  $context['message'] = $message;
2696
2697
  // Update the progress for the batch engine
2698
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
2699
    $context['finished'] = 1;
2700
  }
2701
  else {
2702
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
2703
  }
2704
}
2705
2706
/**
2707
 * Batch 'finished' callback
2708
 */
2709
function boincimport_team_forums_finished($success, $results, $operations) {
2710
  if ($success) {
2711
    // Let's count our successes
2712
    $total_imported = count($results['success']);
2713
    $message = t(
2714
      'Successfully imported @count team forums',
2715
      array('@count' => $total_imported)
2716
    );
2717
    watchdog('boincimport',
2718
      'Successfully imported @count team forums.',
2719
      array('@count' => $total_imported), WATCHDOG_INFO
2720
    );
2721
    // Set the team forum import successful flag in the variable table
2722
    variable_set('boincimport_import_team_forum_successful', '1');
2723
    $_SESSION['boincimport_stage_selected'] = 'team topics';
2724
  }
2725
  else {
2726
    // An error occurred.
2727
    // $operations contains the operations that remained unprocessed.
2728
    $error_operation = reset($operations);
2729
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

2729
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
2730
  }
2731
  drupal_set_message($message);
2732
2733
  // Release the lock on the import process
2734
  variable_del('boincimport_process_locked');
2735
  drupal_goto('admin/boinc/import/process');
2736
}
2737
2738
2739
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2740
 * Team forum topics
2741
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
2742
2743
/**
2744
 * Import BOINC team topics to Drupal team_forum type nodes
2745
 */
2746
function boincimport_team_forum_topics() {
2747
2748
  // Check whether team forum topics have been successfully imported already
2749
  if (variable_get('boincimport_import_team_topic_successful', 0)) {
2750
    drupal_set_message(t('Team topic import has already run successfully'), 'warning');
2751
    watchdog(
2752
      'boincimport', 'Team topic import has already run successfully',
2753
      array(), WATCHDOG_WARNING
2754
    );
2755
  }
2756
2757
  if (!variable_get('boincimport_import_team_topic_started', 0)) {
2758
    // Could prepare database tables, if new fields are necessary, etc.
2759
    variable_set('boincimport_import_team_topic_started', 1);
2760
  }
2761
2762
  $pre = variable_get('boincimport_table_prefix', '');
2763
2764
  // Get all team topics to import from BOINC
2765
  db_set_active('boinc_rw');
2766
  $boincteam_topics = db_query('
2767
    SELECT DISTINCT t.id, t.title, t.owner, t.forum, t.locked, t.hidden,
2768
      t.sticky, t.timestamp, t.create_time
2769
    FROM %sthread t
2770
    JOIN %sforum f ON f.id = t.forum
2771
    JOIN %spost p ON p.thread = t.id
2772
    WHERE f.parent_type = 1
2773
    ORDER BY id',
2774
    $pre, $pre, $pre
2775
  );
2776
  $boincteam_topic_count = mysqli_num_rows($boincteam_topics);
0 ignored issues
show
Bug introduced by
$boincteam_topics of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

2776
  $boincteam_topic_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $boincteam_topics);
Loading history...
2777
  $total_team_topic_count = db_result(db_query('
2778
    SELECT COUNT(*) FROM %sthread t
2779
    JOIN %sforum f ON f.id = t.forum
2780
    WHERE f.parent_type = 1', $pre, $pre
2781
  ));
2782
  $empty_topic_count = $total_team_topic_count - $boincteam_topic_count;
2783
  db_set_active('default');
2784
2785
  if (!$boincteam_topic_count) {
2786
    drupal_set_message(
2787
      t('There were no team topics found: Aborting script'), 'warning'
2788
    );
2789
    watchdog('boincimport',
2790
      'There were no team topics found: Aborting script', array(), WATCHDOG_WARNING
2791
    );
2792
    // Release the lock on the import process
2793
    variable_del('boincimport_process_locked');
2794
    return t('There were no team topics found: Aborting script.');
2795
  }
2796
2797
  watchdog('boincimport',
2798
    'Found %count team topics: Beginning Import',
2799
    array('%count' => $boincteam_topic_count), WATCHDOG_INFO
2800
  );
2801
2802
  $operations = array();
2803
  $existing_team_topics = array();
2804
  $duplicates = array();
2805
2806
  // Get the list of team topics already in Drupal to be sure we're not
2807
  // importing any twice
2808
  $result = db_query('
2809
    SELECT nid, topic_id FROM {boincimport_temp_topic}'
2810
  );
2811
  while ($row = db_fetch_object($result)) {
2812
    $existing_team_topics[$row->topic_id] = $row->nid;
2813
  }
2814
2815
  // Create batches to process
2816
  while ($boincteam_topic = db_fetch_object($boincteam_topics)) {
2817
     if (isset($existing_team_topics[$boincteam_topic->id])) {
2818
      // This team topic has already been imported
2819
      $duplicates[] = $boincteam_topic->id;
2820
    }
2821
    else {
2822
      $operations[] = array(
2823
        'boincimport_team_topics_op', array(
2824
          $boincteam_topic
2825
        )
2826
      );
2827
    }
2828
  }
2829
2830
  if ($duplicates) {
2831
    drupal_set_message(t(
2832
      'Skipped @count team topics that were already imported',
2833
      array('@count' => count($duplicates))
2834
    ));
2835
  }
2836
2837
  $batch = array(
2838
    'operations' => $operations,
2839
    'finished' => 'boincimport_team_topics_finished',
2840
    'title' => t('Importing team topics'),
2841
    'init_message' => t('Beginning team topic import...'),
2842
    'progress_message' => t('Processed @current out of @total team topics.'),
2843
    'error_message' => t('Team topic import has encountered an error.'),
2844
  );
2845
2846
  batch_set($batch);
2847
}
2848
2849
/**
2850
 * Batch operation for importing team topics
2851
 * Create a Drupal node from the given BOINC team topic object
2852
 */
2853
function boincimport_team_topics_op($topic, &$context) {
2854
2855
  $input_format = variable_get('boincimport_input_format', 0);
2856
  $success = FALSE;
2857
  $missing_parent = array();
2858
  $empty_topics = array();
2859
2860
  // Verify that the team forum container has been imported
2861
  $team_forum_id = db_result(db_query("
2862
    SELECT tfid FROM {boincteam_forum}
2863
    WHERE boinc_id = %d",
2864
    $topic->forum
2865
  ));
2866
  if (!$team_forum_id) {
2867
    $missing_parent[] = $topic->id;
2868
  }
2869
  else {
2870
    // Get the content of the post that started the topic
2871
    db_set_active('boinc_rw');
2872
    $query = db_query('
2873
      SELECT id, content
2874
      FROM %spost
2875
      WHERE thread = %d
2876
      ORDER BY timestamp ASC
2877
      LIMIT 1',
2878
      $pre, $topic->id);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pre seems to be never defined.
Loading history...
2879
    db_set_active('default');
2880
2881
    // Skip this topic if there are no posts
2882
    if (!$post = db_fetch_object($query)) {
2883
      // Empty topics should have already been filtered out of the import, so
2884
      // consider this an error condition
2885
      $empty_topics[] = $topic->id;
2886
    }
2887
    else {
2888
      // Get the user ID along with other data to define the topic
2889
      $uid = boincuser_lookup_uid($topic->owner);
2890
       if (!$topic->owner) {
2891
        $uid = 0;
2892
      }
2893
2894
      $node_type = 'team_forum';
2895
      $promote = 0;
2896
      $comment = ($topic->locked) ? 1 : 2;
2897
2898
      $post->content = _boincimport_strip_bbcode($post->content);
2899
      $post->content = _boincimport_text_sanitize($post->content);
2900
      $teaser = node_teaser($post->content);
2901
2902
      if ($topic->timestamp < $topic->create_time) {
2903
        $topic->timestamp = $topic->create_time;
2904
      }
2905
2906
      // Construct the thread as a team_forum topic node
2907
      $node = array(
2908
        'type' => $node_type,
2909
        'title' => $topic->title,
2910
        'uid' => $uid,
2911
        'status' => ($topic->hidden) ? 0 : 1,  // published or not
2912
        'promote' => $promote,
2913
        'created' => $topic->create_time,
2914
        'changed' => $topic->timestamp,
2915
        'comment' => $comment,
2916
        'moderate' => 0,
2917
        'body' => $post->content,
2918
        'sticky' => $topic->sticky,
2919
        'format' => $input_format,
2920
        'teaser' => $teaser,
2921
        'tfid' => $team_forum_id,
2922
      );
2923
2924
      // Save the team topic node
2925
      $node = (object) $node; // node_save requires an object form
2926
      node_save($node);
2927
2928
      if ($node->nid) {
2929
        db_query('
2930
          INSERT INTO {boincimport_temp_topic} (topic_id, post_id, nid)
2931
          VALUES (%d, %d, %d)',
2932
          $topic->id, $post->id, $node->nid
2933
        );
2934
        // Hack to keep the topics in correct order
2935
        db_query('
2936
          UPDATE {node_comment_statistics}
2937
          SET last_comment_timestamp = %d
2938
          WHERE nid = %d',
2939
          $node->created, $node->nid
2940
        );
2941
        $success = TRUE;
2942
      }
2943
    }
2944
  }
2945
2946
  $message = '';
2947
  if ($success) {
2948
    // Store some result for post-processing in the finished callback.
2949
    $context['results']['success'][] = $topic->id;
2950
    $message = "Successfully imported team topic {$topic->id}";
2951
  }
2952
  else {
2953
    $context['results']['failure'][] = $topic->id;
2954
    $message = "Failed to import team topic {$topic->id}!";
2955
    watchdog('boincimport',
2956
      'Failed to import team topic @id!',
2957
      array('@id' => $topic->id), WATCHDOG_WARNING
2958
    );
2959
  }
2960
2961
  // Update our progress information.
2962
  $context['sandbox']['progress']++;
2963
  $context['sandbox']['current_topic'] = $topic->id;
2964
  $context['message'] = $message;
2965
2966
  // Update the progress for the batch engine
2967
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
2968
    $context['finished'] = 1;
2969
  }
2970
  else {
2971
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
2972
  }
2973
}
2974
2975
/**
2976
 * Batch 'finished' callback
2977
 */
2978
function boincimport_team_topics_finished($success, $results, $operations) {
2979
  if ($success) {
2980
    // Let's count our successes
2981
    $total_imported = count($results['success']);
2982
    $message = t(
2983
      'Successfully imported @count team topics',
2984
      array('@count' => $total_imported)
2985
    );
2986
    watchdog('boincimport',
2987
      'Successfully imported @count team topics.',
2988
      array('@count' => $total_imported), WATCHDOG_INFO
2989
    );
2990
    // Set the BLAH import successful flag in the variable table
2991
    variable_set('boincimport_import_team_topic_successful', '1');
2992
    $_SESSION['boincimport_stage_selected'] = 'team posts';
2993
  }
2994
  else {
2995
    // An error occurred.
2996
    // $operations contains the operations that remained unprocessed.
2997
    $error_operation = reset($operations);
2998
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

2998
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
2999
  }
3000
  drupal_set_message($message);
3001
3002
  // Release the lock on the import process
3003
  variable_del('boincimport_process_locked');
3004
  drupal_goto('admin/boinc/import/process');
3005
}
3006
3007
3008
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
3009
 * Team forum posts
3010
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
3011
3012
/**
3013
 * Import BOINC team forum posts as Drupal comments
3014
 */
3015
function boincimport_team_forum_posts() {
3016
3017
  // Check whether team forum posts have been successfully imported already
3018
  if (variable_get('boincimport_import_team_post_successful', 0)) {
3019
    drupal_set_message(t('Team forum post import has already run successfully'), 'warning');
3020
    watchdog(
3021
      'boincimport', 'Team forum post import has already run successfully',
3022
      array(), WATCHDOG_WARNING
3023
    );
3024
    // Release the lock on the import process
3025
    variable_del('boincimport_process_locked');
3026
    return;
3027
  }
3028
3029
  if (!variable_get('boincimport_import_team_post_started', 0)) {
3030
    // Could prepare database tables, if new fields are necessary, etc.
3031
    variable_set('boincimport_import_team_post_started', 1);
3032
  }
3033
3034
  $pre = variable_get('boincimport_table_prefix', '');
3035
3036
  // Get the BOINC threads and get a count of team posts to import
3037
  db_set_active('boinc_rw');
3038
  $team_topic_ids = db_query('
3039
    SELECT DISTINCT t.id FROM %sthread t
3040
    JOIN %sforum f ON f.id = t.forum
3041
    JOIN %spost p ON p.thread = t.id
3042
    WHERE f.parent_type = 1
3043
    ORDER BY id', $pre, $pre
3044
  );
3045
  $team_topic_count = db_result(db_query("
3046
    SELECT COUNT(DISTINCT t.id) FROM %sthread t
3047
    JOIN %sforum f ON f.id = t.forum
3048
    JOIN %spost p ON p.thread = t.id
3049
    WHERE f.parent_type = 1", $pre, $pre, $pre
3050
  ));
3051
  $total_team_post_count = db_result(db_query("
3052
    SELECT COUNT(p.id) FROM %spost p
3053
    JOIN %sthread t ON t.id = p.thread
3054
    JOIN %sforum f ON f.id = t.forum
3055
    WHERE f.parent_type = 1", $pre, $pre, $pre
3056
  ));
3057
  $team_post_count = $total_team_post_count - $team_topic_count;
3058
  db_set_active('default');
3059
3060
  if ($team_post_count <= 0) {
3061
    drupal_set_message(
3062
      t('There were no team posts found: Aborting script'), 'warning'
3063
    );
3064
    watchdog('boincimport',
3065
      'There were no team posts found: Aborting script', array(), WATCHDOG_WARNING
3066
    );
3067
    // Release the lock on the import process
3068
    variable_del('boincimport_process_locked');
3069
    return t('There were no posts found: Aborting script.');
3070
  }
3071
3072
  watchdog('boincimport',
3073
    'Found %count team posts: Beginning Import',
3074
    array('%count' => $team_post_count), WATCHDOG_INFO
3075
  );
3076
3077
  $operations = array();
3078
  $existing_posts = array();
3079
  $duplicates = array();
3080
3081
  // Get the list of team posts already in Drupal to be sure we're not
3082
  // importing any twice
3083
  $result = db_query('
3084
    SELECT cid, post_id FROM {boincimport_temp_post}'
3085
  );
3086
  while ($row = db_fetch_object($result)) {
3087
    $existing_posts[$row->post_id] = $row->cid;
3088
  }
3089
3090
  // Create batches to process
3091
  while ($boincteam_topic = db_fetch_object($team_topic_ids)) {
3092
3093
    db_set_active('boinc_rw');
3094
    $boincteam_posts = db_query('
3095
      SELECT id, user, thread, timestamp, content, parent_post, hidden
3096
      FROM %spost
3097
      WHERE thread = %d
3098
      ORDER BY timestamp ASC',
3099
      $pre, $boincteam_topic->id
3100
    );
3101
    db_set_active('default');
3102
3103
    $first_post = true;
3104
3105
    while ($boincteam_post = db_fetch_object($boincteam_posts)) {
3106
3107
      // Skip the first post as it has already been imported as a topic
3108
      if ($first_post) {
3109
        $first_post = false;
3110
        continue;
3111
      }
3112
3113
      if (isset($existing_posts[$boincteam_post->id])) {
3114
        // This post has already been imported
3115
        $duplicates[] = $boincteam_post->id;
3116
      }
3117
      else {
3118
        $operations[] = array(
3119
          'boincimport_team_posts_op', array(
3120
            $boincteam_post
3121
          )
3122
        );
3123
      }
3124
    }
3125
  }
3126
3127
  if ($duplicates) {
3128
    drupal_set_message(t(
3129
      'Skipped @count team posts that were already imported',
3130
      array('@count' => count($duplicates))
3131
    ));
3132
  }
3133
3134
  $batch = array(
3135
    'operations' => $operations,
3136
    'finished' => 'boincimport_team_posts_finished',
3137
    'title' => t('Importing team posts'),
3138
    'init_message' => t('Beginning team post import...'),
3139
    'progress_message' => t('Processed @current out of @total team posts.'),
3140
    'error_message' => t('Team post import has encountered an error.'),
3141
  );
3142
3143
  batch_set($batch);
3144
}
3145
3146
/**
3147
 * Batch operation for importing team posts
3148
 * Create a Drupal comment from the given BOINC team post object
3149
 */
3150
function boincimport_team_posts_op($post, &$context) {
3151
3152
  $input_format = variable_get('boincimport_input_format', 0);
3153
  $success = FALSE;
3154
3155
  // Make sure the post is valid
3156
  if ($post->content) {
3157
3158
    // Get user, node, and parent IDs for the post and sanitize
3159
    $uid = boincuser_lookup_uid($post->user);
3160
    $node = db_fetch_object(db_query('
3161
      SELECT nr.nid, nr.title
3162
      FROM {boincimport_temp_topic} btt
3163
      LEFT JOIN {node_revisions} AS nr ON btt.nid = nr.nid
3164
      WHERE btt.topic_id = %d',
3165
      $post->thread
3166
    ));
3167
    $nid = $node->nid;
3168
    $pid = db_result(db_query('
3169
      SELECT cid
3170
      FROM {boincimport_temp_post}
3171
      WHERE post_id = %d',
3172
      $post->parent_post));
3173
    if (is_null($pid)) $pid = 0;
3174
    if (!$uid) $uid = 0;
3175
3176
    $post->content = _boincimport_strip_bbcode($post->content);
3177
    $post->content = _boincimport_text_sanitize($post->content);
3178
3179
    $topic_reply = db_result(db_query('
3180
      SELECT COUNT(*)
3181
      FROM {comments}
3182
      WHERE nid = %d',
3183
      $nid
3184
    ));
3185
    $post_reply = $pid;
3186
3187
    if ($post_reply OR $topic_reply) {
3188
      // Create a subject for the post from the post content. The body may be in
3189
      // any format, so we:
3190
      //  1) Filter it into HTML
3191
      //  2) Strip out all HTML tags
3192
      //  3) Convert entities back to plain-text.
3193
      // Note: format is checked by check_markup().
3194
      $subject = truncate_utf8(trim(decode_entities(strip_tags(check_markup($post->content, $input_format)))), 29, TRUE);
3195
      // Replace "Quote:" with "RE:"
3196
      $subject = str_replace('Quote:', 'RE: ', $subject);
3197
      // Fringe cases where the comment body is populated only by HTML tags
3198
      // will require a default subject...
3199
      if ($subject === '')
3200
        $subject = "RE: {$node->title}";
3201
    } else {
3202
      // This is the first post in the topic
3203
      $subject = $node->title;
3204
    }
3205
3206
    // Construct the post as a Drupal comment
3207
    $comment = array(
3208
      'pid' => $pid,
3209
      'nid' => $nid,
3210
      'uid' => $uid,
3211
      'subject' => $subject,
3212
      'comment' => $post->content,
3213
      'timestamp' => $post->timestamp,
3214
      'status' => $post->hidden,
3215
      'format' => $input_format
3216
    );
3217
3218
    // Save the comment
3219
    if (boincimport_forum_comment_save($comment)) {
3220
      $success = db_query('
3221
        INSERT INTO {boincimport_temp_post} (post_id, cid)
3222
        VALUES (%d, %d)',
3223
        $post->id, $comment['cid']
3224
      );
3225
    }
3226
  }
3227
3228
  $message = '';
3229
  if ($success) {
3230
    // Store some result for post-processing in the finished callback.
3231
    $context['results']['success'][] = $post->id;
3232
    $message = "Successfully imported team post {$post->id}";
3233
  }
3234
  else {
3235
    $context['results']['failure'][] = $post->id;
3236
    $message = "Failed to import team post {$post->id}!";
3237
    watchdog('boincimport',
3238
      'Failed to import team post @id!',
3239
      array('@id' => $post->id), WATCHDOG_WARNING
3240
    );
3241
  }
3242
3243
  // Update our progress information.
3244
  $context['sandbox']['progress']++;
3245
  $context['sandbox']['current_post'] = $post->id;
3246
  $context['message'] = $message;
3247
3248
  // Update the progress for the batch engine
3249
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
3250
    $context['finished'] = 1;
3251
  }
3252
  else {
3253
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
3254
  }
3255
}
3256
3257
/**
3258
 * Batch 'finished' callback
3259
 */
3260
function boincimport_team_posts_finished($success, $results, $operations) {
3261
  if ($success) {
3262
    // Let's count our successes
3263
    $total_imported = count($results['success']);
3264
    $message = t(
3265
      'Successfully imported @count team posts',
3266
      array('@count' => $total_imported)
3267
    );
3268
    watchdog('boincimport',
3269
      'Successfully imported @count team posts.',
3270
      array('@count' => $total_imported), WATCHDOG_INFO
3271
    );
3272
    // Set the team post import successful flag in the variable table
3273
    variable_set('boincimport_import_team_post_successful', '1');
3274
    $_SESSION['boincimport_stage_selected'] = 'url';
3275
  }
3276
  else {
3277
    // An error occurred.
3278
    // $operations contains the operations that remained unprocessed.
3279
    $error_operation = reset($operations);
3280
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

3280
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
3281
  }
3282
  drupal_set_message($message);
3283
3284
  // Release the lock on the import process
3285
  variable_del('boincimport_process_locked');
3286
  drupal_goto('admin/boinc/import/process');
3287
}
3288
3289
3290
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
3291
 * Subscriptions
3292
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
3293
3294
/**
3295
 * Import subscriptions for users
3296
 */
3297
function boincimport_subscriptions() {
3298
3299
  // Check whether subscriptions have been successfully imported already
3300
  if (variable_get('boincimport_import_subscription_successful', 0)) {
3301
    drupal_set_message(t('Subscription import has already run successfully'), 'warning');
3302
    watchdog(
3303
      'boincimport', 'Subscription import has already run successfully',
3304
      array(), WATCHDOG_WARNING
3305
    );
3306
  }
3307
3308
  if (!variable_get('boincimport_import_subscription_started', 0)) {
3309
    // Could prepare database tables, if new fields are necessary, etc.
3310
    variable_set('boincimport_import_subscription_started', 1);
3311
  }
3312
3313
  $pre = variable_get('boincimport_table_prefix', '');
3314
3315
  // Get users with subscriptions to import
3316
  db_set_active('boinc_rw');
3317
  $users_with_subscriptions = db_query('
3318
    SELECT DISTINCT userid
3319
    FROM %ssubscriptions
3320
    ORDER BY userid ASC',
3321
    $pre
3322
  );
3323
  $user_count = mysqli_num_rows($users_with_subscriptions);
0 ignored issues
show
Bug introduced by
$users_with_subscriptions of type boolean|resource is incompatible with the type mysqli_result expected by parameter $result of mysqli_num_rows(). ( Ignorable by Annotation )

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

3323
  $user_count = mysqli_num_rows(/** @scrutinizer ignore-type */ $users_with_subscriptions);
Loading history...
3324
  db_set_active('default');
3325
3326
  if (!$user_count) {
3327
    drupal_set_message(
3328
      t('There were no subscriptions found: Aborting script'), 'warning'
3329
    );
3330
    watchdog('boincimport',
3331
      'There were no subscriptions found: Aborting script', array(), WATCHDOG_WARNING
3332
    );
3333
    // Release the lock on the import process
3334
    variable_del('boincimport_process_locked');
3335
    return t('There were no subscriptions found: Aborting script.');
3336
  }
3337
3338
  watchdog('boincimport',
3339
    'Found %count users with subscriptions: Beginning import',
3340
    array('%count' => $user_count), WATCHDOG_INFO
3341
  );
3342
3343
  $operations = array();
3344
3345
  // Create batches to process
3346
  while ($subscribed_user = db_fetch_object($users_with_subscriptions)) {
3347
    $operations[] = array(
3348
      'boincimport_subscriptions_op', array(
3349
        $subscribed_user->userid
3350
      )
3351
    );
3352
  }
3353
3354
  $batch = array(
3355
    'operations' => $operations,
3356
    'finished' => 'boincimport_subscriptions_finished',
3357
    'title' => t('Importing subscriptions'),
3358
    'init_message' => t('Beginning subscription import...'),
3359
    'progress_message' => t('Processed @current out of @total subscriptions.'),
3360
    'error_message' => t('Subscription import has encountered an error.'),
3361
  );
3362
3363
  batch_set($batch);
3364
}
3365
3366
/**
3367
 * Batch operation for importing subscriptions
3368
 * Import subscriptions for the given user
3369
 */
3370
function boincimport_subscriptions_op($boincuser_id, &$context) {
3371
3372
  // Get the drupal user and pull subscriptions
3373
  $uid = get_drupal_id($boincuser_id);
3374
  $count = boincuser_pull_subscriptions($uid);
3375
3376
  $message = '';
3377
  if ($count) {
3378
    // Store some result for post-processing in the finished callback.
3379
    $context['results']['success'][] = $boincuser_id;
3380
    $context['results']['subscriptions'][$boincuser_id] = $count;
3381
    $message = "Successfully imported {$count} subscriptions for user {$boincuser_id}";
3382
  }
3383
  else {
3384
    $context['results']['failure'][] = $boincuser_id;
3385
    $message = "Failed to import subscriptions for user {$boincuser_id}!";
3386
    watchdog('boincimport',
3387
      'Failed to import subscriptions for user @id!',
3388
      array('@id' => $boincuser_id), WATCHDOG_WARNING
3389
    );
3390
  }
3391
3392
  // Update our progress information.
3393
  $context['sandbox']['progress']++;
3394
  $context['sandbox']['current_user'] = $boincuser_id;
3395
  $context['message'] = $message;
3396
3397
  // Update the progress for the batch engine
3398
  if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
3399
    $context['finished'] = 1;
3400
  }
3401
  else {
3402
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
3403
  }
3404
}
3405
3406
/**
3407
 * Batch 'finished' callback
3408
 */
3409
function boincimport_subscriptions_finished($success, $results, $operations) {
3410
  if ($success) {
3411
    // Let's count our successes
3412
    $user_count = count($results['success']);
3413
    $subscriptions_imported = array_sum($results['subscriptions']);
3414
    $message = t(
3415
      'Successfully imported @count subscriptions for @distinct users',
3416
      array('@count' => $subscriptions_imported, '@distinct' => $user_count)
3417
    );
3418
    watchdog('boincimport',
3419
      'Successfully imported @count subscriptions for @distinct users.',
3420
      array('@count' => $subscriptions_imported, '@distinct' => $user_count),
3421
      WATCHDOG_INFO
3422
    );
3423
    // Set the subscription import successful flag in the variable table
3424
    variable_set('boincimport_import_subscription_successful', '1');
3425
    $_SESSION['boincimport_stage_selected'] = 'url';
3426
  }
3427
  else {
3428
    // An error occurred.
3429
    // $operations contains the operations that remained unprocessed.
3430
    $error_operation = reset($operations);
3431
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

3431
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
3432
  }
3433
  drupal_set_message($message);
3434
3435
  // Release the lock on the import process
3436
  variable_del('boincimport_process_locked');
3437
  drupal_goto('admin/boinc/import/process');
3438
}
3439
3440
3441
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
3442
 * URLs
3443
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
3444
/**
3445
 * Update relative BOINC URLs to work with Drupal
3446
 */
3447
function boincimport_replace_urls() {
3448
3449
  // Check whether URLs have already been fixed
3450
  if (variable_get('boincimport_replace_url_successful', 0)) {
3451
    drupal_set_message(t('URLs have already been updated'), 'warning');
3452
    watchdog(
3453
      'boincimport', 'URLs have already been updated',
3454
      array(), WATCHDOG_WARNING
3455
    );
3456
  }
3457
3458
  if (!variable_get('boincimport_replace_url_started', 0)) {
3459
    // Could prepare database tables, if new fields are necessary, etc.
3460
    variable_set('boincimport_replace_url_started', 1);
3461
  }
3462
3463
  // Get the count of nodes and comments to process for URL updates
3464
  $node_count = db_result(db_query('
3465
    SELECT COUNT(DISTINCT btt.nid)
3466
    FROM {boincimport_temp_topic} AS btt
3467
    LEFT JOIN {node_revisions} AS nr ON btt.nid = nr.nid'
3468
  ));
3469
3470
  $comment_count = db_result(db_query('
3471
    SELECT COUNT(c.cid)
3472
    FROM {boincimport_temp_post} AS p
3473
    LEFT JOIN {comments} AS c ON p.cid = c.cid'
3474
  ));
3475
3476
  $pm_count = db_result(db_query('
3477
    SELECT COUNT(*)
3478
    FROM {pm_message} pm'
3479
  ));
3480
3481
  if (!$node_count AND !$comment_count AND !$pm_count) {
3482
    drupal_set_message(
3483
      t('There were no nodes, comments, or private messages found: Aborting script'), 'warning'
3484
    );
3485
    watchdog('boincimport',
3486
      'There were no nodes,comments, or private messages found: Aborting script', array(), WATCHDOG_WARNING
3487
    );
3488
    // Release the lock on the import process
3489
    variable_del('boincimport_process_locked');
3490
    return t('There were no nodes, comments, or private messages found: Aborting script.');
3491
  }
3492
3493
  watchdog('boincimport',
3494
    'Found %node_count nodes, %comment_count comments, and %pm_count private messages: Updating URLs...',
3495
    array(
3496
      '%node_count' => $node_count,
3497
      '%comment_count' => $comment_count,
3498
      '%pm_count' => $pm_count,
3499
    ),
3500
    WATCHDOG_INFO
3501
  );
3502
3503
  $operations = array();
3504
  $batch_size = 100;
3505
3506
  // Create node batches to process
3507
  for ($offset = 0; $offset < $node_count; $offset+=$batch_size) {
3508
    $nodes_per_batch = $batch_size;
3509
    if ($offset + $batch_size > $node_count) {
3510
      $nodes_per_batch = $node_count - $offset;
3511
    }
3512
    $operations[] = array(
3513
      'boincimport_replace_urls_node_op', array(
3514
        $offset, $nodes_per_batch
3515
      )
3516
    );
3517
  }
3518
  // Add comment batches
3519
  for ($offset = 0; $offset < $comment_count; $offset+=$batch_size) {
3520
    $comments_per_batch = $batch_size;
3521
    if ($offset + $batch_size > $comment_count) {
3522
      $comments_per_batch = $comment_count - $offset;
3523
    }
3524
    $operations[] = array(
3525
      'boincimport_replace_urls_comment_op', array(
3526
        $offset, $comments_per_batch
3527
      )
3528
    );
3529
  }
3530
  // And don't forget to process private messages
3531
  for ($offset = 0; $offset < $pm_count; $offset+=$batch_size) {
3532
    $messages_per_batch = $batch_size;
3533
    if ($offset + $batch_size > $pm_count) {
3534
      $messages_per_batch = $pm_count - $offset;
3535
    }
3536
    $operations[] = array(
3537
      'boincimport_replace_urls_pm_op', array(
3538
        $offset, $messages_per_batch
3539
      )
3540
    );
3541
  }
3542
3543
  $batch = array(
3544
    'operations' => $operations,
3545
    'finished' => 'boincimport_replace_urls_finished',
3546
    'title' => t('Updating URLs...'),
3547
    'init_message' => t('Beginning URL update...'),
3548
    'progress_message' => t('Processed URLs in @current out of @total batches (@size items per batch).', array(
3549
      '@size' => $batch_size,
3550
    )),
3551
    'error_message' => t('URL update has encountered an error.'),
3552
  );
3553
3554
  batch_set($batch);
3555
}
3556
3557
/**
3558
 * Batch operation for updating URLs in nodes
3559
 * Find URLs for the old system and update them with Drupal paths
3560
 */
3561
function boincimport_replace_urls_node_op($offset, $batch_size, &$context) {
3562
  // Initialize the batch, if needed
3563
  if (!isset($context['sandbox']['progress'])) {
3564
    $context['sandbox']['progress'] = 0;
3565
    $context['sandbox']['max'] = $batch_size;
3566
  }
3567
3568
  $input_format = variable_get('boincimport_input_format', 0);
3569
3570
  // Since topics have just been imported, there should be only one vid for
3571
  // each nid, so we can update node_revisions by nid
3572
  // Get nodes to process
3573
  $nodes = db_query('
3574
    SELECT btt.nid, nr.body, nr.teaser
3575
    FROM {boincimport_temp_topic} AS btt
3576
    LEFT JOIN {node_revisions} AS nr ON btt.nid = nr.nid
3577
    ORDER BY btt.nid
3578
    LIMIT %d,%d',
3579
    $offset, $batch_size
3580
  );
3581
3582
  while ($node = db_fetch_object($nodes)) {
3583
    $updated = FALSE;
3584
3585
    // Update URLs in node contents
3586
    $original_body = $node->body;
3587
    $original_teaser = $node->teaser;
3588
    $node->body = _boincimport_replace_links($node->body);
3589
    $node->teaser = _boincimport_replace_links($node->teaser);
3590
    if ($node->body != $original_body OR $node->teaser != $original_teaser) {
3591
      $updated = db_query("
3592
        UPDATE {node_revisions}
3593
        SET body= '%s', teaser = '%s'
3594
        WHERE nid = %d",
3595
        $node->body, $node->teaser, $node->nid
3596
      );
3597
    }
3598
3599
    $message = '';
3600
    $context['results']['success'][] = $node->nid;
3601
    if ($updated) {
3602
      // Store some result for post-processing in the finished callback.
3603
      $context['results']['nodes']['updated'][] = $node->nid;
3604
      $message = "Successfully updated node {$node->nid}";
3605
    }
3606
    else {
3607
      $message = "No changes made to node {$node->nid}!";
3608
    }
3609
3610
    // Update our progress information.
3611
    $context['sandbox']['progress']++;
3612
    $context['sandbox']['current_node'] = $node->nid;
3613
    $context['message'] = $message;
3614
3615
    // Update the progress for the batch engine
3616
    if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
3617
      $context['finished'] = 1;
3618
    }
3619
    else {
3620
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
3621
    }
3622
  }
3623
}
3624
3625
/**
3626
 * Batch operation for updating URLs in comments
3627
 * Find URLs for the old system and update them with Drupal paths
3628
 */
3629
function boincimport_replace_urls_comment_op($offset, $batch_size, &$context) {
3630
  // Initialize the batch, if needed
3631
  if (!isset($context['sandbox']['progress'])) {
3632
    $context['sandbox']['progress'] = 0;
3633
    $context['sandbox']['max'] = $batch_size;
3634
  }
3635
3636
  $input_format = variable_get('boincimport_input_format', 0);
3637
3638
  // Get comments to process
3639
  $comments = db_query('
3640
    SELECT c.cid, c.comment
3641
    FROM {boincimport_temp_post} AS p
3642
    LEFT JOIN {comments} AS c ON p.cid = c.cid
3643
    ORDER BY c.cid
3644
    LIMIT %d,%d',
3645
    $offset, $batch_size
3646
  );
3647
3648
  while ($comment = db_fetch_object($comments)) {
3649
    $updated = FALSE;
3650
3651
    // Update URLs in comment contents
3652
    $original_comment = $comment->comment;
3653
    $comment->comment = _boincimport_replace_links($comment->comment);
3654
    if ($comment->comment != $original_comment) {
3655
      $updated = db_query("
3656
        UPDATE {comments}
3657
        SET comment= '%s'
3658
        WHERE cid = %d",
3659
        $comment->comment, $comment->cid
3660
      );
3661
    }
3662
3663
    $message = '';
3664
    $context['results']['success'][] = $comment->cid;
3665
    if ($updated) {
3666
      // Store some result for post-processing in the finished callback.
3667
      $context['results']['comments']['updated'][] = $comment->cid;
3668
      $message = "Successfully updated comment {$comment->cid}";
3669
    }
3670
    else {
3671
      $message = "No changes made to comment {$comment->cid}!";
3672
    }
3673
3674
    // Update our progress information.
3675
    $context['sandbox']['progress']++;
3676
    $context['sandbox']['current_comment'] = $comment->cid;
3677
    $context['message'] = $message;
3678
3679
    // Update the progress for the batch engine
3680
    if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
3681
      $context['finished'] = 1;
3682
    }
3683
    else {
3684
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
3685
    }
3686
  }
3687
}
3688
3689
/**
3690
 * Batch operation for updating URLs in private messages
3691
 * Find URLs for the old system and update them with Drupal paths
3692
 */
3693
function boincimport_replace_urls_pm_op($offset, $batch_size, &$context) {
3694
  // Initialize the batch, if needed
3695
  if (!isset($context['sandbox']['progress'])) {
3696
    $context['sandbox']['progress'] = 0;
3697
    $context['sandbox']['max'] = $batch_size;
3698
  }
3699
3700
  $input_format = variable_get('boincimport_input_format', 0);
3701
3702
  // Get private messages to process
3703
  $messages = db_query('
3704
    SELECT pm.mid, pm.body
3705
    FROM {pm_message} pm
3706
    ORDER BY pm.mid
3707
    LIMIT %d,%d',
3708
    $offset, $batch_size
3709
  );
3710
3711
  while ($pm = db_fetch_object($messages)) {
3712
    $updated = FALSE;
3713
3714
    // Update URLs in private message body
3715
    $original_pm_body = $pm->body;
3716
    $pm->body = _boincimport_replace_links($pm->body);
3717
    if ($pm->body != $original_pm_body) {
3718
      $updated = db_query("
3719
        UPDATE {pm_message}
3720
        SET body= '%s'
3721
        WHERE mid = %d",
3722
        $pm->body, $pm->mid
3723
      );
3724
    }
3725
3726
    $message = '';
3727
    $context['results']['success'][] = $pm->mid;
3728
    if ($updated) {
3729
      // Store some result for post-processing in the finished callback.
3730
      $context['results']['pm']['updated'][] = $pm->mid;
3731
      $message = "Successfully updated private message {$pm->mid}";
3732
    }
3733
    else {
3734
      $message = "No changes made to private message {$pm->mid}!";
3735
    }
3736
3737
    // Update our progress information.
3738
    $context['sandbox']['progress']++;
3739
    $context['sandbox']['current_pm'] = $pm->mid;
3740
    $context['message'] = $message;
3741
3742
    // Update the progress for the batch engine
3743
    if ($context['sandbox']['progress'] >= $context['sandbox']['max']) {
3744
      $context['finished'] = 1;
3745
    }
3746
    else {
3747
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
3748
    }
3749
  }
3750
}
3751
3752
/**
3753
 * Batch 'finished' callback
3754
 */
3755
function boincimport_replace_urls_finished($success, $results, $operations) {
3756
  if ($success) {
3757
    // Let's count our successes
3758
    $total_processed = count($results['success']);
3759
    $nodes_updated = count($results['nodes']['updated']);
3760
    $comments_updated = count($results['comments']['updated']);
3761
    $private_messages_updated = count($results['pm']['updated']);
3762
    $message = t(
3763
      'Successfully processed @count nodes, comments, and private messages (@nodes_updated nodes, @comments_updated comments, and @pm_updated private messages were updated)',
3764
      array(
3765
        '@count' => $total_processed,
3766
        '@nodes_updated' => $nodes_updated,
3767
        '@comments_updated' => $comments_updated,
3768
        '@pm_updated' => $private_messages_updated,
3769
      )
3770
    );
3771
    if ($private_messages_updated) {
3772
      watchdog('boincimport',
3773
        'Updated URLs in these private_messages: @mid_list',
3774
        array(
3775
          '@mid_list' => implode(', ', $results['pm']['updated']),
3776
        ),
3777
        WATCHDOG_INFO
3778
      );
3779
    }
3780
    if ($comments_updated) {
3781
      watchdog('boincimport',
3782
        'Updated URLs in these comments: @cid_list',
3783
        array(
3784
          '@cid_list' => implode(', ', $results['comments']['updated']),
3785
        ),
3786
        WATCHDOG_INFO
3787
      );
3788
    }
3789
    if ($nodes_updated) {
3790
      watchdog('boincimport',
3791
        'Updated URLs in these nodes: @nid_list',
3792
        array(
3793
          '@nid_list' => implode(', ', $results['nodes']['updated']),
3794
        ),
3795
        WATCHDOG_INFO
3796
      );
3797
    }
3798
    watchdog('boincimport',
3799
      'Successfully processed @count nodes, comments, and private messages (@nodes_updated nodes, @comments_updated comments, and @pm_updated private messages were updated)',
3800
      array(
3801
        '@count' => $total_processed,
3802
        '@nodes_updated' => $nodes_updated,
3803
        '@comments_updated' => $comments_updated,
3804
        '@pm_updated' => $private_messages_updated,
3805
      ),
3806
      WATCHDOG_INFO
3807
    );
3808
    // Set the replace URLs successful flag in the variable table
3809
    variable_set('boincimport_replace_urls_successful', '1');
3810
    $_SESSION['boincimport_stage_selected'] = 'users';
3811
  }
3812
  else {
3813
    // An error occurred.
3814
    // $operations contains the operations that remained unprocessed.
3815
    $error_operation = reset($operations);
3816
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . print_r($error_operation[0], TRUE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($error_operation[0], TRUE) of type string|true 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

3816
    $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments :' . /** @scrutinizer ignore-type */ print_r($error_operation[0], TRUE);
Loading history...
3817
  }
3818
  drupal_set_message($message);
3819
3820
  // Release the lock on the import process
3821
  variable_del('boincimport_process_locked');
3822
  drupal_goto('admin/boinc/import/process');
3823
}
3824
3825
3826
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
3827
 * Clean up
3828
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
3829
3830
/**
3831
 * Remove temporary variables, clear caches, etc.
3832
 */
3833
function boincimport_process_cleanup() {
3834
  db_set_active('default');
3835
3836
  variable_del('boincimport_base_url_boinc');
3837
  variable_del('boincimport_base_url_drupal');
3838
  variable_del('boincimport_import_user_successful');
3839
  variable_del('boincimport_import_user_started');
3840
  variable_del('boincimport_import_team_successful');
3841
  variable_del('boincimport_import_team_started');
3842
  variable_del('boincimport_import_category_successful');
3843
  variable_del('boincimport_replace_url_successful');
3844
  variable_del('boincimport_import_category_started');
3845
  variable_del('boincimport_import_topic_successful');
3846
  variable_del('boincimport_import_topic_started');
3847
  variable_del('boincimport_import_post_successful');
3848
  variable_del('boincimport_import_post_started');
3849
  variable_del('boincimport_team_forum_successful');
3850
  variable_del('boincimport_team_topic_successful');
3851
  variable_del('boincimport_team_post_successful');
3852
  variable_del('boincimport_team_post_started');
3853
  variable_del('boincimport_ready');
3854
  variable_del('boincimport_db_url');
3855
  variable_del('boincimport_tested');
3856
  variable_del('boincimport_db_configured');
3857
  variable_del('boincimport_table_prefix');
3858
  variable_del('boincimport_team_types');
3859
  variable_del('boincimport_time_limit');
3860
  variable_del('boincimport_import_lurkers');
3861
  variable_del('boincimport_import_polls');
3862
  variable_del('boincimport_import_poll_started');
3863
  variable_del('boincimport_import_poll_successful');
3864
  variable_del('boincimport_import_pm_successful');
3865
  variable_del('boincimport_encode');
3866
  variable_del('boincimport_encoding_phpbb');
3867
  variable_del('boincimport_encoding_drupal');
3868
  variable_del('boincimport_version');
3869
3870
  db_query('DELETE FROM {cache}');
3871
}
3872
3873
/**
3874
 * Helper Functions
3875
 */
3876
3877
function boincimport_forum_comment_save(&$edit) {
3878
  // Here we are building the thread field.  See the comment in comment_render().
3879
  if ($edit['pid'] == 0) {
3880
    // This is a comment with no parent comment (depth 0): we start by retrieving
3881
    // the maximum thread level.
3882
    $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
3883
    // Strip the "/" from the end of the thread.
3884
    $max = rtrim($max, '/');
0 ignored issues
show
Bug introduced by
It seems like $max can also be of type false; however, parameter $string of rtrim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

3884
    $max = rtrim(/** @scrutinizer ignore-type */ $max, '/');
Loading history...
3885
    $thread = int2vancode(vancode2int($max)+1) .'/';
3886
  } else {
3887
    // This is comment with a parent comment: we increase the part of the thread
3888
    // value at the proper depth.
3889
    $parent = db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid = %d', $edit['pid']));
3890
    // Strip the "/" from the end of the parent thread.
3891
    $parent->thread = (string) rtrim((string) $parent->thread, '/');
3892
    // Get the max value in _this_ thread.
3893
    $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid']));
3894
    if ($max == '') {
3895
      // First child of this parent.
3896
      $thread = $parent->thread .'.'. int2vancode(1) .'/';
3897
    } else {
3898
      // Strip the "/" at the end of the thread.
3899
      $max = rtrim($max, '/');
3900
      // We need to get the value at the correct depth.
3901
      $parts = explode('.', $max);
3902
      $parent_depth = count(explode('.', $parent->thread));
3903
      $last = $parts[$parent_depth];
3904
      // Finally, build the thread field for this new comment.
3905
      $thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';
3906
    }
3907
  }
3908
3909
  $status = 0; // 1 - not published, 0 - published
3910
  $format = variable_get('boincimport_input_format', 0);
3911
  $score = 0; // 0 default value, comments get higher score depending on the author's roles
3912
  $users = serialize(array(0 => 1));  // default value for everybody!!
3913
3914
  if ($edit['uid'] === $user->uid) { // '===' because we want to modify anonymous users too
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user does not exist. Did you maybe mean $users?
Loading history...
3915
    $edit['name'] = $user->name;
3916
  }
3917
3918
  $success = db_query("INSERT INTO {comments} (nid, pid, uid, subject, comment, format, hostname, timestamp, status, thread, name) VALUES (%d, %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s')", $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], ip_address(), $edit['timestamp'], $edit['status'], $thread, $edit['name']);
3919
  if ($success) {
3920
    $edit['cid'] = db_last_insert_id('comments', 'cid');
3921
    _comment_update_node_statistics($edit['nid']);
3922
  }
3923
  return $success;
3924
}
3925
3926
/**
3927
 * Strips text of extra phpbb3 markup and if requested, also strips all bbcode from text.
3928
 */
3929
function _boincimport_strip_bbcode($text) {
3930
  // Strip the text of extra markup - regular expressions taken from phpbb3 includes/function.php, function get_preg_expression().
3931
  $match = array(
3932
    '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
3933
    '#<!\-\- l \-\-><a (?:class="[\w-]+" )?href="(.*?)(?:(&amp;|\?)sid=[0-9a-f]{32})?">.*?</a><!\-\- l \-\->#',
3934
    '#<!\-\- ([mw]) \-\-><a (?:class="[\w-]+" )?href="(.*?)">.*?</a><!\-\- \1 \-\->#',
3935
    '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
3936
    '#<!\-\- .*? \-\->#s',
3937
    '#<.*?>#s',
3938
  );
3939
  $replace = array('$1', '$1', '$2', '$1', '', '');
3940
  $text = preg_replace($match, $replace, $text);
3941
3942
  // If BBcode conversion to has been selected, the following will convert the
3943
  // BBcode to normal html
3944
  if (variable_get('boincimport_bbcode', 0)) {
3945
    $input_format = variable_get('boincimport_input_format', 0);
3946
    $text = bbcode_filter('process', 0 , $input_format, $text);
3947
  }
3948
  return $text;
3949
}
3950
3951
/**
3952
 * Function to properly encode strings.
3953
 */
3954
function _boincimport_text_sanitize($text) {
3955
  $input_format = variable_get('boincimport_input_format', 0);
3956
  $text = html_entity_decode($text, ENT_QUOTES, 'utf-8');
3957
  // Be sure the text is filtered for the default input format
3958
  $text = check_markup($text, $input_format);
3959
  return $text;
3960
}
3961
3962
3963
/**
3964
 * Replace all types of links.
3965
 */
3966
function _boincimport_replace_links($html) {
3967
3968
  $transformer = new BoincImportUrlTransformer();
3969
3970
  // Update links to posts, threads, and forums
3971
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)forum_thread\.php\?id=(\d+)&postid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformPostLinks'), $html);
3972
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)forum_thread\.php\?id=(\d+)(&\w+=\w*)*?(#(\d+)?)}i', array($transformer, 'transformOldPostLinks'), $html);
3973
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)forum_thread\.php\?id=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformTopicLinks'), $html);
3974
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)forum_forum\.php\?id=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformForumLinks'), $html);
3975
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)show_user\.php\?userid=(\d+)((&\w+=\w*)+)?}i', array($transformer, 'transformUserLinks'), $html);
3976
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)workunit\.php\?wuid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformWorkUnitLinks'), $html);
3977
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)result\.php\?resultid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformResultLinks'), $html);
3978
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)results\.php\?userid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformUserResultsLinks'), $html);
3979
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)results\.php\?hostid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformHostResultsLinks'), $html);
3980
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)show_host_detail\.php\?hostid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformHostLinks'), $html);
3981
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)hosts_user\.php\?userid=(\d+)(&\w+=\w*)*?}i', array($transformer, 'transformUserHostsLinks'), $html);
3982
3983
  // Update any links to the top level index
3984
  $html = preg_replace_callback('{(?:(http|https)://([^\s]*?)|href="(?:/)?)forum_index.php}i', array($transformer, 'transformForumIndexLinks'), $html);
3985
3986
  return $html;
3987
}
3988
3989
/**
3990
 * Limit redundancy by using this class to do URL transformations
3991
 */
3992
class BoincImportUrlTransformer {
3993
3994
  var $basePath;
3995
  var $boincDomain;
3996
  var $drupalDomain;
3997
3998
  /**
3999
   * Constructor
4000
   */
4001
  function __construct() {
4002
    global $base_url;
4003
    global $base_path;
4004
    $boinc_base_urls = variable_get('boincimport_base_url_boinc', '');
4005
    $drupal_base_url = variable_get('boincimport_base_url_drupal', $base_url);
4006
    $this->basePath = $base_path;
4007
    $this->drupalDomain = parse_url($drupal_base_url, PHP_URL_HOST);
4008
    $this->boincDomains = array();
4009
    $boinc_base_urls = preg_split('/\s+/', $boinc_base_urls);
4010
    foreach ($boinc_base_urls as $url) {
4011
      $domain = parse_url($url, PHP_URL_HOST);
4012
      if ($domain) {
4013
        $this->boincDomains[$domain] = TRUE;
4014
      }
4015
    }
4016
    if (!$this->boincDomains) {
4017
      watchdog('boincimport', 'No valid BOINC base URLs found to transform!',
4018
        array(), WATCHDOG_WARNING);
4019
    }
4020
  }
4021
4022
  // old-style constructor for backwards compatibility
4023
  function BoincImportUrlTransformer() {
4024
    self::__construct();
0 ignored issues
show
Bug Best Practice introduced by
The method BoincImportUrlTransformer::__construct() is not static, but was called statically. ( Ignorable by Annotation )

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

4024
    self::/** @scrutinizer ignore-call */ 
4025
          __construct();
Loading history...
4025
  }
4026
4027
  /**
4028
   * Get what the new base URL should be (needed for every transformation)
4029
   */
4030
  function getNewBaseUrl($matches) {
4031
    $http = $matches[1];
4032
    $domain = trim($matches[2], '/');
4033
    if ($http) {
4034
      if (isset($this->boincDomains[$domain])) {
4035
        // This is a URL configured to be transformed
4036
        return "{$http}://{$this->drupalDomain}{$this->basePath}";
4037
      }
4038
      else {
4039
        // This URL should not be transformed
4040
        return NULL;
4041
      }
4042
    }
4043
    else {
4044
      // This is a relative URL
4045
      return $this->basePath;
4046
    }
4047
  }
4048
4049
  /**
4050
   * Replace links to specific posts. If the given post is the first in the
4051
   * thread, it is a topic node in Drupal, not a comment.
4052
   */
4053
  function transformPostLinks($matches) {
4054
    $link = $matches[0];
4055
    $newBaseUrl = $this->getNewBaseUrl($matches);
4056
    if ($newBaseUrl !== NULL) {
4057
      $id = db_result(db_query('
4058
        SELECT p.cid
4059
        FROM {boincimport_temp_post} p
4060
        WHERE p.post_id = %d',
4061
        $matches[4]
4062
      ));
4063
      if ($id) {
4064
        $link = "{$newBaseUrl}goto/comment/{$id}";
4065
      }
4066
      else {
4067
        // This post is not in the post import table, so it's probably a topic
4068
        $link = $this->transformTopicLinks($matches);
4069
      }
4070
    }
4071
    return $link;
4072
  }
4073
4074
  /**
4075
   * Replace links that include anchors to specific posts. If the given post is
4076
   * the first in the thread, it is a topic node in Drupal, not a comment.
4077
   */
4078
  function transformOldPostLinks($matches) {
4079
    $link = $matches[0];
4080
    $newBaseUrl = $this->getNewBaseUrl($matches);
4081
    if ($newBaseUrl !== NULL) {
4082
      $id = db_result(db_query('
4083
        SELECT p.cid
4084
        FROM {boincimport_temp_post} p
4085
        WHERE p.post_id = %d',
4086
        $matches[6]
4087
      ));
4088
      if ($id) {
4089
        $link = "{$newBaseUrl}goto/comment/{$id}";
4090
      }
4091
      else {
4092
        // This post is not in the post import table, so it's probably a topic
4093
        $link = $this->transformTopicLinks($matches);
4094
      }
4095
    }
4096
    return $link;
4097
  }
4098
4099
  function transformTopicLinks($matches) {
4100
    $link = $matches[0];
4101
    $newBaseUrl = $this->getNewBaseUrl($matches);
4102
    if ($newBaseUrl !== NULL) {
4103
      $id = db_result(db_query('
4104
        SELECT nid
4105
        FROM {boincimport_temp_topic}
4106
        WHERE topic_id = %d',
4107
        $matches[3]
4108
      ));
4109
      $link = "{$newBaseUrl}node/{$id}";
4110
    }
4111
    return $link;
4112
  }
4113
4114
  function transformForumLinks($matches) {
4115
    $link = $matches[0];
4116
    $newBaseUrl = $this->getNewBaseUrl($matches);
4117
    if ($newBaseUrl !== NULL) {
4118
      $forum = db_fetch_object(db_query('
4119
        SELECT tid
4120
        FROM {boincimport_temp_forum}
4121
        WHERE forum_id = %d',
4122
        $matches[3]
4123
      ));
4124
      $link = "{$newBaseUrl}community/forum/{$forum->tid}";
4125
    }
4126
    return $link;
4127
  }
4128
4129
  function transformUserLinks($matches) {
4130
    $link = $matches[0];
4131
    $newBaseUrl = $this->getNewBaseUrl($matches);
4132
    if ($newBaseUrl !== NULL) {
4133
      // Make sure this isn't an RPC link (no need to transform those)
4134
      if (!$matches[5]) {
4135
        // TODO: This regex doesn't seem to capture the format=xml part of the
4136
        // URL, making it impossible to distinguish if this is an RPC or not...
4137
        //watchdog('DEBUG', 'matches: @m', array('@m' => print_r($matches,true)), WATCHDOG_DEBUG);
4138
        $uid = boincuser_lookup_uid($matches[3]);
4139
        $link = "{$newBaseUrl}account/{$uid}";
4140
      }
4141
    }
4142
    return $link;
4143
  }
4144
4145
  function transformWorkUnitLinks($matches) {
4146
    $link = $matches[0];
4147
    $newBaseUrl = $this->getNewBaseUrl($matches);
4148
    if ($newBaseUrl !== NULL) {
4149
      $id = $matches[3];
4150
      $link = "{$newBaseUrl}workunit/{$id}";
4151
    }
4152
    return $link;
4153
  }
4154
4155
  function transformResultLinks($matches) {
4156
    $link = $matches[0];
4157
    $newBaseUrl = $this->getNewBaseUrl($matches);
4158
    if ($newBaseUrl !== NULL) {
4159
      $id = $matches[3];
4160
      $link = "{$newBaseUrl}task/{$id}";
4161
    }
4162
    return $link;
4163
  }
4164
4165
  function transformHostResultsLinks($matches) {
4166
    $link = $matches[0];
4167
    $newBaseUrl = $this->getNewBaseUrl($matches);
4168
    if ($newBaseUrl !== NULL) {
4169
      $id = $matches[3];
4170
      $link = "{$newBaseUrl}host/{$id}/tasks";
4171
    }
4172
    return $link;
4173
  }
4174
4175
  function transformUserResultsLinks($matches) {
4176
    $link = $matches[0];
4177
    $newBaseUrl = $this->getNewBaseUrl($matches);
4178
    if ($newBaseUrl !== NULL) {
4179
      $link = "{$newBaseUrl}account/tasks";
4180
    }
4181
    return $link;
4182
  }
4183
4184
  function transformHostLinks($matches) {
4185
    $link = $matches[0];
4186
    $newBaseUrl = $this->getNewBaseUrl($matches);
4187
    if ($newBaseUrl !== NULL) {
4188
      $id = $matches[3];
4189
      $link = "{$newBaseUrl}host/{$id}";
4190
    }
4191
    return $link;
4192
  }
4193
4194
  function transformUserHostsLinks($matches) {
4195
    $link = $matches[0];
4196
    $newBaseUrl = $this->getNewBaseUrl($matches);
4197
    if ($newBaseUrl !== NULL) {
4198
      $uid = boincuser_lookup_uid($matches[3]);
4199
      if ($uid) {
4200
        $link = "{$newBaseUrl}account/{$uid}/computers";
4201
      }
4202
    }
4203
    return $link;
4204
  }
4205
4206
  function transformForumIndexLinks($matches) {
4207
    $link = $matches[0];
4208
    $newBaseUrl = $this->getNewBaseUrl($matches);
4209
    if ($newBaseUrl !== NULL) {
4210
      $link = "{$newBaseUrl}community/forum";
4211
    }
4212
    return $link;
4213
  }
4214
4215
}
4216