boincwork_generate_prefs_element()   F
last analyzed

Complexity

Conditions 78
Paths 12749

Size

Total Lines 284
Code Lines 194

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 78
eloc 194
c 0
b 0
f 0
nc 12749
nop 4
dl 0
loc 284
rs 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
// $Id$
3
4
/**
5
 * Functions that are shared amongst files and dependent modules go
6
 * here to keep the clutter down in the main module file.
7
 */
8
9
/**
10
 * When a venue is changed in preference forms, don't carry over the preset
11
 * that was selected
12
 */
13
function boincwork_ahah_helper_venue_submit($form, &$form_state) {
14
  $form_state['storage']['prefs']['preset'] = null;
15
  ahah_helper_generic_submit($form, $form_state);
16
}
17
18
/**
19
 * Get a predetermined set of preferences
20
 */
21
function boincwork_get_preset_prefs($preset = null) {
22
  $saved_state = variable_get('boincwork_preset_prefs', null);
23
24
  // If not configured yet, use these values as for inital
25
  // computing/general preferences.
26
  if (!$saved_state) {
27
    // Get BOINC project disk space configurations from config.xml to
28
    // fill in initial preference values.
29
    require_boinc(array('db', 'prefs'));
30
    $disk_space_config = get_disk_space_config();
31
32
    $saved_state = '
33
      <general_preferences>
34
        <preset name="standard">
35
          <run_on_batteries>0</run_on_batteries>
36
          <run_if_user_active>0</run_if_user_active>
37
          <run_gpu_if_user_active>1</run_gpu_if_user_active>
38
          <idle_time_to_run>3</idle_time_to_run>
39
          <suspend_if_no_recent_input>0</suspend_if_no_recent_input>
40
          <suspend_cpu_usage>25</suspend_cpu_usage>
41
          <start_hour>0</start_hour>
42
          <end_hour>0</end_hour>
43
          <leave_apps_in_memory>1</leave_apps_in_memory>
44
          <cpu_scheduling_period_minutes>60</cpu_scheduling_period_minutes>
45
          <max_ncpus_pct>100</max_ncpus_pct>
46
          <cpu_usage_limit>80</cpu_usage_limit>
47
          <disk_max_used_gb>'.$disk_space_config->disk_max_used_gb.'</disk_max_used_gb>
48
          <disk_min_free_gb>'.$disk_space_config->disk_min_free_gb.'</disk_min_free_gb>
49
          <disk_max_used_pct>'.$disk_space_config->disk_max_used_pct.'</disk_max_used_pct>
50
          <disk_interval>60</disk_interval>
51
          <vm_max_used_pct>0</vm_max_used_pct>
52
          <ram_max_used_busy_pct>15</ram_max_used_busy_pct>
53
          <ram_max_used_idle_pct>50</ram_max_used_idle_pct>
54
          <work_buf_min_days>0.1</work_buf_min_days>
55
          <work_buf_additional_days>0.25</work_buf_additional_days>
56
          <confirm_before_connecting>1</confirm_before_connecting>
57
          <hangup_if_dialed>0</hangup_if_dialed>
58
          <max_bytes_sec_down>0</max_bytes_sec_down>
59
          <max_bytes_sec_up>0</max_bytes_sec_up>
60
          <net_start_hour>0</net_start_hour>
61
          <net_end_hour>0</net_end_hour>
62
          <daily_xfer_limit_mb>0</daily_xfer_limit_mb>
63
          <daily_xfer_period_days>0</daily_xfer_period_days>
64
          <dont_verify_images>0</dont_verify_images>
65
        </preset>
66
        <preset name="maximum">
67
          <run_on_batteries>1</run_on_batteries>
68
          <run_if_user_active>1</run_if_user_active>
69
          <run_gpu_if_user_active>1</run_gpu_if_user_active>
70
          <idle_time_to_run>3</idle_time_to_run>
71
          <suspend_if_no_recent_input>0</suspend_if_no_recent_input>
72
          <suspend_cpu_usage>0</suspend_cpu_usage>
73
          <start_hour>0</start_hour>
74
          <end_hour>0</end_hour>
75
          <leave_apps_in_memory>1</leave_apps_in_memory>
76
          <cpu_scheduling_period_minutes>60</cpu_scheduling_period_minutes>
77
          <max_ncpus_pct>100</max_ncpus_pct>
78
          <cpu_usage_limit>100</cpu_usage_limit>
79
          <disk_max_used_gb>100</disk_max_used_gb>
80
          <disk_min_free_gb>2</disk_min_free_gb>
81
          <disk_max_used_pct>100</disk_max_used_pct>
82
          <disk_interval>60</disk_interval>
83
          <vm_max_used_pct>50</vm_max_used_pct>
84
          <ram_max_used_busy_pct>80</ram_max_used_busy_pct>
85
          <ram_max_used_idle_pct>90</ram_max_used_idle_pct>
86
          <work_buf_min_days>0.1</work_buf_min_days>
87
          <work_buf_additional_days>0.25</work_buf_additional_days>
88
          <confirm_before_connecting>1</confirm_before_connecting>
89
          <hangup_if_dialed>0</hangup_if_dialed>
90
          <max_bytes_sec_down>0</max_bytes_sec_down>
91
          <max_bytes_sec_up>0</max_bytes_sec_up>
92
          <net_start_hour>0</net_start_hour>
93
          <net_end_hour>0</net_end_hour>
94
          <daily_xfer_limit_mb>0</daily_xfer_limit_mb>
95
          <daily_xfer_period_days>0</daily_xfer_period_days>
96
          <dont_verify_images>0</dont_verify_images>
97
        </preset>
98
        <preset name="green">
99
          <run_on_batteries>0</run_on_batteries>
100
          <run_if_user_active>1</run_if_user_active>
101
          <run_gpu_if_user_active>1</run_gpu_if_user_active>
102
          <idle_time_to_run>3</idle_time_to_run>
103
          <suspend_if_no_recent_input>1</suspend_if_no_recent_input>
104
          <suspend_cpu_usage>75</suspend_cpu_usage>
105
          <start_hour>0</start_hour>
106
          <end_hour>0</end_hour>
107
          <leave_apps_in_memory>1</leave_apps_in_memory>
108
          <cpu_scheduling_period_minutes>60</cpu_scheduling_period_minutes>
109
          <max_ncpus_pct>100</max_ncpus_pct>
110
          <cpu_usage_limit>80</cpu_usage_limit>
111
          <disk_max_used_gb>8</disk_max_used_gb>
112
          <disk_min_free_gb>4</disk_min_free_gb>
113
          <disk_max_used_pct>10</disk_max_used_pct>
114
          <disk_interval>60</disk_interval>
115
          <vm_max_used_pct>0</vm_max_used_pct>
116
          <ram_max_used_busy_pct>50</ram_max_used_busy_pct>
117
          <ram_max_used_idle_pct>75</ram_max_used_idle_pct>
118
          <work_buf_min_days>0.1</work_buf_min_days>
119
          <work_buf_additional_days>0.25</work_buf_additional_days>
120
          <confirm_before_connecting>1</confirm_before_connecting>
121
          <hangup_if_dialed>0</hangup_if_dialed>
122
          <max_bytes_sec_down>100000</max_bytes_sec_down>
123
          <max_bytes_sec_up>10000</max_bytes_sec_up>
124
          <net_start_hour>0</net_start_hour>
125
          <net_end_hour>0</net_end_hour>
126
          <daily_xfer_limit_mb>100</daily_xfer_limit_mb>
127
          <daily_xfer_period_days>2</daily_xfer_period_days>
128
          <dont_verify_images>1</dont_verify_images>
129
        </preset>
130
        <preset name="minimum">
131
          <run_on_batteries>0</run_on_batteries>
132
          <run_if_user_active>0</run_if_user_active>
133
          <run_gpu_if_user_active>0</run_gpu_if_user_active>
134
          <idle_time_to_run>5</idle_time_to_run>
135
          <suspend_if_no_recent_input>1</suspend_if_no_recent_input>
136
          <suspend_cpu_usage>25</suspend_cpu_usage>
137
          <start_hour>0</start_hour>
138
          <end_hour>8</end_hour>
139
          <leave_apps_in_memory>0</leave_apps_in_memory>
140
          <cpu_scheduling_period_minutes>120</cpu_scheduling_period_minutes>
141
          <max_ncpus_pct>25</max_ncpus_pct>
142
          <cpu_usage_limit>40</cpu_usage_limit>
143
          <disk_max_used_gb>2</disk_max_used_gb>
144
          <disk_min_free_gb>4</disk_min_free_gb>
145
          <disk_max_used_pct>5</disk_max_used_pct>
146
          <disk_interval>120</disk_interval>
147
          <vm_max_used_pct>0</vm_max_used_pct>
148
          <ram_max_used_busy_pct>5</ram_max_used_busy_pct>
149
          <ram_max_used_idle_pct>20</ram_max_used_idle_pct>
150
          <work_buf_min_days>0.1</work_buf_min_days>
151
          <work_buf_additional_days>0.25</work_buf_additional_days>
152
          <confirm_before_connecting>1</confirm_before_connecting>
153
          <hangup_if_dialed>0</hangup_if_dialed>
154
          <max_bytes_sec_down>15000</max_bytes_sec_down>
155
          <max_bytes_sec_up>5000</max_bytes_sec_up>
156
          <net_start_hour>0</net_start_hour>
157
          <net_end_hour>8</net_end_hour>
158
          <daily_xfer_limit_mb>1000</daily_xfer_limit_mb>
159
          <daily_xfer_period_days>30</daily_xfer_period_days>
160
          <dont_verify_images>0</dont_verify_images>
161
        </preset>
162
      </general_preferences>';
163
  }
164
165
  // Convert XML data to array format
166
  $preset_prefs = load_configuration($saved_state);
167
168
  if ($preset) {
169
    // Load preset from configuration
170
    $preset_prefs = (array) $preset_prefs['general_preferences'];
171
    if (isset($preset_prefs['preset'])) {
172
      if (!is_numeric(key($preset_prefs['preset']))) {
173
        $preset_prefs['preset'] = array($preset_prefs['preset']);
174
      }
175
      foreach ($preset_prefs['preset'] as $key => $prefs) {
176
        if (isset($prefs['@attributes']['name']) AND $prefs['@attributes']['name'] == $preset) {
177
          return $preset_prefs['preset'][$key];
178
        }
179
      }
180
    }
181
  }
182
  return $preset_prefs;
183
}
184
185
/**
186
 * Load (and validate) the project specific configuration XML
187
 */
