Completed
Push — 7.x-1.x ( 2f9e3c...1070be )
by Frédéric G.
01:36
created

qa.module (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @file
5
 * OSInet Quality Assurance module for Drupal
6
 *
7
 * @copyright Copyright (C) 2005-2012 Frederic G. MARAND for Ouest Systèmes Informatiques (OSInet)
8
 *
9
 * @since DRUPAL-4-6
10
 *
11
 * @license Licensed under the disjunction of the CeCILL, version 2 and General Public License version 2 and later
12
 *
13
 * License note: QA is distributed by OSInet to its customers under the
14
 * CeCILL 2.0 license. OSInet support services only apply to the module
15
 * when distributed by OSInet, not by any third-party further down the
16
 * distribution chain.
17
 *
18
 * If you obtained QA from drupal.org, that site received it under the
19
 * GPLv2 license and can therefore distribute it under the GPLv2, and
20
 * so can you and just anyone down the chain as long as the GPLv2 terms
21
 * are abided by, the module distributor in that case being the
22
 * drupal.org organization or the downstream distributor, not OSInet.
23
 */
24
use OSInet\DrupalQA\Variable\Variable;
25
26
/**
27
 * Implements hook_init().
28
 *
29
 * - add module CSS.
30
 * - register custom autoloader.
31
 *
32
 * TODO probabaly remove the CSS from here.
33
 */
34
function qa_init() {
35
  drupal_add_css(drupal_get_path('module', 'qa') .'/qa.css');
36
}
37
38
/**
39
 * Implements hook_boot().
40
 *
41
 * Menu loaders may need objects before hook_init().
42
 */
43
function qa_boot() {
44
  spl_autoload_register('qa_autoload');
45
}
46
47
/**
48
 * Dedicated autoloader for QA.
49
 *
50
 * Only load symbols in the OSInet\DrupalQA namespace.
51
 *
52
 * @param string $name
53
 */
54
function qa_autoload($name) {
55
  // Adjust verbosity if needed.
56
  $verbose = FALSE;
57
58
  $verbose && watchdog('qa/autoload', 'Loading %name', array('%name' => $name), WATCHDOG_DEBUG);
59
  if (strpos($name, 'OSInet\DrupalQA\\') !== 0) {
60
    return;
61
  }
62
63
  $module_path = drupal_get_path('module', 'qa');
64
  $path_array = explode('\\', $name);
65
  $filename = array_pop($path_array);
66
  array_unshift($path_array, $module_path);
67
  $path = implode('/', $path_array);
68
  if (!is_dir($path) || !is_readable($path)) {
69
    $args = array('%path' => $path);
70
    drupal_set_message(t("Cannot read plugins directory %path.", $args), 'warning');
71
    watchdog('qa', "Cannot read plugins directory %path", $args, WATCHDOG_WARNING);
72
  }
73
  $path_array[] = "{$filename}.php";
74
  $path = implode('/', $path_array);
75
  $sts = include_once $path;
76
  $verbose && drupal_set_message(t('QA Autoloaded %path: @result', array(
77
    '%path' => $path,
78
    '@result' => $sts ? t('Success'): t('Failure'),
79
  )));
80
}
81
82
/**
83
 * Implements hook_menu().
84
 */
85
function qa_menu() {
86
  $items = array();
87
  $items['admin/reports/qa'] = array(
88
    'title'            => 'Quality Assurance',
89
    'description'      => 'Assisted auditing tools by OSInet',
90
    'page callback'    => 'drupal_get_form',
91
    'page arguments'   => array('qa_report_form'),
92
    'access arguments' => array('access site reports'),
93
  );
94
  $items['admin/reports/qa/projects'] = array(
95
    'title'           => 'Projects',
96
    'type'             => MENU_LOCAL_TASK,
97
    'page callback'    => 'qa_report_projects',
98
    'access arguments' => array('access site reports'),
99
    'file'             => 'qa_projects.inc',
100
  );
101
  $items['admin/reports/qa/variable'] = array(
102
    'title'           => 'Variables',
103
    'type'             => MENU_LOCAL_TASK,
104
    'page callback'    => 'qa_report_variables',
105
    'access arguments' => array('access site reports'),
106
    'file'             => 'qa_variables.inc',
107
  );
108
  $items['admin/reports/qa/variable/%qa_variable'] = array(
109
    'title'           => 'Variables',
110
    'type'             => MENU_CALLBACK,
111
    'page callback'    => 'qa_report_variable',
112
    'page arguments'   => array(4),
113
    'access arguments' => array('access site reports'),
114
    'file'             => 'qa_variables.inc',
115
  );
116
117
  $items['admin/reports/qa/results'] = array(
118
    'title'            => 'Quality Assurance results',
119
    'page callback'    => 'qa_report_results',
120
    'page arguments'   => array(),
121
    'access arguments' => array('access site reports'),
122
    'type'             => MENU_CALLBACK,
123
  );
124
  $items['admin/reports/qa/list'] = array(
125
    'title'            => 'QA Tests',
126
    'type'             => MENU_DEFAULT_LOCAL_TASK,
127
  );
128
  $items['admin/reports/qa/dependencies'] = array(
129
    'title'            => 'Dependencies',
130
    'type'             => MENU_LOCAL_TASK,
131
    'page callback'    => 'qa_page_dependencies',
132
    'access arguments' => array('access site reports'),
133
    'file'             => 'qa_dependencies.inc',
134
    'weight'           => 1,
135
  );
136
  return $items;
137
}
138
139
/**
140
 * Page callback for qa/dependencies
141
 *
142
 * TODO convert to native Image_GraphViz to remove dependency on graphviz_filter
143
 * XXX convert to Grafizzi to remove dependency on Image_GraphViz
144
 *
145
 * @return string
146
 */
147
function qa_page_dependencies() {
148
  $G = qa_dependencies();
149
  // passed by reference: cannot pass a function return
150
  return graphviz_filter_render($G);
151
}
152
153
/**
154
 * Batch conclusion callback.
155
 *
156
 * @param boolean $success
157
 * @param array $results
158
 * @param array $operations
159
 */
160
function qa_report_finished($success, $results, $operations) {
161
  unset($results['#message']);
162
  if ($success) {
163
    $message = format_plural(count($results), 'One control pass ran.', '@count control passes ran.');
164
  }
165
  else {
166
    $message = t('Finished with an error.');
167
  }
168
  drupal_set_message($message);
169
  $_SESSION['qa_results'] = $results;
170
  drupal_goto('admin/reports/qa/results');
171
}
172
173
/**
174
 * Results page for QA Controls batch.
175
 *
176
 * @link http://www.php.net/manual/fr/function.unserialize.php @endlink
177
 */
178
function qa_report_results() {
179
  if (empty($_SESSION['qa_results'])) {
180
    drupal_goto('admin/reports/qa');
181
  }
182
  // Work around incomplete classes
183
  $results = unserialize(serialize($_SESSION['qa_results']));
184
185
  $header = array(
186
    t('Control'),
187
    t('Status'),
188
    t('Results'),
189
  );
190
  $data = array();
191
  foreach ($results as $pass) {
192
    $control = $pass->control;
193
    $data[] = array(
194
      $control->title,
195
      $pass->status
196
        ? theme('image', array(
197
          'path' => 'misc/watchdog-ok.png',
198
          'alt' => t('OK'),
199
          ))
200
        : theme('image', array(
201
          'path' => 'misc/watchdog-error.png',
202
          'alt' => t('Error'),
203
          )),
204
      $pass->result,
205
    );
206
  }
207
  $ret = theme('table', array(
208
    'header' => $header,
209
    'rows' => $data,
210
    'attributes' => array(
211
      'id' => 'qa-results',
212
    )));
213
  // unset($_SESSION['qa_results']);
214
  return $ret;
215
}
216
217
/**
218
 * Form builder for QA packages/controls selection form.
219
 *
220
 * @return array
221
 */
222
function qa_report_form($form, $form_state) {
223
  $form = array();
224
  $base = drupal_get_path('module', 'qa');
225
  $packages = OSInet\DrupalQA\Exportable::getClasses($base, 'OSInet\DrupalQA\BasePackage');
226
  ksort($packages);
227
  foreach ($packages as $package_name => $package) {
228
    $collapsed = TRUE;
229
    $form[$package_name] = array(
230
      '#type' => 'fieldset',
231
      '#title' => filter_xss_admin($package->title),
232
      '#description' => filter_xss_admin($package->description),
233
      '#collapsible' => TRUE,
234
    );
235
    $controls = $package->getClasses($package->dir, 'OSInet\DrupalQA\BaseControl');
236
237
    foreach ($controls as $control_name => $control) {
238
      $default_value = isset($_SESSION[$control_name])
239
        ? $_SESSION[$control_name]
240
        : NULL;
241
      if ($default_value) {
242
        $collapsed = FALSE;
243
      }
244
245
      $deps = array();
246
      $met = TRUE;
247
      foreach ($control->getDependencies() as $dep_name) {
248
        if (module_exists($dep_name)) {
249
          $deps[] = t('@module (<span class="admin-enabled">available</span>)', array('@module' => $dep_name));
250
        }
251
        else {
252
          $deps[] = t('@module (<span class="admin-disabled">unavailable</span>)', array('@module' => $dep_name));
253
          $met = FALSE;
254
        }
255
      }
256
      $form[$package_name][$control_name] = array(
257
        '#type'          => 'checkbox',
258
        '#default_value' => $met ? $default_value : 0,
259
        '#title'         => filter_xss_admin($control->title),
260
        '#description'   => filter_xss_admin($control->description),
261
        '#disabled'      => !$met,
262
      );
263
      $form[$package_name][$control_name .'-dependencies'] = array(
264
        '#value' => t('Depends on: !dependencies', array(
265
          '!dependencies' => implode(', ', $deps),
266
          )),
267
        '#prefix' => '<div class="admin-dependencies">',
268
        '#suffix' => '</div>',
269
      );
270
    }
271
    $form[$package_name]['#collapsed'] = $collapsed;
272
  }
273
274
  $form['submit'] = array(
275
    '#type'  => 'submit',
276
    '#value' => t('Run controls'),
277
  );
278
279
  return $form;
280
}
281
282
/**
283
 * Submit handler for QA packages/controls selection form
284
 *
285
 * @param array $form
286
 * @param array $form_state
287
 */
288
function qa_report_form_submit($form, &$form_state) {
289
  $controls = array();
290
  foreach ($form_state['values'] as $item => $value) {
291
    if (class_exists($item) && is_subclass_of($item, '\OSInet\DrupalQA\BaseControl')) {
0 ignored issues
show
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
292
      if ($value) {
293
        $controls[$item] = $value;
294
      }
295
      $_SESSION[$item] = $value;
296
    }
297
    elseif ($value == 1) {
298
      $args = array(
299
        '%control' => $item,
300
      );
301
      drupal_set_message(t('Requested invalid control %control', $args), 'error');
302
      watchdog('qa', 'Requested invalid control %control', $args, WATCHDOG_ERROR);
303
    }
304
  }
305
306
  drupal_set_message(t('Prepare to run these controls: @controls', array(
307
    '@controls' => implode(', ', array_keys($controls)))), 'status');
308
  $batch = array(
309
    'operations'       => array(),
310
    'title'            => t('QA Controls running'),
311
    'init_message'     => t('QA Controls initializing'),
312
    // 'progress_message' => t('current: @current, Remaining: @remaining, Total: @total'),
313
    'error_message'    => t('Error in QA Control'),
314
    'finished'         => 'qa_report_finished',
315
    // 'file'             => '', // only if outside module file
316
  );
317
318
  foreach ($controls as $item => $value) {
319
    $batch['operations'][] = array('qa_report_run_pass', array($item));
320
  }
321
  batch_set($batch);
322
}
323
324
/**
325
 * Batch progress step.
326
 *
327
 * @return void
328
 */
329
function qa_report_run_pass($class_name, &$context) {
330
  $name_arg = array('@class' => $class_name);
331
332
  $control = new $class_name();
333
  if (!is_object($control)) {
334
    drupal_set_message(t('Cannot obtain an instance for @class', $name_arg), 'error');
335
    $context['results']['#message'] = t('Control @class failed to run.', $name_arg);
336
    $context['message'] = t('Control @class failed to run.', $name_arg);
337
    $context['results'][$class_name] = 'wow';
338
  }
339
  else {
340
    drupal_set_message(t('Running a control instance for @class', $name_arg), 'status');
341
    $pass = $control->run();
342
    if (!$pass->status) {
343
      $context['success'] = FALSE;
344
    }
345
    $context['results']['#message'][] = t('Control @class ran', $name_arg);
346
    $context['message'] = theme('item_list', $context['results']['#message']);
347
    $context['results'][$class_name] = $pass;
348
  }
349
}
350
351
function qa_variable_load($name) {
352
  $variable = new Variable($name);
353
  if (!$variable->is_set) {
354
    return FALSE;
355
  }
356
357
  return $variable;
358
}
359