188
function boincwork_get_project_specific_config() {
189
  $raw_config_data = variable_get('boinc_project_specific_prefs_config', '');
190
191
  $xsd = './' . drupal_get_path('module', 'boincwork') . '/includes/projectprefs.xsd';
192
  libxml_use_internal_errors(true);
193
194
  $xml = new DomDocument();
195
  $xml->loadXML($raw_config_data, LIBXML_NOBLANKS);
196
  if (!$xml->schemaValidate($xsd)) {
197
    $errors = libxml_get_errors();
198
    $lines = explode("\r", $raw_config_data);
199
    drupal_set_message("{$errors[0]->message} at line {$errors[0]->line}" .
200
      ': <br/>' . htmlentities($lines[$errors[0]->line - 1]), 'error');
201
    return NULL;
202
  }
203
204
  // Convert XML to array for validation
205
  $xml = load_configuration($raw_config_data);
206
  return $xml;
207
}
208
209
/**
210
 * Get rules by which to validate project specific data
211
 */
212
function boincwork_get_project_specific_config_validation_rules($xml = array()) {
213
  $rules = array();
214
  if (!$xml) {
215
    // Read the config XML
216
    $xml = boincwork_get_project_specific_config();
217
    $xml = $xml['project_specific_preferences'];
218
  }
219
  foreach ($xml as $type => $elements) {
220
    if (is_array($elements) AND !is_numeric(key($elements))) {
221
      $elements = array($elements);
222
    }
223
    switch ($type) {
224
    case 'compound':
225
      foreach ($elements as $element) {
226
        $name = $element['@attributes']['name'];
227
        $rules[$name] = boincwork_get_project_specific_config_validation_rules($element['attributes']);
228
      }
229
      break;
230
231
    case 'text':
232
      foreach ($elements as $element) {
233
        $name = $element['@attributes']['name'];
234
        $rules[$name] = array(
235
          'datatype' => $element['@attributes']['datatype']
236
        );
237
        if (isset($element['@attributes']['min'])) {
238
          $rules[$name]['min'] = $element['@attributes']['min'];
239
        }
240
        if (isset($element['@attributes']['max'])) {
241
          $rules[$name]['max'] = $element['@attributes']['max'];
242
        }
243
      }
244
      break;
245
    /*
246
    case 'radio':
247
    case 'dropdown':
248
      foreach ($elements as $element) {
249
        $name = $element['@attributes']['name'];
250
        $options = array();
251
        foreach ($element['items']['item'] as $option) {
252
          if (is_array($option) AND isset($option['@value'])) {
253
            $option = $option['@value'];
254
          }
255
          $options[] = $option;
256
        }
257
        $rules[$name] = array(
258
          'options' => $options
259
        );
260
      }
261
      break;
262
    */
263
    case 'apps':
264
      // At least one app needs to be selected
265
      $rules['apps'] = array(
266
        'minimum selected' => 1,
267
        'list' => array()
268
      );
269
      foreach ($elements as $element) {
270
        foreach ($element['app'] as $app) {
271
          $name = "app_{$app['@attributes']['id']}";
272
          $rules['apps']['list'][] = $name;
273
          //$rules[$name] = array(
274
          //  'options' => $options
275
          //);
276
        }
277
      }
278
      break;
279
280
    case 'group':
281
      foreach ($elements as $element) {
282
        $name = $element['@attributes']['name'];
283
        $rules += boincwork_get_project_specific_config_validation_rules($element);
284
      }
285
      break;
286
    /*
287
    case 'boolean':
288
      // Shouldn't need to validate boolean...
289
      break;
290
      */
291
    default:
292
    }
293
  }
294
  return $rules;
295
}
296
297
/**
298
 * Define how project specific settings should be saved
299
 */
300
function boincwork_format_project_specific_prefs_data($values, $xml = array()) {
301
  $defaults = array();
302
  if (!$xml) {
303
    // Read the config XML
304
    $xml = boincwork_get_project_specific_config();
305
    $xml = $xml['project_specific_preferences'];
306
  }
307
  foreach ($xml as $type => $elements) {
308
    $structure_data = array();
309
    if (is_array($elements) AND !is_numeric(key($elements))) {
310
      $elements = array($elements);
311
    }
312
    switch ($type) {
313
    case 'compound':
314
      foreach ($elements as $element) {
315
        $name = $element['@attributes']['name'];
316
        $default[$name]['@attributes'] = boincwork_format_project_specific_prefs_data($values[$name], $element['attributes']);
317
      }
318
      $defaults += $default;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $default does not seem to be defined for all execution paths leading up to this point.
Loading history...
319
      break;
320
321
    case 'group':
322
      foreach ($elements as $element) {
323
        $defaults += boincwork_format_project_specific_prefs_data($values, $element);
324
      }
325
      break;
326
327
    case 'text':
328
    case 'radio':
329
    case 'dropdown':
330
    case 'boolean':
331
      foreach ($elements as $element) {
332
        $name = $element['@attributes']['name'];
333
        if (isset($element['@attributes']['entitytype']) AND $element['@attributes']['entitytype'] == 'attribute') {
334
          $defaults['@attributes'][$name] = $values[$name];
335
        }
336
        else {
337
          $defaults[$name] = $values[$name];
338
        }
339
      }
340
      break;
341
342
    case 'apps':
343
      foreach ($elements as $element) {
344
        $defaults['app_id'] = array();
345
        foreach ($element['app'] as $app) {
346
          $app_id = $app['@attributes']['id'];
347
          if ($values['applications']["app_{$app_id}"]) {
348
            $defaults['app_id'][] = $app_id;
349
          }
350
        }
351
      }
352
      break;
353
354
    default:
355
    }
356
  }
357
  return $defaults;
358
}
359
360
/**
361
 * Add an element to the form based on its definition
362
 */
363
function boincwork_generate_prefs_element(&$form, $type, $elements, $user_prefs = null) {
364
  switch ($type) {
365
  case 'text':
366
    if (!is_numeric(key($elements))) {
367
      $elements = array($elements);
368
    }
369
    foreach ($elements as $element) {
370
      $name = $element['@attributes']['name'];
371
      $default = $element['@attributes']['default'];
372
      $title = is_array($element['title']) ? $element['title']['@value'] : $element['title'];
373
      $description = '';
374
      if (isset($element['description'])) {
375
        $description = is_array($element['description']) ? $element['description']['@value'] : $element['description'];
376
      }
377
378
      $value = $default;
379
      $user_pref = $user_prefs;
380
      $entitytype = isset($element['@attributes']['entitytype']) ? $element['@attributes']['entitytype'] : 'element';
381
      if ($entitytype == 'attribute') {
382
        $user_pref = $user_prefs['@attributes'];
383
      }
384
      if (isset($user_pref[$name])) {
385
        if (is_array($user_pref[$name]) AND isset($user_pref[$name]['@value'])) {
386
          $value = $user_pref[$name]['@value'];
387
        }
388
        else {
389
          $value = $user_pref[$name];
390
        }
391
      }
392
393
      // Use appropriate datatype
394
      if (isset($element['@attributes']['datatype'])) {
395
        switch($element['@attributes']['datatype']) {
396
        case 'integer':
397
          $value = (int) $value;
398
          break;
399
400
        case 'float':
401
          $value = number_format((float) $value, 2);
402
          break;
403
404
        default:
405
        }
406
      }
407
408
      // Translate elements as appropriate
409
      if ($title) {
410
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
411
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
412
      }
413
      if ($description) {
414
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($description));
415
        $description = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($description));
416
      }
417
418
      $form[$name] = array(
419
        '#title' => $title,
420
        '#type' => 'textfield',
421
        '#default_value' => $value,
422
        '#size' => 5,
423
        '#description' => $description . bts(' Default value: @default', array('@default' => $default), NULL, 'boinc:account-preferences-project')
424
      );
425
    }
426
    break;
427
428
  case 'boolean':
429
    if (!is_numeric(key($elements))) {
430
      $elements = array($elements);
431
    }
432
    foreach ($elements as $element) {
433
      $name = $element['@attributes']['name'];
434
      $title = is_array($element['title']) ? $element['title']['@value'] : $element['title'];
435
      $default = (isset($element['@attributes']['selected']) AND $element['@attributes']['selected'] == 'true') ? 1 : 0;
436
      $description = '';
437
      if (isset($element['description'])) {
438
        $description = is_array($element['description']) ? $element['description']['@value'] : $element['description'];
439
      }
440
441
      $value = $default;
442
      $user_pref = $user_prefs;
443
      $entitytype = isset($element['@attributes']['entitytype']) ? $element['@attributes']['entitytype'] : 'element';
444
      if ($entitytype == 'attribute') {
445
        $user_pref = $user_prefs['@attributes'];
446
      }
447
      if (isset($user_pref[$name])) {
448
        if (is_array($user_pref[$name]) AND isset($user_pref[$name]['@value'])) {
449
          $value = $user_pref[$name]['@value'];
450
        }
451
        else {
452
          $value = $user_pref[$name];
453
        }
454
      }
455
456
      // Translate elements as appropriate
457
      if ($title) {
458
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
459
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
460
      }
461
      if ($description) {
462
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($description));
463
        $description = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($description));
464
      }
465
466
      $form[$name] = array(
467
        '#title' => $title,
468
        '#type' => 'radios',
469
        '#options' => array(1 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), 0 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes')),
470
        '#attributes' => array('class' => 'fancy'),
471
        '#default_value' => $value,
472
        '#description' => $description
473
      );
474
    }
475
    break;
476
477
  case 'radio':
478
  case 'dropdown':
479
480
    if (!is_numeric(key($elements))) {
481
      $elements = array($elements);
482
    }
483
    foreach ($elements as $element) {
484
      $name = $element['@attributes']['name'];
485
      $default = null;
486
      $options = array();
487
      foreach($element['items']['item'] as $item) {
488
        if (is_array($item)) {
489
          $value = $item['@value'];
490
          if ($default === NULL AND
491
              isset($item['@attributes']) AND
492
              isset($item['@attributes']['selected'])) {
493
            $default = ($item['@attributes']['selected'] == 'true') ? $item['@value'] : null;
494
          }
495
        }
496
        else {
497
          $value = $item;
498
        }
499
        $options[$value] = $value;
500
      }
501
      $title = is_array($element['title']) ? $element['title']['@value'] : $element['title'];
502
      $description = '';
503
      if (isset($element['description'])) {
504
        $description = is_array($element['description']) ? $element['description']['@value'] : $element['description'];
505
      }
506
      $user_pref = $user_prefs;
507
      $entitytype = isset($element['@attributes']['entitytype']) ? $element['@attributes']['entitytype'] : 'element';
508
      if ($entitytype == 'attribute') {
509
        $user_pref = $user_prefs['@attributes'];
510
      }
511
      $value = isset($user_pref[$name]) ? $user_pref[$name] : $default;
512
513
      // Translate elements as appropriate
514
      if ($title) {
515
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
516
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
517
      }
518
      if ($description) {
519
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($description));
520
        $description = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($description));
521
      }
522
523
      $form[$name] = array(
524
        '#title' => $title,
525
        '#type' => ($type == 'radio') ? 'radios' : 'select',
526
        '#options' => $options,
527
        '#attributes' => array('class' => 'fancy'),
528
        '#default_value' => $value,
529
        '#description' => $description . bts(' Default value: @default', array('@default' =>$default), NULL, 'boinc:account-preferences-project')
530
      );
531
    }
532
    break;
533
534
  case 'apps':
535
    $title = is_array($elements['title']) ? $elements['title']['@value'] : $elements['title'];
536
537
      // Translate elements as appropriate
538
      if ($title) {
539
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
540
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
541
      }
542
543
    $form['applications'] = array(
544
      '#title' => bts('Applications', array(), NULL, 'boinc:account-preferences'),
545
      '#type' => 'fieldset',
546
      '#description' => $title,
547
      '#collapsible' => TRUE,
548
      '#collapsed' => FALSE
549
    );
550
    $applications = array();
551
    if (!is_array($user_prefs['app_id'])) {
552
      $user_prefs['app_id'] = array($user_prefs['app_id']);
553
    }
554
    foreach ($user_prefs['app_id'] as $app) {
555
      if (!$app) continue;
556
      if (is_array($app) AND isset($app['@value'])) {
557
        $app = $app['@value'];
558
      }
559
      $applications[] = $app;
560
    }
561
    foreach ($elements['app'] as $app) {
562
      $app_id = $app['@attributes']['id'];
563
      $app_name = $app['@value'];
564
      $app_enabled = TRUE;
565
      if (isset($app['@attributes']['enabled']) AND
566
          $app['@attributes']['enabled'] == 'false') {
567
        $app_enabled = FALSE;
568
      }
569
      if ($applications) {
570
        $checked = in_array($app_id, $applications);
571
      } else {
572
        $checked = TRUE;
573
        if (isset($app['@attributes']['selected']) AND
574
            $app['@attributes']['selected'] == 'false') {
575
          $checked = FALSE;
576
        }
577
      }
578
      $form['applications']["app_{$app_id}"] = array(
579
        '#title' => $app_name,
580
        '#type' => 'checkbox',
581
        '#default_value' => ($checked) ? 'x' : false,
582
        '#disabled' => !$app_enabled
583
      );
584
    }
585
586
    break;
587
588
  case 'group':
589
    if (!is_numeric(key($elements))) {
590
      $elements = array($elements);
591
    }
592
    foreach ($elements as $key => $element) {
593
      $title = is_array($element['title']) ? $element['title']['@value'] : $element['title'];
594
      $name = str_replace(' ','_',strtolower($title));
595
      $name = "group_{$name}";
596
597
      // Translate elements as appropriate
598
      if ($title) {
599
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
600
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
601
      }
602
603
      $form[$name] = array(
604
          '#title' => $title,
605
          '#type' => 'fieldset',
606
          '#tree' => FALSE,
607
          //'#description' => t('Notes about this group of fields'),
608
          '#collapsible' => TRUE,
609
          '#collapsed' => FALSE
610
      );
611
      // Recursively populate the compound element
612
      foreach ($element as $child_type => $child) {
613
        boincwork_generate_prefs_element($form[$name], $child_type, $child, $user_prefs);
614
      }
615
    }
616
    break;
617
618
  case 'compound':
619
    if (!is_numeric(key($elements))) {
620
      $elements = array($elements);
621
    }
622
    foreach ($elements as $element) {
623
      $name = $element['@attributes']['name'];
624
      $title = is_array($element['title']) ? $element['title']['@value'] : $element['title'];
625
626
      // Translate elements as appropriate
627
      if ($title) {
628
        i18nstrings_update('project:prefs_xml', _boinctranslate_supertrim($title));
629
        $title = i18nstrings('project:prefs_xml', _boinctranslate_supertrim($title));
630
      }
631
632
      $form[$name] = array(
633
          '#title' => $title,
634
          '#type' => 'fieldset',
635
          //'#description' => t('Notes about this group of fields'),
636
          '#collapsible' => TRUE,
637
          '#collapsed' => FALSE
638
      );
639
      // Recursively populate the compound element
640
      foreach ($element['attributes'] as $child_type => $child) {
641
        boincwork_generate_prefs_element($form[$name], $child_type, $child, $user_prefs[$name]['@attributes']);
642
      }
643
    }
644
    break;
645
646
    default:
647
      // Don't generate form elements for things that aren't explicitly form
648
      // elements (i.e. 'title', '@attributes' keys, and the like)
649
  }
650
}
651
652
/**
653
 * Generate a tabular structure out of preferences for use in comparison
654
 * views of preference sets
655
 */
656
function boincwork_make_prefs_table($prefs, $top_level = TRUE) {
657
658
  $prefs_table = array();
659
  $uncategorized = array();
660
661
  // Parse the project preferences form
662
  foreach ($prefs as $key => $element) {
663
664
    // Determine which type of element this is and act accordingly
665
    $element_type = NULL;
666
    if (is_array($element) AND isset($element['#type'])) {
667
      $element_type = $element['#type'];
668
    }
669
    switch ($element_type) {
670
    case 'fieldset':
671
      $prefs_table[$key] = array(
672
        'name' => $element['#title'],
673
        'elements' => boincwork_make_prefs_table($element, FALSE),
674
      );
675
      break;
676
    case 'textfield':
677
    case 'radios':
678
    case 'checkbox':
679
    case 'select':
680
      // Special hack for time range preferences...
681
      if (in_array($key, array('start_hour', 'net_start_hour'))) {
682
        switch ($key) {
683
        case 'start_hour':
684
          $element['#title'] = bts('Compute only between:', array(), NULL, 'boinc:account-preferences-computing');
685
          break;
686
        case 'net_start_hour':
687
          $element['#title'] = bts('Transfer files only between:', array(), NULL, 'boinc:account-preferences-comuting');
688
          break;
689
        default:
690
        }
691
      }
692
      $prefs_element = array(
693
        'name' => (isset($element['#title'])) ? $element['#title'] : '',
694
        'description' => (isset($element['#description'])) ? $element['#description'] : '',
695
        'default_value' => (isset($element['#default_value'])) ? $element['#default_value'] : NULL,
696
      );
697
      if ($top_level) {
698
        $uncategorized[$key] = $prefs_element;
699
      }
700
      else {
701
        $prefs_table[$key] = $prefs_element;
702
      }
703
      break;
704
    default:
705
    }
706
  }
707
708
  if ($prefs_table AND $uncategorized) {
709
    // Throw any settings that don't fit elsewhere into "other"
710
    $prefs_table['other'] = array(
711
      'name' => bts('Other settings', array(), NULL, 'boinc:account-preferences'),
712
      'elements' => $uncategorized,
713
    );
714
  }
715
  elseif ($uncategorized) {
716
    // If nothing is categorized, output all prefs under a general "settings"
717
    $prefs_table['settings'] = array(
718
      'name' => bts('Settings', array(), NULL, 'boinc:account-preferences'),
719
      'elements' => $uncategorized,
720
    );
721
  }
722
723
  return $prefs_table;
724
}
725
726
/**
727
 * Load general or project preferences from BOINC account
728
 */
729
function boincwork_load_prefs($type = 'general', $venue = null, $account = null) {
730
731
  require_boinc(array('user'));
732
733
  // Load the BOINC user object
734
  if (!$account) {
735
    global $user;
736
    $account = $user;
737
  }
738
  $account = user_load($account->uid);
739
  $boincuser = BoincUser::lookup_id($account->boincuser_id);
740
741
  // Load the desired preferences for the user
742
  $main_prefs = array();
743
  if ($type == 'project') {
744
    if ($boincuser->project_prefs) {
745
      $main_prefs = load_configuration($boincuser->project_prefs);
746
      $main_prefs = (array) $main_prefs['project_preferences'];
747
    }
748
  }
749
  else {
750
    if ($boincuser->global_prefs) {
751
      $main_prefs = load_configuration($boincuser->global_prefs);
752
      $main_prefs = (array) $main_prefs['global_preferences'];
753
    }
754
  }
755
756
  // Return general preferences or a subset based on venue
757
  if (!$venue OR $venue == 'generic') {
758
    unset($main_prefs['venue']);
759
    // Use the length of the $main_prefs array as a condition as to
760
    // whether the preferences have already been set. This is
761
    // HARDCODED here.
762
    if (count($main_prefs) < 3)
763
        $main_prefs['@attributes'] = array('cleared' => 1);
764
    return $main_prefs;
765
  }
766
  else {
767
    if (isset($main_prefs['venue'])) {
768
      if (!is_numeric(key($main_prefs['venue']))) {
769
        $main_prefs['venue'] = array($main_prefs['venue']);
770
      }
771
      foreach ($main_prefs['venue'] as $key => $prefs_venue) {
772
        if (isset($prefs_venue['@attributes']['name']) AND $prefs_venue['@attributes']['name'] == $venue) {
773
          return $main_prefs['venue'][$key];
774
        }
775
      }
776
    }
777
  }
778
779
  return array(
780
    '@attributes' => array('name' => $venue, 'cleared' => 1)
781
  );
782
}
783
784
/**
785
 * Save project preferences to BOINC account
786
 */
787
function boincwork_save_prefs($prefs, $type = 'general', $venue = null, $account = null) {
788
789
  require_boinc(array('user'));
790
791
  // Load existing project prefs from the BOINC user object
792
  if (!$account) {
793
    global $user;
794
    $account = $user;
795
  }
796
  $account = user_load($account->uid);
797
  $boincuser = BoincUser::lookup_id($account->boincuser_id);
798
799
  // Load the specified preferences for the user
800
  $main_prefs = array();
801
  if ($type == 'project') {
802
    if ($boincuser->project_prefs) {
803
      $main_prefs = load_configuration($boincuser->project_prefs);
804
      $main_prefs = (array) $main_prefs['project_preferences'];
805
    }
806
  }
807
  else {
808
    if ($boincuser->global_prefs) {
809
      $main_prefs = load_configuration($boincuser->global_prefs);
810
      $main_prefs = (array) $main_prefs['global_preferences'];
811
    }
812
  }
813
814
  // Save all preferences or a subset based on venue
815
  //drupal_set_message('<pre>' . print_r($main_prefs, true) . '</pre>');
816
  $new_venue = true;
817
  if (!$venue OR $venue == 'generic') {
818
    //$main_prefs = $prefs;
819
    $main_prefs = $prefs + $main_prefs;
820
  }
821
  else {
822
    if (isset($main_prefs['venue'])) {
823
      if (!is_numeric(key($main_prefs['venue']))) {
824
        $main_prefs['venue'] = array($main_prefs['venue']);
825
      }
826
      foreach ($main_prefs['venue'] as $key => $prefs_venue) {
827
        if (isset($prefs_venue['@attributes']['name']) AND $prefs_venue['@attributes']['name'] == $venue) {
828
          if ($prefs) {
829
            $main_prefs['venue'][$key] = $prefs;
830
          }
831
          else {
832
            // If prefs is null, clear out this preference set
833
            unset($main_prefs['venue'][$key]);
834
            if (count($main_prefs['venue']) == 0) {
835
              // If that was the only preference set configured, unset the
836
              // venue tag altogether
837
              unset($main_prefs['venue']);
838
            }
839
          }
840
          $new_venue = false;
841
          break;
842
        }
843
      }
844
    }
845
    if ($new_venue) {
846
      $main_prefs['venue'][] = $prefs;
847
    }
848
  }
849
850
  // Set modified time
851
  if ($type == 'project') {
852
    if (!isset($main_prefs['modified'])) {
853
      $main_prefs = array_merge(array('modified' => 0), $main_prefs);
854
    }
855
    $main_prefs['modified'] = time();
856
  } else {
857
    if (!isset($main_prefs['mod_time'])) {
858
      $main_prefs = array_merge(array('mod_time' => 0), $main_prefs);
859
    }
860
    $main_prefs['mod_time'] = time();
861
    // unset source information, the Client will fill this in again
862
    if (isset($main_prefs['source_project'])) {
863
      unset($main_prefs['source_project']);
864
    }
865
    if (isset($main_prefs['source_scheduler'])) {
866
      unset($main_prefs['source_scheduler']);
867
    }
868
  }
869
870
  // Convert prefs back to XML and save to database
871
  $result = null;
872
  if ($type == 'project') {
873
    $main_prefs = array('project_preferences' => $main_prefs);
874
    $boincuser->project_prefs = save_configuration($main_prefs);
875
    db_set_active('boinc_rw');
876
    $result = db_query("UPDATE user SET project_prefs = '{$boincuser->project_prefs}' WHERE id = '{$boincuser->id}'");
877
    db_set_active('default');
878
  }
879
  else {
880
    $main_prefs = array('global_preferences' => $main_prefs);
881
    $boincuser->global_prefs = save_configuration($main_prefs);
882
    db_set_active('boinc_rw');
883
    $result = db_query("UPDATE user SET global_prefs = '{$boincuser->global_prefs}' WHERE id = '{$boincuser->id}'");
884
    db_set_active('default');
885
  }
886
  return $result;
887
}
888
889
890
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
891
 * Ignore user functions
892
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
893
894
// These functions are boinc-ppecific "replacements" for the
895
// ignore_user module's add and remove user functions.
896
897
898
/**
899
 *Add another user to the current user's ignore list using a BOINC
900
 *username. Called from privacy preference form.
901
 */
902
function boincwork_ignore_user_add_user_username($name = NULL) {
903
  global $user;
904
905
  if (isset($name)) {
906
    // Get the BOINC ID from the name string, and lookup the
907
    // corresponding drupal user.
908
    $boincname = substr($name, 0, strrpos($name, '_'));
909
    $boincid = substr($name, strrpos($name, '_') + 1);
910
    // iuid is the drupal uid to be ignored and author to be blocked.
911
    $iuid = get_drupal_id($boincid);
912
913
    if ($user->uid == $iuid) {
914
      drupal_set_message(bts('You can\'t add yourself to your own ignore list.', array(), NULL, 'boinc:ignore-user-error-message'), 'error');
915
      drupal_goto('account/prefs/privacy');
916
    }
917
918
    if (is_numeric($iuid) && $iuid > 0) {
919
      if (!db_result(db_query('SELECT COUNT(iuid) FROM {ignore_user} WHERE uid = %d AND iuid = %d', $user->uid, $iuid))) {
920
        db_query('INSERT INTO {ignore_user} (uid, iuid) VALUES (%d, %d)', $user->uid, $iuid);
921
      }// endif db_result
922
923
      if (module_exists('pm_block_user')) {
924
        if (!db_result(db_query('SELECT COUNT(recipient) FROM {pm_block_user} WHERE author = %d AND recipient = %d', $iuid, $user->uid))) {
925
          db_query('INSERT INTO {pm_block_user} (author, recipient) VALUES (%d, %d)', $iuid, $user->uid);
926
        }// endif db_result
927
      }// endif module_exists('pm_block_user')
928
929
    }// endif $iuid
930
  }
931
}
932
933
/**
934
 * Add another user's UID to the current user's ignore list.
935
 */
936
function boincwork_ignore_user_add_user($iuid = NULL) {
937
  global $user;
938
939
  if ($user->uid == $iuid) {
940
    drupal_set_message(bts('You can\'t add yourself to your own ignore list.', array(), NULL, 'boinc:ignore-user-error-message'), 'error');
941
    drupal_goto();
942
  }
943
944
  $otheraccount = user_load($iuid);
945
946
  if (is_numeric($iuid) && $iuid > 0) {
947
    if (!db_result(db_query('SELECT COUNT(iuid) FROM {ignore_user} WHERE uid = %d AND iuid = %d', $user->uid, $iuid))) {
948
      db_query('INSERT INTO {ignore_user} (uid, iuid) VALUES (%d, %d)', $user->uid, $iuid);
949
    }// endif db_result
950
951
    if (module_exists('pm_block_user')) {
952
      if (!db_result(db_query('SELECT COUNT(recipient) FROM {pm_block_user} WHERE author = %d AND recipient = %d', $iuid, $user->uid))) {
953
        db_query('INSERT INTO {pm_block_user} (author, recipient) VALUES (%d, %d)', $iuid, $user->uid);
954
      }// endif db_result
955
    }// endif module_exists('pm_block_user')
956
957
    drupal_set_message(
958
      bts('@username has been added to your ignore list. See your !privacy_preferences for more details.',
959
        array(
960
          '@username' => $otheraccount->boincuser_name,
961
          '!privacy_preferences' => l(bts('privacy preferences', array(), NULL, 'boinc:ignore-user-add'), 'account/prefs/privacy'),
962
        ),
963
        NULL, 'boinc:ignore-user-add'),
964
      'status');
965
    drupal_goto();
966
  }
967
  else {
968
    drupal_not_found();
969
  }// endif iuid
970
}
971
972
/**
973
 * Remove user from user's ignore list.
974
 */
975
function boincwork_ignore_user_remove_user($iuid = NULL) {
976
  global $user;
977
  $otheraccount = user_load($iuid);
978
979
  db_query('DELETE FROM {ignore_user} WHERE uid = %d AND iuid = %d', $user->uid, $iuid);
980
  if (module_exists('pm_block_user')) {
981
    db_query('DELETE FROM {pm_block_user} WHERE author = %d AND recipient = %d', $iuid, $user->uid);
982
  }// endif module_exists
983
  drupal_set_message(
984
    bts('@username has been removed from your ignore list. See your !privacy_preferences for more details.',
985
      array(
986
        '@username' => $otheraccount->boincuser_name,
987
        '!privacy_preferences' => l(bts('privacy preferences', array(), NULL, 'boinc:ignore-user-add'), 'account/prefs/privacy'),
988
      ),
989
      NULL, 'boinc:ignore-user-add'),
990
    'status');
991
  drupal_goto('account/prefs/privacy');
992
}
993
994
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
995
 * Consent to Privacy funtions
996
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
997
998
/**
999
 * Load consent types for privacy preferences from database. Returns
1000
 * an array of the relevant consent_types. Otherwise returns an emtpy
1001
 * array.
1002
 */
1003
function boincwork_load_privacyconsenttypes() {
1004
1005
  db_set_active('boinc_rw');
1006
  $db_result = db_query("SELECT id,shortname,description FROM consent_type WHERE enabled=1 AND privacypref=1 ORDER by project_specific ASC");
1007
  db_set_active('drupal');
1008
1009
  if ($db_result) {
1010
    $consent_types = array();
1011
    while ($result = db_fetch_array($db_result)) {
1012
      $consent_types[] = $result;
1013
    }
1014
    return $consent_types;
1015
  }
1016
  return array();
1017
}
1018
1019
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1020
 * Utility functions
1021
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1022
1023
/**
1024
 * Set the default preference set for the user
1025
 */
1026
function boincwork_set_default_venue($venue = '') {
1027
1028
  global $user;
1029
  $account = user_load($user->uid);
1030
1031
  if ($venue == 'generic') {
1032
    $venue = '';
1033
  }
1034
1035
  db_set_active('boinc_rw');
1036
  db_query("
1037
    UPDATE user
1038
    SET venue = '%s'
1039
    WHERE id = %d",
1040
    $venue, $account->boincuser_id
1041
  );
1042
  db_set_active('default');
1043
}
1044
1045
/**
1046
 * Recursively validate submitted form values against a set of rules
1047
 */
1048
function boincwork_validate_form($validation_rules, $values, $path = array()) {
1049
  foreach ($validation_rules as $field => $rules) {
1050
    $parents = $path;
1051
    if (is_array($values[$field])) {
1052
      // Process nested form elements
1053
      $parents[] = $field;
1054
      boincwork_validate_form($rules, $values[$field], $parents);
1055
    }
1056
    else {
1057
      if ($parents) {
1058
        // form_set_error() identifies nested form elements with '][' as a
1059
        // delimiter between each parent and child element
1060
        $parents[] = $field;
1061
        $form_field = implode('][', $parents);
1062
      }
1063
      else {
1064
        $form_field = $field;
1065
      }
1066
      if (isset($rules['datatype']) AND !boincwork_validate_datatype($values[$field], $rules['datatype'])) {
1067
        form_set_error($form_field, bts('Invalid data type for @field', array('@field' => $field), NULL, 'boinc:account-preferences'));
1068
      }
1069
      if (isset($rules['min']) AND $values[$field] < $rules['min']) {
1070
        form_set_error($form_field, bts('Minimum value not met for @field', array('@field' => $field), NULL, 'boinc:account-preferences'));
1071
      }
1072
      if (isset($rules['max']) AND $values[$field] > $rules['max']) {
1073
        form_set_error($form_field, bts('Maximum value exceeded for @field', array('@field' => $field), NULL, 'boinc:account-preferences'));
1074
      }
1075
    }
1076
  }
1077
}
1078
1079
/**
1080
 * Check that numeric data conforms to specifications
1081
 */
1082
function boincwork_validate_datatype($data, $datatype = NULL) {
1083
  switch ($datatype) {
1084
  case 'float':
1085
    if (!is_numeric($data)) {
1086
      return FALSE;
1087
    }
1088
    $data += 0.0;
1089
    if (!is_float($data)) {
0 ignored issues
show
introduced by
The condition is_float($data) is always false.
Loading history...
1090
      return FALSE;
1091
    }
1092
    break;
1093
1094
  case 'integer':
1095
    if (!is_numeric($data)) {
1096
      return FALSE;
1097
    }
1098
    $data += 0;
1099
    if (!is_int($data)) {
0 ignored issues
show
introduced by
The condition is_int($data) is always true.
Loading history...
1100
      return FALSE;
1101
    }
1102
    break;
1103
1104
  case 'text':
1105
  default:
1106
1107
  }
1108
  return TRUE;
1109
}
1110
1111
/**
1112
 * Format a number to be displayed using a maximum number of digits
1113
 */
1114
function boincwork_format_stats($number, $max_digits = 4) {
1115
  $suffix = array(
1116
    0 => '',
1117
    1 => 'k',
1118
    2 => 'M',
1119
    3 => 'G',
1120
    4 => 'T',
1121
    5 => 'P',
1122
    6 => 'E',
1123
    7 => 'Z',
1124
    8 => 'Y'
1125
  );
1126
  if (!is_numeric($number)) $number = 0;
1127
1128
  $digits = floor(log($number, 10)) + 1;
1129
  $magnitude = 0;
1130
  $precision = 0;
1131
  if ($digits > $max_digits) {
1132
    $magnitude = floor(($digits - ($max_digits - 3)) / 3);
1133
    $precision = $max_digits - ($digits - ($magnitude * 3) + 1);
1134
    $number = round($number / pow(1000, $magnitude), $precision);
0 ignored issues
show
Bug introduced by
$precision of type double is incompatible with the type integer expected by parameter $precision of round(). ( Ignorable by Annotation )

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

1134
    $number = round($number / pow(1000, $magnitude), /** @scrutinizer ignore-type */ $precision);
Loading history...
1135
  }
1136
  $number = number_format($number, $precision) . (($magnitude) ? "{$suffix[$magnitude]}" : '');
0 ignored issues
show
Bug introduced by
It seems like $precision can also be of type double; however, parameter $decimals of number_format() does only seem to accept integer, 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

1136
  $number = number_format($number, /** @scrutinizer ignore-type */ $precision) . (($magnitude) ? "{$suffix[$magnitude]}" : '');
Loading history...
1137
1138
  return $number;
1139
}
1140
1141
  //------------------------------------------------------------------------------------------------
1142
  //  load_configuration(): Convert structured text/xml to array
1143
  //------------------------------------------------------------------------------------------------
1144
1145
  function load_configuration($text)
1146
  {
1147
      if (preg_match('/^\<\?xml .*\?\>$/i', $text)) return null;
1148
      if ($xml = text_to_xml($text)) return xml_to_array($xml);
1149
      return false;
1150
  }
1151
1152
  //------------------------------------------------------------------------------------------------
1153
  //  save_configuration(): Convert array to structured text/xml
1154
  //------------------------------------------------------------------------------------------------
1155
1156
  function save_configuration($array)
1157
  {
1158
      if ($xml = array_to_xml($array)) return xml_to_text($xml, false, true);
1159
      return false;
1160
  }
1161
1162
  //------------------------------------------------------------------------------------------------
1163
  //  array_to_xml(): Take a multidimensional array and convert it to a structured
1164
  //  DOM XML object
1165
  //------------------------------------------------------------------------------------------------
1166
1167
  function array_to_xml($array, $dom = false, $parent_node = false) {
1168
    $is_root = false;
1169
    if (!$dom) $dom = new DomDocument('1.0');
1170
    if (!$parent_node) {
1171
      $parent_node = $dom;
1172
      $is_root = true;
1173
    }
1174
    // Created an intermediate array to attempt to sort by @position
1175
    $ordered_array = array();
1176
    $unordered_array = array();
1177
    foreach ($array as $name => $value) {
1178
      if ($is_root) {
1179
        $unordered_array[] = $array;
1180
        break;
1181
      }
1182
      if (is_array($value)) {
1183
        if (is_numeric(key($value))) {
1184
          foreach ($value as $item) {
1185
            if (is_array($item) AND isset($item['@position'])) {
1186
              $ordered_array[$item['@position']] = array(
1187
                $name => $item
1188
              );
1189
            }
1190
            else {
1191
              $unordered_array[] = array(
1192
                $name => $item
1193
              );
1194
            }
1195
          }
1196
        }
1197
        elseif (isset($value['@position'])) {
1198
          $ordered_array[$value['@position']] = array(
1199
            $name => $value
1200
          );
1201
        }
1202
        else {
1203
          $unordered_array[] = array(
1204
            $name => $value
1205
          );
1206
        }
1207
      }
1208
      else {
1209
        $unordered_array[] = array(
1210
          $name => $value
1211
        );
1212
      }
1213
    }
1214
1215
    // Now append items without explicit positions at the end
1216
    $primed_array = array_merge($ordered_array, $unordered_array);
1217
1218
    // Convert to XML...
1219
    foreach ($primed_array as $item) {
1220
      list($name, $value) = each($item);
1221
      if (strcmp($name, '@attributes') == 0) {
1222
        if (!is_array($value)) continue;
1223
        foreach ($value as $attributeName => $attributeValue) {
1224
          $parent_node->setAttribute($attributeName, $attributeValue);
1225
        }
1226
      } elseif (strcmp($name, '@value') == 0) {
1227
        if (isset($value)) $parent_node->nodeValue = $value;
1228
      } elseif (strcmp($name, '@position') == 0) {
1229
        continue;
1230
      } else {
1231
        if (is_numeric($name)) {
1232
          $name = $parent_node->tagName;
1233
        }
1234
        $current_item = $dom->createElement($name);
1235
        if (is_array($value)) {
1236
          if (is_numeric(key($value))) {
1237
            $current_node = $parent_node->appendChild($current_item);
1238
            $current_node = array_to_xml($value, $dom, $current_node);
1239
            $child_count = $current_node->childNodes->length;
1240
            for ($i = 0; $i < $child_count; $i++) {
1241
              $parent_node->appendChild($current_node->childNodes->item(0));
1242
            }
1243
            $parent_node->removeChild($current_node);
1244
          } else {
1245
            $current_node = $dom->appendChild($current_item);
1246
            $parent_node->appendChild(array_to_xml($value, $dom, $current_node));
1247
          }
1248
        } else {
1249
          if (isset($value)) $current_item->nodeValue = $value;
1250
          $parent_node->appendChild($current_item);
1251
        }
1252
      }
1253
    }
1254
    /*
1255
    foreach ($array as $name => $value) {
1256
      if (strcmp($name, '@attributes') == 0) {
1257
        if (!is_array($value)) continue;
1258
        foreach ($value as $attributeName => $attributeValue) {
1259
          $parent_node->setAttribute($attributeName, $attributeValue);
1260
        }
1261
      } elseif (strcmp($name, '@value') == 0) {
1262
        if (isset($value)) $parent_node->nodeValue = $value;
1263
      } else {
1264
        if (is_numeric($name)) {
1265
          $name = $parent_node->tagName;
1266
        }
1267
        $current_item = $dom->createElement($name);
1268
        if (is_array($value)) {
1269
          if (is_numeric(key($value))) {
1270
            $current_node = $parent_node->appendChild($current_item);
1271
            $current_node = array_to_xml($value, $dom, $current_node);
1272
            $child_count = $current_node->childNodes->length;
1273
            for ($i = 0; $i < $child_count; $i++) {
1274
              $parent_node->appendChild($current_node->childNodes->item(0));
1275
            }
1276
            $parent_node->removeChild($current_node);
1277
          } else {
1278
            $current_node = $dom->appendChild($current_item);
1279
            $parent_node->appendChild(array_to_xml($value, $dom, $current_node));
1280
          }
1281
        } else {
1282
          if (isset($value)) $current_item->nodeValue = $value;
1283
          $parent_node->appendChild($current_item);
1284
        }
1285
      }
1286
    }*/
1287
    return $parent_node;
1288
  }
1289
1290
  //------------------------------------------------------------------------------------------------
1291
  //  xml_to_text(): Convert an XML DOM object to string format
1292
  //------------------------------------------------------------------------------------------------
1293
1294
  function xml_to_text($xml, $include_xml_declaration = true, $add_carriage_returns = false)
1295
  {
1296
      $xml->formatOutput = true;
1297
      $text = $xml->saveXML();
1298
      if (!$include_xml_declaration) {
1299
        $text = preg_replace('/<\?xml version=.*\?>\s*/i', '', $text, 1);
1300
      }
1301
      if ($add_carriage_returns) {;
1302
        $text = preg_replace('/\n/i', "\r\n", $text);
1303
      }
1304
      return trim($text);
1305
  }
1306
1307
  //------------------------------------------------------------------------------------------------
1308
  //  text_to_xml(): Convert an XML DOM object to string format
1309
  //------------------------------------------------------------------------------------------------
1310
1311
  function text_to_xml($text) {
1312
    $xml = new DomDocument();
1313
    if ( !($xml->loadXML($text)) ) return false;
1314
    return $xml;
1315
  }
1316
1317
1318
  //------------------------------------------------------------------------------------------------
1319
  //  xml_to_array(): Convert an XML DOM object to array format
1320
  //------------------------------------------------------------------------------------------------
1321
1322
  function xml_to_array($xml) {
1323
      $node = $xml->firstChild; //$xml->first_child();
1324
      $result = '';
1325
      $index = 1;
1326
      $position = 0;
1327
      while (!is_null($node)) {
1328
          switch ($node->nodeType) {
1329
          case XML_TEXT_NODE:
1330
              if (trim($node->nodeValue)  != '') $result = $node->nodeValue;
1331
              break;
1332
          case XML_ELEMENT_NODE:
1333
              $node_name = $node->nodeName;
1334
              $parent = $node->parentNode;
1335
              $sibling = $node->nextSibling;
1336
1337
              // Determine if this node forms a set with siblings (share a node name)
1338
              while (($sibling) AND (($sibling->nodeType != XML_ELEMENT_NODE) OR ($sibling->nodeName != $node->nodeName))) $sibling = $sibling->nextSibling;
1339
              if (!$sibling) {
1340
                  $sibling = $node->previousSibling;
1341
                  while (($sibling) AND (($sibling->nodeType != XML_ELEMENT_NODE) OR ($sibling->nodeName != $node->nodeName))) $sibling = $sibling->previousSibling;
1342
              }
1343
1344
              if ($sibling) {
1345
                  $result[$node_name][$index] = '';
1346
                  if ($node->childNodes) {
1347
                      $result[$node_name][$index] = xml_to_array($node) ;
1348
                  }
1349
                  if ($node->hasAttributes()) {
1350
                      $attributes = $node->attributes;
1351
                      if ($result[$node_name][$index] !== '' AND !is_array($result[$node_name][$index])) {
1352
                          $result[$node_name][$index] = array('@value' => $result[$node_name][$index]);
1353
                      }
1354
                      foreach ($attributes as $key => $attribute) {
1355
                          $result[$node_name][$index]['@attributes'][$attribute->name] = $attribute->value;
1356
                      }
1357
                  }
1358
                  // Retain the position of the element
1359
                  if (!is_array($result[$node_name][$index])) {
1360
                    $result[$node_name][$index] = array(
1361
                      '@value' => $result[$node_name][$index]
1362
                    );
1363
                  }
1364
                  $result[$node_name][$index]['@position'] = $position;
1365
                  $position++;
1366
                  $index++;
1367
              } else {
1368
                  $result[$node_name] = '';
1369
                  if ($node->childNodes) {
1370
                      $result[$node_name] = xml_to_array($node) ;
1371
                  }
1372
                  if ($node->hasAttributes()) {
1373
                      $attributes = $node->attributes;
1374
                      if ($result[$node_name] !== '' AND !is_array($result[$node_name])) {
1375
                          $result[$node_name] = array('@value' => $result[$node_name]);
1376
                      }
1377
                      foreach($attributes as $key => $attribute) {
1378
                          $result[$node_name]['@attributes'][$attribute->name] = $attribute->value;
1379
                      }
1380
                  }
1381
                  // Retain the position of the element
1382
                  if (!is_array($result[$node_name])) {
1383
                    $result[$node_name] = array(
1384
                      '@value' => $result[$node_name]
1385
                    );
1386
                  }
1387
                  $result[$node_name]['@position'] = $position;
1388
                  $position++;
1389
              }
1390
              break;
1391
          }
1392
          $node = $node->nextSibling;
1393
      }
1394
      return $result;
1395
  }
1396
1397
1398
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1399
 * Functions for use in displaying special case text in views
1400
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1401
1402
/**
1403
  * Determine output for host list views when no hosts are found.
1404
  */
1405
function boincwork_views_host_list_empty_text($context = NULL) {
1406
1407
  // Pull the BOINC user ID from the view arguments to get show_hosts
1408
  // preference for that user
1409
  require_boinc('boinc_db');
1410
  $view = views_get_current_view();
1411
  $account = user_load($view->args[0]);
1412
  $boincuser = BoincUser::lookup_id($account->boincuser_id);
1413
1414
  // Determine if hosts are associated at all or just hidden
1415
  $output = '';
1416
  if ($boincuser->show_hosts) {
1417
    switch($context) {
1418
    case 'active':
1419
      $output .=  '<h2>' . bts('No active computers', array(), NULL, 'boinc:host-list') . '</h2>';
1420
      $output .=  '<p>' . bts('This user has no computers that have been'
1421
      . ' active in the last 30 days.', array(), NULL, 'boinc:host-list') . '</p>';
1422
      break;
1423
1424
    case 'preferences':
1425
      $output .=  '<h2>' . bts('No computers', array(), NULL, 'boinc:host-list') . '</h2>';
1426
      $output .=  '<p>' . bts('There are no computers assigned to this'
1427
      . ' preference set.', array(), NULL, 'boinc:host-list') . '</p>';
1428
      break;
1429
1430
    default:
1431
      $output .=  '<h2>' . bts('Computers pending', array(), NULL, 'boinc:host-list') . '</h2>';
1432
      $output .=  '<p>' . bts('This user does not yet have any associated'
1433
      . ' computers. Computers will be displayed when they have earned their'
1434
      . ' first credits.', array(), NULL, 'boinc:host-list') . '</p>';
1435
    }
1436
  }
1437
  else {
1438
    $output .=  '<h2>' . bts('Computers hidden', array(), NULL, 'boinc:host-list') . '</h2>';
1439
    $output .=  '<p>' . bts('This user has chosen not to show information'
1440
    . ' about their computers.', array(), NULL, 'boinc:host-list') . '</p>';
1441
  }
1442
  return $output;
1443
}
1444
1445
/**
1446
  * Determine output for task list views when no tasks are found.
1447
  */
1448
function boincwork_views_task_list_empty_text($context = NULL) {
1449
1450
  //
1451
  $output = '';
1452
  switch($context) {
1453
  default:
1454
    $output .=  '<h2>' . bts('No @type tasks', array('@type' => $context), NULL, 'boinc:task-list')
1455
    . '</h2>';
1456
    $output .=  '<p>' . bts('There are no tasks of this type on record', array(), NULL, 'boinc:task-list')
1457
    . '</p>';
1458
  }
1459
  return $output;
1460
}
1461
1462
/**
1463
  * Output links to perform host actions
1464
  */
1465
function boincwork_host_action_links($host_id) {
1466
  $output = '';
1467
  if (boincwork_host_user_is_owner($host_id)) {
1468
    // Show merge hosts option
1469
    $output = '<ul class="tab-list"><li class="first tab">';
1470
    $output .= l(bts('Merge', array(), NULL, 'boinc:form-merge'), "host/{$host_id}/merge");
1471
    $output .= '</li>';
1472
    // If host has no tasks, allow the host to be deleted
1473
    if (!boincwork_host_get_task_count($host_id)) {
1474
      $output .= '<li class="tab">';
1475
      $output .= l(bts('Delete', array(), NULL, 'boinc:form-delete'), "host/{$host_id}/delete",
1476
        array(
1477
          'attributes' => array(
1478
            'onclick' => 'return confirm(\'' . bts('This will delete host @id'
1479
              . ' from your account forever. Are you sure this is OK?',
1480
              array('@id' => $host_id),
1481
              NULL, 'boinc:account-host-delete') . '\')'
1482
          )
1483
        )
1484
      );
1485
      $output .= '</li>';
1486
    }
1487
    $output .= '</ul>';
1488
  }
1489
  return $output;
1490
}
1491
1492
/**
1493
 * Get details for a given host
1494
 */
1495
function boincwork_host_get_info($host_id) {
1496
  db_set_active('boinc_ro');
1497
  $host = db_fetch_object(db_query(
1498
    "SELECT * FROM {host} WHERE id = '%d'",
1499
    $host_id
1500
  ));
1501
  db_set_active('default');
1502
  return $host;
1503
}
1504
1505
/**
1506
 * Get the number of tasks associated with a given host
1507
 */
1508
function boincwork_host_get_task_count($host_id) {
1509
  db_set_active('boinc_ro');
1510
  $count = db_result(db_query(
1511
    "SELECT COUNT(*) FROM {result} WHERE hostid = '%d'",
1512
    $host_id
1513
  ));
1514
  db_set_active('default');
1515
  return $count;
1516
}
1517
1518
/**
1519
 * Check whether a user is the owner of a host
1520
 */
1521
function boincwork_host_user_is_owner($host_id, $uid = NULL) {
1522
  if (!$uid) {
1523
    global $user;
1524
    $uid = $user->uid;
1525
  }
1526
  $account = user_load($uid);
1527
  // Get host owner
1528
  db_set_active('boinc_ro');
1529
  $owner = db_result(db_query(
1530
    "SELECT userid FROM {host} WHERE id = '%d'",
1531
    $host_id
1532
  ));
1533
  db_set_active('default');
1534
  return ($account->boincuser_id === $owner);
1535
}
1536
1537
/**
1538
  * Determine output for host last contact time
1539
  */
1540
function boincwork_host_last_contact($timestamp, $host_id = NULL, $context = NULL) {
1541
  $output = '---';
1542
  $root_log_dir = variable_get('boinc_host_sched_logs_dir', '');
1543
  $log = '';
1544
  if ($timestamp) {
1545
    $output = date('j M Y G:i:s T', $timestamp);
1546
  }
1547
  if ($root_log_dir AND $host_id) {
1548
    $subdir = substr($host_id, 0, -3) OR $subdir = 0;
1549
    $log = implode('/', array($root_log_dir, $subdir, $host_id));
1550
  }
1551
  if ($log AND file_exists($log)) {
1552
    $output = l($output, "host/{$host_id}/log");
1553
  }
1554
  return $output;
1555
}
1556
1557
/**
1558
 *
1559
 */
1560
function boincwork_host_venue_selector($host_id) {
1561
  $output = '';
1562
  if (function_exists('jump_quickly')) {
1563
    $path = "host/{$host_id}/set-venue";
1564
    $venues = array(
1565
      "{$path}/generic" => bts('Generic', array(), NULL, 'boinc:account-preferences-location'),
1566
      "{$path}/home" => bts('Home', array(), NULL, 'boinc:account-preferences-location:-1:ignoreoverwrite'),
1567
      "{$path}/work" => bts('Work', array(), NULL, 'boinc:account-preferences-location'),
1568
      "{$path}/school" => bts('School', array(), NULL, 'boinc:account-preferences-location')
1569
    );
1570
    variable_set('jump_use_js_venues-Array', 1);
1571
    drupal_add_js(drupal_get_path('module', 'jump') . '/jump.js');
1572
    drupal_add_js(drupal_get_path('theme', 'boinc') . '/js/prefs.js', 'theme');
1573
    // Get current venue
1574
    db_set_active('boinc_ro');
1575
    $venue = db_result(db_query(
1576
      "SELECT venue FROM {host} WHERE id = '%d'",
1577
      $host_id
1578
    ));
1579
    db_set_active('default');
1580
    $output .= jump_quickly($venues, 'venues', 1, "{$path}/{$venue}");
1581
  }
1582
  return $output;
1583
}
1584
1585
/**
1586
  * Determine output for task reported time / deadline
1587
  */
1588
function boincwork_task_time_reported($received_time = NULL, $deadline = NULL, $context = NULL) {
1589
  $output = '---';
1590
  if ($received_time OR $deadline) {
1591
    $timestamp = ($received_time) ? $received_time : $deadline;
1592
    $output = date('j M Y G:i:s T', $timestamp);
1593
    // Add a wrapper to deadline text
1594
    if (!$received_time) {
1595
      if (time() < $deadline) {
1596
        $output = '<span class="on-time">' . $output . '</span>';
1597
      }
1598
      else {
1599
        $output = '<span class="past-due">' . $output . '</span>';
1600
      }
1601
    }
1602
  }
1603
  return $output;
1604
}
1605
1606
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1607
 * Functions for creating a task table for users, hosts, and workunits
1608
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1609
1610
/**
1611
 * boincwork_tasktable
1612
 *
1613
 * Given two DB results, generates a table of tasks with a navigation
1614
 * header, and application filter.
1615
 *
1616
 * Parameters
1617
 *
1618
 * @param int $category
1619
 *   An integer specifying the category of task table to display: 0 =>
1620
 *   account, 1=> workunit, 2=> host. These are hardcoded.
1621
 * @param int $queryid
1622
 *   The id of the user, host, or workunit to query. Will be added to
1623
 *   the SQL query.
1624
 * @param int $tselect
1625
 *   The task selection state chosen by the user. 0 is for all states,
1626
 *   other states are defined in html/inc/result.inc
1627
 * @param int $app_id
1628
 *   Application id of the application chosen by user. 0 and -1 are
1629
 *   for all applications.
1630
 * @param int $tablerows
1631
 *   Number of table row to display per page. Defaults to 20.
1632
 */
1633
function boincwork_tasktable($category = 0, $queryid = 1, $tselect = NULL, $app_id = 0, $tablerows = 20) {
1634
  // Check type parameter, if not (0,2) then return an error.
1635
  if ( ($category!=0) AND ($category!=1) AND ($category!=2) ) {
1636
    watchdog('boincwork', 'task table called with invalid category = %category', array('%category' => $category), WATCHDOG_WARNING);
1637
    return '';
1638
  }
1639
1640
  require_boinc( array('util', 'result') );
1641
1642
  global $language;
1643
  $locality=$language->language;
1644
  $nf = new NumberFormatter($locality, NumberFormatter::DECIMAL);
1645
  $nf->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, 0);
1646
  $nf->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 0);
1647
1648
  $output = '';
1649
1650
  $state_hnames = array(
1651
    STATE_ALL => 'All',
1652
    STATE_IN_PROGRESS => 'In progress',
1653
    STATE_PENDING => 'Pending',
1654
    STATE_VALID => 'Valid',
1655
    STATE_INVALID => 'Invalid',
1656
    STATE_ERROR => 'Error',
1657
  );
1658
  // Array (hash) to count total number of results/tasks, and their states.
1659
  $taskstates = array(
1660
    STATE_ALL => 0,
1661
    STATE_IN_PROGRESS => 0,
1662
    STATE_PENDING => 0,
1663
    STATE_VALID => 0,
1664
    STATE_INVALID => 0,
1665
    STATE_ERROR => 0,
1666
  );
1667
  // Array to hold pretty-print result data to be displayed in a table.
1668
  $resultdata = array();
1669
  // Arrays for applications. Form below uses $applications as parameter.
1670
  $application_map = array();
1671
  $application_select_count = array();
1672
  $applications = array();
1673
1674
  // BOINC DB queries for results, application names
1675
  db_set_active('boinc_ro');
1676
1677
  // Query to retreive all results, in order to calculate status for a
1678
  // host with application names for each result.
1679
  $sqlall = "SELECT user_friendly_name,"
1680
      ."r.appid as appid,"
1681
      ."r.server_state AS server_state,"
1682
      ."r.outcome AS outcome,"
1683
      ."r.client_state AS client_state,"
1684
      ."r.validate_state AS validate_state,"
1685
      ."r.exit_status AS exit_status "
1686
      ."FROM {result} AS r "
1687
      ."INNER JOIN {app} AS a "
1688
      ."ON r.appid=a.id ";
1689
1690
  // Use userid, hostid, or workunitid
1691
  if ($category==0) {
1692
    $sqlall .= " WHERE r.userid='%s' ";
1693
  }
1694
  elseif ($category==1) {
1695
    $sqlall .= " WHERE r.workunitid='%s' ";
1696
  }
1697
  elseif ($category==2) {
1698
    $sqlall .= " WHERE r.hostid='%s' ";
1699
  }
1700
  $sqlall .= " ORDER BY user_friendly_name";
1701
  $dbres_all = db_query($sqlall, $queryid);
1702
  db_set_active('default');
1703
1704
  // Loop 1 of DB results
1705
  if ($dbres_all) {
1706
    while ($result = db_fetch_object($dbres_all)) {
1707
      $mystate = state_num($result);
1708
      if ( ($result->appid==$app_id) OR ($app_id==0) OR ($app_id==-1) ) {
1709
        $taskstates[STATE_ALL]++;
1710
        switch ($mystate) {
1711
        case STATE_IN_PROGRESS:
1712
          $taskstates[STATE_IN_PROGRESS]++;
1713
          break;
1714
        case STATE_PENDING:
1715
          $taskstates[STATE_PENDING]++;
1716
          break;
1717
        case STATE_VALID:
1718
          $taskstates[STATE_VALID]++;
1719
          break;
1720
        case STATE_INVALID:
1721
          $taskstates[STATE_INVALID]++;
1722
          break;
1723
        case STATE_ERROR:
1724
          $taskstates[STATE_ERROR]++;
1725
          break;
1726
        }
1727
      }// if app_id
1728
1729
      //map holds a map between app ids and user friendly names for all applications.
1730
      $application_map[$result->appid] = $result->user_friendly_name;
1731
      if ( ($mystate == $tselect) OR ($tselect==STATE_ALL) ) {
1732
        //count of appids in the results.
1733
        $application_select_count[$result->appid]++;
1734
      }// if mystate
1735
1736
    }// while
1737
  }
1738
  else {
1739
  }
1740
1741
  // Entry for all applications.
1742
  $allcount = $application_select_count ? array_sum($application_select_count) : 0;
0 ignored issues
show
introduced by
$application_select_count is an empty array, thus is always false.
Loading history...
1743
  $applications[-1] = bts('Application', array(), NULL, 'boinc:task-table');
1744
  $applications[0] = bts('All applications', array(), NULL, 'boinc:task-table') . ' (' . $allcount . ')';
1745
  // Create application filter from application_map and application_select_count.
1746
  foreach($application_map as $akey => $aname) {
1747
    $acount = 0;
1748
    if ( $application_select_count and array_key_exists($akey, $application_select_count) ) {
1749
      $acount = $application_select_count[$akey];
1750
    }
1751
    $applications[$akey] = $aname . ' ('. $acount . ')';
1752
  }
1753
  // Header array for (sub) results table.
1754
  $resultheader = array(
1755
    array(
1756
      'data' => bts('Task ID', array(), NULL, 'boinc:task-table'),
1757
      'field' => 'id',
1758
    ),
1759
    array(
1760
      'data' => bts('Workunit ID', array(), NULL, 'boinc:task-table'),
1761
      'field' => 'workunitid',
1762
    ),
1763
    array(
1764
      'data' => bts('Computer', array(), NULL, 'boinc:task-table'),
1765
      'field' => 'hostid',
1766
    ),
1767
    array(
1768
      'data' => bts('Sent', array(), NULL, 'boinc:task-table'),
1769
      'field' => 'sent_time',
1770
    ),
1771
    array(
1772
      'data' => bts('Time Reported or Deadline', array(), NULL, 'boinc:task-table')
1773
    ),
1774
    array(
1775
      'data' => bts('Status', array(), NULL, 'boinc:task-table')
1776
    ),
1777
    array(
1778
      'data' => bts('Run time', array(), NULL, 'boinc:task-table'),
1779
      'field' => 'elapsed_time',
1780
    ),
1781
    array(
1782
      'data' => bts('CPU time', array(), NULL, 'boinc:task-table'),
1783
      'field' => 'cpu_time',
1784
    ),
1785
    array(
1786
      'data' => bts('Granted Credit', array(), NULL, 'boinc:task-table'),
1787
      'field' => 'granted_credit',
1788
    ),
1789
    // Application is a column, but won't be added until after tablesort_sql().
1790
  );
1791
1792
  // Query to retreive a subset of the total results for the results table.
1793
  db_set_active('boinc_ro');
1794
  $sqlsub = "SELECT r.id AS id,"
1795
      ."r.name AS name,"
1796
      ."r.workunitid AS workunitid,"
1797
      ."r.hostid as hostid,"
1798
      ."r.sent_time AS sent_time,"
1799
      ."r.received_time AS received_time,"
1800
      ."r.report_deadline AS report_deadline,"
1801
      ."r.server_state AS server_state,"
1802
      ."r.outcome AS outcome,"
1803
      ."r.client_state AS client_state,"
1804
      ."r.validate_state AS validate_state,"
1805
      ."r.exit_status AS exit_status,"
1806
      ."r.elapsed_time AS elapsed_time,"
1807
      ."r.cpu_time AS cpu_time,"
1808
      ."r.granted_credit AS granted_credit,"
1809
      ."r.appid AS appid,"
1810
      ."r.app_version_id AS app_version_id,"
1811
      ."a.user_friendly_name,"
1812
      ."av.version_num AS version_number,"
1813
      ."av.plan_class AS plan_class,"
1814
      ."pl.name AS platform "
1815
      ."FROM {result} AS r "
1816
      ."INNER JOIN {app} AS a "
1817
      ."ON r.appid=a.id "
1818
      ."LEFT JOIN {app_version} AS av "
1819
      ."ON r.app_version_id=av.id "
1820
      ."LEFT JOIN {platform} AS pl "
1821
      ."ON av.platformid=pl.id ";
1822
1823
  // Build an array for the WHERE clauses. The individual clauses are
1824
  // placed into an array, and implode() is used to combine them into
1825
  // a WHERE statement for the sql query. If no such clauses are added
1826
  // to the array, then no WHERE statement will be included.
1827
  $sqlwhere = array();
1828
1829
  // Use userid, hostid, or workunitid
1830
  if ($category==0) {
1831
    $sqlwhere[] = "r.userid = '%s'";
1832
  }
1833
  elseif ($category==1) {
1834
    $sqlwhere[] = "r.workunitid = '%s'";
1835
  }
1836
  elseif ($category==2) {
1837
    $sqlwhere[] = "r.hostid = '%s'";
1838
  }
1839
1840
  // Append additional where clauses based on task selection.
1841
  switch ($tselect) {
1842
  case STATE_IN_PROGRESS:
1843
    $sqlwhere[] = "r.server_state = 4";
1844
    break;
1845
  case STATE_PENDING:
1846
    $sqlwhere[] = "(r.server_state = 5) AND (r.outcome = 1) AND (r.validate_state >= 0) AND (r.validate_state <= 0 OR r.validate_state >= 4) AND (r.validate_state <= 4)";
1847
    break;
1848
  case STATE_VALID:
1849
    $sqlwhere[] = "(r.server_state = 5) AND (r.outcome = 1) AND (r.validate_state = 1)";
1850
    break;
1851
  case STATE_INVALID:
1852
    $sqlwhere[] = "(r.server_state = 5) AND ((r.outcome = 6) OR ((r.outcome = 1) AND ((r.validate_state = 2) OR (r.validate_state = 3) OR (r.validate_state = 5))))";
1853
    break;
1854
  case STATE_ERROR:
1855
    $sqlwhere[] = "(r.server_state = 5) AND (r.outcome >= 3) AND (r.outcome <= 4 OR r.outcome >= 7) AND (r.outcome <= 7)";
1856
    break;
1857
  default:
1858
  }
1859
1860
  if (is_numeric($app_id) AND $app_id>0 ) {
1861
    $sqlwhere[] = "r.appid = '%s'";
1862
    if ($sqlwhere)  $sqlsub .= " WHERE " . implode(' AND ', $sqlwhere);
1863
    $dbres_sub = pager_query( $sqlsub . tablesort_sql($resultheader), $tablerows, 0, NULL, $queryid, $app_id);
1864
  }
1865
  else {
1866
    if ($sqlwhere)  $sqlsub .= " WHERE " . implode(' AND ', $sqlwhere);
1867
    $dbres_sub = pager_query( $sqlsub . tablesort_sql($resultheader), $tablerows, 0, NULL, $queryid);
1868
  }
1869
  db_set_active('default');
1870
1871
  // Loop 2 over DB results.
1872
  if ($dbres_sub) {
1873
    while ($result = db_fetch_object($dbres_sub)) {
1874
      // state_num() function changes $result object, clone $result
1875
      // object for use in state_num()
1876
      // check if state matches selection
1877
      if ( (state_num(clone $result) == $tselect) OR ($tselect==STATE_ALL) ) {
1878
        // create pretty result row
1879
        $prettyresult = array(
1880
          array(
1881
            'data' => l($result->name, "task/{$result->id}"),
1882
            'class' => 'task-name',
1883
          ),
1884
          l($result->workunitid, "workunit/{$result->workunitid}"),
1885
          l($result->hostid, "host/{$result->hostid}"),
1886
          date('j M Y G:i:s T', $result->sent_time),
1887
          boincwork_task_time_reported($result->received_time, $result->report_deadline),
1888
          state_string($result),
1889
          $nf->format($result->elapsed_time),
1890
          $nf->format($result->cpu_time),
1891
          $nf->format($result->granted_credit),
1892
          array(
1893
            'data' => $result->user_friendly_name . " " . pretty_application_version($result->app_version_id,$result->version_number, $result->plan_class, $result->platform),
1894
            'class' => 'task-app',
1895
          ),
1896
        );
1897
        $resultdata[] = array_values($prettyresult);
1898
      }
1899
    }// while
1900
  }
1901
  else {
1902
  }
1903
  // Begin result navigation
1904
1905
  // Set pathprefix based on type
1906
  if ($category==0) {
1907
    $pathprefix = 'account/tasks';
1908
  }
1909
  elseif ($category==1) {
1910
    $pathprefix = 'workunit/' . $queryid . '/tasks';
1911
  }
1912
  elseif ($category==2) {
1913
    $pathprefix = 'host/' . $queryid . '/tasks';
1914
  }
1915
  // Need an "All" tab as well, maps to app_id of zero.
1916
  $application_map[0] = bts('All', array(), NULL, 'boinc:task-table');
1917
  $stitems = array();
1918
  foreach ($taskstates as $state => $numstates) {
1919
    $mypath = $pathprefix . '/' . $state . '/' . $app_id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pathprefix does not seem to be defined for all execution paths leading up to this point.
Loading history...
1920
    if ($state==STATE_ALL) {
1921
      $ltext = '<span class="tab task-app-name">' . bts('All', array(), NULL, 'boinc:task-table') . ' (' . $numstates . ')</span>';
1922
    }
1923
    else {
1924
      $ltext = '<span class="tab">' . bts($state_hnames[$state], array(), NULL, 'boinc:task-table') . ' (' . $numstates . ')</span>';
1925
    }
1926
    $myitem = array(
1927
      'data' => l($ltext, $mypath, array('html' => TRUE) ),
1928
    );
1929
    if ($state==$tselect) {
1930
      $myitem['class'] = 'active';
1931
    }
1932
    $stitems[] = $myitem;
1933
  }
1934
  // Add reset button
1935
  $mypath = $pathprefix . '/0/0';
1936
  $ltext = '<span class="tab">' . bts('Reset', array(), NULL, 'boinc:task-table') . '</span>';
1937
  $stitems[] = array( 'data' => l($ltext, $mypath, array('html' => TRUE) ) );
1938
1939
  $output .= theme_item_list($stitems, NULL, 'ul' . ' class="tabs secondary clearfix"');
1940
1941
  // Application select-drop down form
1942
  // Hack to place Application form into header
1943
  // App ID of zero maps to "-1" for drop-down box.
1944
  if ($app_id==0) {
1945
    $app_id=-1;
1946
  }
1947
  $resultheader[] = drupal_get_form('boincwork_selectapp_form', $applications, $app_id);
1948
1949
  // Begin table of results
1950
  if ( is_array($resultheader) AND is_array($resultdata) ) {
0 ignored issues
show
introduced by
The condition is_array($resultdata) is always true.
Loading history...
1951
1952
    // Take advantage of the fact that $category is the same as the row/column we want to remove.
1953
    if ( ($category==1) OR ($category==2) ) {
1954
      unset($resultheader[$category]);
1955
      delete_col($resultdata, $category);
1956
    }
1957
1958
    $output .= theme_table($resultheader, $resultdata);
1959
    if (count($resultdata) > 0) {
1960
      $output .= theme('pager');
1961
    }
1962
  }
1963
  return $output;
1964
}
1965
1966
/**
1967
 * Function to delete a column from an array.
1968
 */
1969
function delete_col(&$array, $offset) {
1970
  return array_walk($array, function (&$v) use ($offset) {
1971
     array_splice($v, $offset, 1);
1972
  });
1973
}
1974
1975
/**
1976
 * Pretty print the application version
1977
 *
1978
 * Parameters are obtained from the BOINC project database, result,
1979
 * app, app_version, and platform tables.
1980
 *
1981
 * Parameters
1982
 * @param int $appverid
1983
 *  app_version_id field, may be negative- anonymous platforms.
1984
 * @param int $vernum
1985
 *  version_num field, application version number, may be NULL
1986
 * @param int $plan_class
1987
 *  plan_class field, applcation plan class, may be NULL
1988
 * @param string $plfm
1989
 *  platform name, may be NULL
1990
 */
1991
function pretty_application_version($appverid, $vernum, $plan_class, $plfm) {
1992
  switch ($appverid) {
1993
    case ANON_PLATFORM_UNKNOWN:
1994
      return "Anonymous platform";
1995
    case ANON_PLATFORM_CPU:
1996
      return "Anonymous platform CPU";
1997
    case ANON_PLATFORM_NVIDIA:
1998
      return "Anonymous platform NVIDIA GPU";
1999
    case ANON_PLATFORM_ATI:
2000
      return "Anonymous platform AMD GPU";
2001
    case ANON_PLATFORM_INTEL_GPU:
2002
      return "Anonymous platform Intel GPU";
2003
    case ANON_PLATFORM_APPLE_GPU:
2004
      return "Anonymous platform Apple GPU";
2005
    case 0:
2006
      return "---";
2007
    default:
2008
      // Handle the case where the appversid is still negative. This
2009
      // may be cause BOINC has introduced a new anonymous platform
2010
      // that is not handled by the above case statements.
2011
      if ($appverid < 0) {
2012
        return "Unknown Anonymous platform";
2013
      }
2014
      else {
2015
        $prettyv = sprintf("%d.%02d", $vernum/100, $vernum%100);
2016
        $prettyc = ($plan_class) ? "($av->plan_class)" : '';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $av seems to be never defined.
Loading history...
2017
        return "v$prettyv $prettyc $plfm";
2018
      }
2019
  }
2020
}
2021