| 1 |
<?php
|
| 2 |
// $Id: journal.module,v 1.20 2009/06/21 00:02:13 sun Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Allows to maintain a custom log of performed setup and configuration actions.
|
| 7 |
*
|
| 8 |
* Journal module adds additional fields to all forms in a Drupal site.
|
| 9 |
* Only users granted the 'access journal' permission are able to add entries
|
| 10 |
* to the journal.
|
| 11 |
*
|
| 12 |
* Journal form fields may be disabled for certain forms, for example forms that
|
| 13 |
* are displayed in blocks.
|
| 14 |
*
|
| 15 |
* @todo Describe Demo module implementation.
|
| 16 |
* @todo Are we able to track enabling/disabling of modules automatically?
|
| 17 |
* @todo Allow to include all form field values in a journal entry.
|
| 18 |
*/
|
| 19 |
|
| 20 |
/**
|
| 21 |
* Implementation of hook_help().
|
| 22 |
*/
|
| 23 |
function journal_help($path, $arg) {
|
| 24 |
switch ($path) {
|
| 25 |
case 'admin/modules#description':
|
| 26 |
return t('Allows to maintain a custom log of performed setup and configuration actions.');
|
| 27 |
}
|
| 28 |
}
|
| 29 |
|
| 30 |
/**
|
| 31 |
* Implementation of hook_perm().
|
| 32 |
*/
|
| 33 |
function journal_perm() {
|
| 34 |
return array('access journal');
|
| 35 |
}
|
| 36 |
|
| 37 |
/**
|
| 38 |
* Implementation of hook_menu().
|
| 39 |
*/
|
| 40 |
function journal_menu() {
|
| 41 |
$items = array();
|
| 42 |
$items['admin/reports/journal'] = array(
|
| 43 |
'title' => 'Journal entries',
|
| 44 |
'description' => 'View journal entries.',
|
| 45 |
'page callback' => 'journal_view',
|
| 46 |
'access arguments' => array('access journal'),
|
| 47 |
);
|
| 48 |
$items['admin/reports/journal/list'] = array(
|
| 49 |
'title' => 'List',
|
| 50 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 51 |
'weight' => -10,
|
| 52 |
);
|
| 53 |
$items['admin/reports/journal/patches'] = array(
|
| 54 |
'title' => 'Patches',
|
| 55 |
'description' => 'View list of applied patches and hacks on this Drupal site.',
|
| 56 |
'page callback' => 'journal_patch_view',
|
| 57 |
'access arguments' => array('access journal'),
|
| 58 |
'type' => MENU_LOCAL_TASK,
|
| 59 |
);
|
| 60 |
$items['admin/reports/journal/patches/edit'] = array(
|
| 61 |
'title' => 'Edit patch',
|
| 62 |
'page callback' => 'drupal_get_form',
|
| 63 |
'page arguments' => array('journal_patch_form'),
|
| 64 |
'access arguments' => array('access journal'),
|
| 65 |
'type' => MENU_CALLBACK,
|
| 66 |
);
|
| 67 |
$items['admin/reports/journal/patches/delete'] = array(
|
| 68 |
'page callback' => 'drupal_get_form',
|
| 69 |
'page arguments' => array('journal_patch_delete_confirm'),
|
| 70 |
'access arguments' => array('access journal'),
|
| 71 |
'type' => MENU_CALLBACK,
|
| 72 |
);
|
| 73 |
return $items;
|
| 74 |
}
|
| 75 |
|
| 76 |
/**
|
| 77 |
* Add Journal fields to all forms.
|
| 78 |
*
|
| 79 |
* Any form, except user-defined form_ids, will be extended by a fieldset
|
| 80 |
* to enter a journal entry. All journal form ids are stored in one variable
|
| 81 |
* array; having form_ids as keys and a boolean value whether to skip a form id
|
| 82 |
* (0) or force/require a journal entry for it (1).
|
| 83 |
*
|
| 84 |
* @see journal_form_ids_default()
|
| 85 |
*/
|
| 86 |
function journal_form_alter(&$form, &$form_state, $form_id) {
|
| 87 |
if (!user_access('access journal')) {
|
| 88 |
return;
|
| 89 |
}
|
| 90 |
$entry_required = FALSE;
|
| 91 |
if (!isset($form['#submit'])) {
|
| 92 |
$form['#submit'] = array();
|
| 93 |
}
|
| 94 |
// Check whether form has to/must not be extended.
|
| 95 |
$journal_ids = variable_get('journal_form_ids', journal_form_ids_default());
|
| 96 |
if (isset($journal_ids[$form_id]) || in_array('system_settings_form_submit', $form['#submit'])) {
|
| 97 |
if (isset($journal_ids[$form_id]) && !$journal_ids[$form_id]) {
|
| 98 |
// No journal entry for 'form_id' => 0.
|
| 99 |
return;
|
| 100 |
}
|
| 101 |
else {
|
| 102 |
// Require journal entry for 'form_id' => 1 or system settings forms.
|
| 103 |
$entry_required = TRUE;
|
| 104 |
}
|
| 105 |
}
|
| 106 |
|
| 107 |
// Shift system_settings_form buttons.
|
| 108 |
if (in_array('system_settings_form_submit', $form['#submit'])) {
|
| 109 |
$weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0;
|
| 110 |
$form['buttons']['#weight'] = $weight + 2;
|
| 111 |
$journal_weight = $weight + 1;
|
| 112 |
$entry_required = TRUE;
|
| 113 |
}
|
| 114 |
else {
|
| 115 |
$journal_weight = 100;
|
| 116 |
}
|
| 117 |
|
| 118 |
// Prepend our journal submit handler, so we can eliminate the form value of
|
| 119 |
// journal_entry, which would be saved as a variable in system_settings_form()
|
| 120 |
// otherwise.
|
| 121 |
array_unshift($form['#submit'], 'journal_form_submit');
|
| 122 |
|
| 123 |
$form['journal'] = array(
|
| 124 |
'#weight' => $journal_weight,
|
| 125 |
'#tree' => FALSE,
|
| 126 |
);
|
| 127 |
|
| 128 |
// Store the path on which this form was initially displayed.
|
| 129 |
// We need to store this in a hidden field, since forms with custom '#action's
|
| 130 |
// (like admin/build/modules) will reset our value to $_GET['q'] otherwise.
|
| 131 |
$form['journal']['journal_location'] = array(
|
| 132 |
'#type' => 'hidden',
|
| 133 |
'#value' => (!empty($_REQUEST['journal_location']) ? $_REQUEST['journal_location'] : $_GET['q']),
|
| 134 |
);
|
| 135 |
|
| 136 |
// Add journal entry field.
|
| 137 |
$form['journal']['journal_entry'] = array(
|
| 138 |
'#type' => 'textarea',
|
| 139 |
'#title' => t('Journal entry'),
|
| 140 |
'#description' => t('If not empty, contents of this field will be logged to the system journal.'),
|
| 141 |
'#required' => $entry_required,
|
| 142 |
'#wysiwyg' => FALSE,
|
| 143 |
);
|
| 144 |
if ($entry_required && user_access('access devel information')) {
|
| 145 |
$form['journal']['journal_entry']['#required'] = FALSE;
|
| 146 |
$form['journal']['journal_omit'] = array(
|
| 147 |
'#type' => 'checkbox',
|
| 148 |
'#title' => t('Skip journal entry'),
|
| 149 |
'#return_value' => 1,
|
| 150 |
'#default_value' => 0,
|
| 151 |
'#description' => t('The journal entry for this form is required. If enabled, the form can be submitted without a journal entry.'),
|
| 152 |
);
|
| 153 |
$form['#validate'][] = 'journal_form_validate';
|
| 154 |
}
|
| 155 |
}
|
| 156 |
|
| 157 |
/**
|
| 158 |
* Validate optional journal entry for privileged users.
|
| 159 |
*/
|
| 160 |
function journal_form_validate($form, &$form_state) {
|
| 161 |
if (empty($form_state['values']['journal_omit']) && empty($form_state['values']['journal_entry'])) {
|
| 162 |
form_set_error('journal', t('!name field is required.', array('!name' => t('Journal entry'))));
|
| 163 |
}
|
| 164 |
}
|
| 165 |
|
| 166 |
/**
|
| 167 |
* Save a new journal entry and clean out form values.
|
| 168 |
*/
|
| 169 |
function journal_form_submit($form, &$form_state) {
|
| 170 |
if (!empty($form_state['values']['journal_entry'])) {
|
| 171 |
journal_add_entry($form_state['values']['journal_entry'], $form_state['values']['journal_location']);
|
| 172 |
}
|
| 173 |
unset($form_state['values']['journal_entry'], $form_state['values']['journal_location']);
|
| 174 |
}
|
| 175 |
|
| 176 |
/**
|
| 177 |
* Indicate if a form must not extended.
|
| 178 |
*
|
| 179 |
* @param string $form_id
|
| 180 |
* A form_id to check against.
|
| 181 |
*
|
| 182 |
* @return bool
|
| 183 |
* True if form should be skipped, false if form can be extended.
|
| 184 |
*
|
| 185 |
* @todo Introduce a new FAPI attribute #journal = TRUE to require a journal
|
| 186 |
* entry if Journal module is enabled - OR - introduce a new hook_journal?
|
| 187 |
*/
|
| 188 |
function journal_form_ids_default() {
|
| 189 |
return array(
|
| 190 |
'comment_form' => 0,
|
| 191 |
'dblog_filter_form' => 0,
|
| 192 |
'devel_admin_settings' => 0,
|
| 193 |
'devel_execute_form' => 0,
|
| 194 |
'devel_switch_user_form' => 0,
|
| 195 |
'journal_patch_form' => 0,
|
| 196 |
'node_filter_form' => 0,
|
| 197 |
'poll_view_voting' => 0,
|
| 198 |
'search_block_form' => 0,
|
| 199 |
'search_box' => 0,
|
| 200 |
'search_form' => 0,
|
| 201 |
'search_theme_form' => 0,
|
| 202 |
'system_modules' => 1,
|
| 203 |
'user_admin_perm' => 1,
|
| 204 |
'user_filter_form' => 0,
|
| 205 |
'user_login_block' => 0,
|
| 206 |
'views_exposed_form' => 0,
|
| 207 |
'views_filters' => 0,
|
| 208 |
'views_ui_add_display_form' => 0,
|
| 209 |
'views_ui_add_item_form' => 0,
|
| 210 |
'views_ui_analyze_view_button' => 0,
|
| 211 |
'views_ui_config_item_form' => 0,
|
| 212 |
'views_ui_config_type_form' => 0,
|
| 213 |
'views_ui_edit_details_form' => 0,
|
| 214 |
'views_ui_edit_display_form' => 0,
|
| 215 |
'views_ui_export_page' => 0,
|
| 216 |
'views_ui_list_views_form' => 0,
|
| 217 |
'views_ui_preview_form' => 0,
|
| 218 |
'views_ui_rearrange_form' => 0,
|
| 219 |
'views_ui_remove_display_form' => 0,
|
| 220 |
);
|
| 221 |
}
|
| 222 |
|
| 223 |
/**
|
| 224 |
* Implementation of hook_user().
|
| 225 |
*/
|
| 226 |
function journal_user($op, &$edit, &$user) {
|
| 227 |
if ($op == 'delete') {
|
| 228 |
db_query('UPDATE {journal} SET uid = 0 WHERE uid = %d', $user->uid);
|
| 229 |
}
|
| 230 |
}
|
| 231 |
|
| 232 |
/**
|
| 233 |
* Implementation of hook_block().
|
| 234 |
*/
|
| 235 |
function journal_block($op = 'list', $delta = 0, $edit = array()) {
|
| 236 |
if ($op == 'list') {
|
| 237 |
$blocks = array();
|
| 238 |
$blocks['backlog'] = array(
|
| 239 |
'info' => t('Journal entries'),
|
| 240 |
'weight' => -10,
|
| 241 |
'enabled' => 1,
|
| 242 |
'region' => 'right',
|
| 243 |
);
|
| 244 |
return $blocks;
|
| 245 |
}
|
| 246 |
else if ($op == 'view' && user_access('access journal')) {
|
| 247 |
$block = array();
|
| 248 |
switch ($delta) {
|
| 249 |
case 'backlog':
|
| 250 |
$result = db_query("SELECT j.*, u.name FROM {journal} j INNER JOIN {users} u ON j.uid = u.uid WHERE j.location = '%s' ORDER BY j.timestamp DESC", $_GET['q']);
|
| 251 |
if ($output = journal_output($result, 'list')) {
|
| 252 |
drupal_add_css(drupal_get_path('module', 'journal') .'/journal.css', 'module', 'all', FALSE);
|
| 253 |
$block = array(
|
| 254 |
'subject' => t('Journal entries'),
|
| 255 |
'content' => $output,
|
| 256 |
);
|
| 257 |
}
|
| 258 |
break;
|
| 259 |
}
|
| 260 |
return $block;
|
| 261 |
}
|
| 262 |
}
|
| 263 |
|
| 264 |
/**
|
| 265 |
* Output a sortable table containing all journal entries.
|
| 266 |
*/
|
| 267 |
function journal_view() {
|
| 268 |
$sql = "SELECT j.*, u.name FROM {journal} j INNER JOIN {users} u ON j.uid = u.uid";
|
| 269 |
|
| 270 |
$header = array(
|
| 271 |
array('data' => t('Date'), 'field' => 'j.timestamp', 'sort' => 'desc'),
|
| 272 |
array('data' => t('User'), 'field' => 'u.name'),
|
| 273 |
t('Message'),
|
| 274 |
t('Location'),
|
| 275 |
);
|
| 276 |
$tablesort = tablesort_sql($header);
|
| 277 |
$result = pager_query($sql . $tablesort, 50);
|
| 278 |
|
| 279 |
return journal_output($result, 'table', $header);
|
| 280 |
}
|
| 281 |
|
| 282 |
/**
|
| 283 |
* Render journal entries.
|
| 284 |
*
|
| 285 |
* Use this function to render and return
|
| 286 |
* - a journal provided as a database query result resource or
|
| 287 |
* - a custom journal provided as an array containing journal entry objects.
|
| 288 |
*
|
| 289 |
* This function may look insane to some, but it ensures that implementation of
|
| 290 |
* journal module into other modules is as easy as possible.
|
| 291 |
*
|
| 292 |
* @param array $journal
|
| 293 |
* A database query result resource or an array containing journal entry
|
| 294 |
* objects to output.
|
| 295 |
* @param string $format
|
| 296 |
* Whether to output all log entries as 'table', 'list' or plain 'text'.
|
| 297 |
* @param array $header
|
| 298 |
* An array containing header data for 'table' output.
|
| 299 |
*
|
| 300 |
* @todo Add XML output format.
|
| 301 |
*/
|
| 302 |
function journal_output($journal, $format = 'table', $header = array()) {
|
| 303 |
switch ($format) {
|
| 304 |
case 'text':
|
| 305 |
// Output delimiter in first line, since this may change.
|
| 306 |
$output = '\t' . "\n";
|
| 307 |
|
| 308 |
while ($entry = (is_array($journal) ? array_shift($journal) : db_fetch_object($journal))) {
|
| 309 |
$row = array(
|
| 310 |
$entry->timestamp,
|
| 311 |
$entry->uid,
|
| 312 |
$entry->message,
|
| 313 |
$entry->location,
|
| 314 |
);
|
| 315 |
$output .= implode("\t", $row) ."\n";
|
| 316 |
}
|
| 317 |
break;
|
| 318 |
|
| 319 |
case 'list':
|
| 320 |
$output = '';
|
| 321 |
while ($entry = (is_array($journal) ? array_shift($journal) : db_fetch_object($journal))) {
|
| 322 |
$output .= '<li>';
|
| 323 |
$output .= '<span class="journal-info">'. theme('username', $entry) .' '. format_date($entry->timestamp, 'small') .':</span>';
|
| 324 |
$output .= '<span class="journal-entry">'. filter_xss_admin($entry->message) .'</span>';
|
| 325 |
$output .= '</li>';
|
| 326 |
}
|
| 327 |
if ($output) {
|
| 328 |
$output = '<ul id="journal-backlog">'. $output .'</ul>';
|
| 329 |
}
|
| 330 |
break;
|
| 331 |
|
| 332 |
case 'table':
|
| 333 |
default:
|
| 334 |
$rows = array();
|
| 335 |
while ($entry = (is_array($journal) ? array_shift($journal) : db_fetch_object($journal))) {
|
| 336 |
$rows[] = array(
|
| 337 |
format_date($entry->timestamp, 'small'),
|
| 338 |
theme('username', $entry),
|
| 339 |
filter_xss_admin($entry->message),
|
| 340 |
l(truncate_utf8($entry->location, 32, FALSE, TRUE), $entry->location),
|
| 341 |
);
|
| 342 |
}
|
| 343 |
|
| 344 |
if (empty($rows)) {
|
| 345 |
$rows[] = array(array('data' => t('No journal entries available.'), 'colspan' => 4));
|
| 346 |
}
|
| 347 |
|
| 348 |
$output = theme('table', $header, $rows);
|
| 349 |
$output .= theme('pager', NULL, 50, 0);
|
| 350 |
break;
|
| 351 |
}
|
| 352 |
|
| 353 |
return $output;
|
| 354 |
}
|
| 355 |
|
| 356 |
/**
|
| 357 |
* Convert a journal into an array.
|
| 358 |
*
|
| 359 |
* @param mixed $data
|
| 360 |
* Journal data.
|
| 361 |
* @param string $type
|
| 362 |
* The type of passed-in journal data.
|
| 363 |
*
|
| 364 |
* @return array $journal
|
| 365 |
* An array containing one or more journal entry objects.
|
| 366 |
*/
|
| 367 |
function journal_convert($data, $type = 'text') {
|
| 368 |
$journal = array();
|
| 369 |
|
| 370 |
switch ($type) {
|
| 371 |
case 'text':
|
| 372 |
default:
|
| 373 |
$data = explode('\n', $data);
|
| 374 |
|
| 375 |
// Determine delimiter string.
|
| 376 |
$delimiter = array_shift($data);
|
| 377 |
|
| 378 |
while ($row = array_shift($data)) {
|
| 379 |
$row = explode($delimiter, $row);
|
| 380 |
$journal[] = (object)$row;
|
| 381 |
}
|
| 382 |
break;
|
| 383 |
}
|
| 384 |
|
| 385 |
return $journal;
|
| 386 |
}
|
| 387 |
|
| 388 |
/**
|
| 389 |
* Store a new journal entry in the database.
|
| 390 |
*
|
| 391 |
* @param string $description
|
| 392 |
* A journal entry text entered by an user.
|
| 393 |
* @param string $location
|
| 394 |
* The path on which the journal entry has been entered.
|
| 395 |
*/
|
| 396 |
function journal_add_entry($description, $location) {
|
| 397 |
global $user;
|
| 398 |
|
| 399 |
db_query("INSERT INTO {journal} (uid, message, location, timestamp) VALUES (%d, '%s', '%s', %d)", $user->uid, $description, $location, time());
|
| 400 |
}
|
| 401 |
|
| 402 |
/**
|
| 403 |
* Output a sortable table containing all recorded patches.
|
| 404 |
*/
|
| 405 |
function journal_patch_view() {
|
| 406 |
$header = array(
|
| 407 |
array('data' => t('Date'), 'field' => 'j.timestamp', 'sort' => 'desc'),
|
| 408 |
array('data' => t('Module'), 'field' => 'j.module'),
|
| 409 |
array('data' => t('User'), 'field' => 'u.name'),
|
| 410 |
t('Description'),
|
| 411 |
t('Issue'),
|
| 412 |
t('Status'),
|
| 413 |
t('Operations'),
|
| 414 |
);
|
| 415 |
$sql = "SELECT j.*, u.name FROM {journal_patch} j INNER JOIN {users} u ON j.uid = u.uid";
|
| 416 |
$result = pager_query($sql . tablesort_sql($header), 25);
|
| 417 |
$module_list = module_list(FALSE, FALSE);
|
| 418 |
$rows = array();
|
| 419 |
while ($entry = db_fetch_object($result)) {
|
| 420 |
$modules = array();
|
| 421 |
foreach (explode(',', $entry->module) as $module) {
|
| 422 |
$info = drupal_parse_info_file(drupal_get_path('module', $module) .'/'. $module .'.info');
|
| 423 |
if (isset($info['project'])) {
|
| 424 |
$url = 'http://drupal.org/project/issues/'. $info['project'];
|
| 425 |
$modules[] = l($info['name'], $url);
|
| 426 |
}
|
| 427 |
else {
|
| 428 |
$modules[] = $info['name'];
|
| 429 |
}
|
| 430 |
}
|
| 431 |
if ($entry->url != '') {
|
| 432 |
if (preg_match('@drupal.org/node/(\d+)@', $entry->url, $issue_title)) {
|
| 433 |
$issue_link = l('#'. $issue_title[1], $entry->url);
|
| 434 |
}
|
| 435 |
else {
|
| 436 |
$issue_link = l(t('View'), $entry->url);
|
| 437 |
}
|
| 438 |
}
|
| 439 |
else {
|
| 440 |
$issue_link = '';
|
| 441 |
}
|
| 442 |
$rows[] = array(
|
| 443 |
format_date($entry->timestamp, 'small'),
|
| 444 |
implode(', ', $modules),
|
| 445 |
theme('username', $entry),
|
| 446 |
filter_xss_admin($entry->description),
|
| 447 |
$issue_link,
|
| 448 |
t($entry->status),
|
| 449 |
l(t('edit'), "admin/reports/journal/patches/edit/$entry->pid"),
|
| 450 |
);
|
| 451 |
}
|
| 452 |
|
| 453 |
if (empty($rows)) {
|
| 454 |
$rows[] = array(array('data' => t('No patch entries available.'), 'colspan' => 7));
|
| 455 |
}
|
| 456 |
|
| 457 |
$output = drupal_get_form('journal_patch_form');
|
| 458 |
$output .= theme('table', $header, $rows);
|
| 459 |
$output .= theme('pager', NULL, 50, 0);
|
| 460 |
return $output;
|
| 461 |
}
|
| 462 |
|
| 463 |
/**
|
| 464 |
* Form builder function for patches.
|
| 465 |
*/
|
| 466 |
function journal_patch_form($form_state, $pid = NULL) {
|
| 467 |
drupal_add_css(drupal_get_path('module', 'journal') .'/journal_patch.css', 'module', 'all', FALSE);
|
| 468 |
$patch = array();
|
| 469 |
if (isset($pid)) {
|
| 470 |
$patch = db_fetch_array(db_query("SELECT j.* FROM {journal_patch} j WHERE j.pid = %d", $pid));
|
| 471 |
}
|
| 472 |
$patch += array(
|
| 473 |
'module' => '',
|
| 474 |
'description' => '',
|
| 475 |
'url' => '',
|
| 476 |
'status' => 'open',
|
| 477 |
);
|
| 478 |
|
| 479 |
$form = array();
|
| 480 |
$form['patch'] = array(
|
| 481 |
'#type' => 'fieldset',
|
| 482 |
'#title' => t('Add patch record'),
|
| 483 |
'#tree' => TRUE,
|
| 484 |
);
|
| 485 |
$form['patch']['module'] = array(
|
| 486 |
'#type' => 'select',
|
| 487 |
'#title' => t('Affected modules'),
|
| 488 |
'#options' => module_list(FALSE, FALSE, TRUE),
|
| 489 |
'#multiple' => TRUE,
|
| 490 |
'#default_value' => explode(',', $patch['module']),
|
| 491 |
'#size' => 8,
|
| 492 |
'#required' => TRUE,
|
| 493 |
'#prefix' => '<div class="journal-patch-module-select">',
|
| 494 |
'#suffix' => '</div>',
|
| 495 |
);
|
| 496 |
$form['patch']['description'] = array(
|
| 497 |
'#type' => 'textarea',
|
| 498 |
'#title' => t('Description'),
|
| 499 |
'#default_value' => $patch['description'],
|
| 500 |
'#required' => TRUE,
|
| 501 |
'#prefix' => '<div class="clear-block">',
|
| 502 |
'#suffix' => '</div>',
|
| 503 |
);
|
| 504 |
$form['patch']['url'] = array(
|
| 505 |
'#type' => 'textfield',
|
| 506 |
'#title' => t('Issue URL'),
|
| 507 |
'#default_value' => $patch['url'],
|
| 508 |
'#prefix' => '<div class="journal-patch-issue clear-block">',
|
| 509 |
);
|
| 510 |
$form['patch']['status'] = array(
|
| 511 |
'#type' => 'select',
|
| 512 |
'#title' => t('Status'),
|
| 513 |
'#options' => array('open' => t('open'), 'fixed' => t('fixed'), "won't fix" => t("won't fix")),
|
| 514 |
'#default_value' => $patch['status'],
|
| 515 |
'#suffix' => '</div>',
|
| 516 |
);
|
| 517 |
if (!empty($patch['pid'])) {
|
| 518 |
$form['patch']['pid'] = array(
|
| 519 |
'#type' => 'value',
|
| 520 |
'#value' => $patch['pid'],
|
| 521 |
);
|
| 522 |
}
|
| 523 |
$form['patch']['submit'] = array(
|
| 524 |
'#type' => 'submit',
|
| 525 |
'#value' => isset($patch['pid']) ? t('Save') : t('Add'),
|
| 526 |
);
|
| 527 |
if (!empty($patch['pid'])) {
|
| 528 |
$form['patch']['delete'] = array(
|
| 529 |
'#type' => 'submit',
|
| 530 |
'#value' => t('Delete'),
|
| 531 |
);
|
| 532 |
}
|
| 533 |
return $form;
|
| 534 |
}
|
| 535 |
|
| 536 |
/**
|
| 537 |
* Submit handler for journal patch form.
|
| 538 |
*/
|
| 539 |
function journal_patch_form_submit($form, &$form_state) {
|
| 540 |
global $user;
|
| 541 |
|
| 542 |
$patch = $form_state['values']['patch'];
|
| 543 |
|
| 544 |
if (preg_match('@^#\d+@', $patch['url'])) {
|
| 545 |
$patch['url'] = 'http://drupal.org/node/'. substr($patch['url'], 1);
|
| 546 |
}
|
| 547 |
|
| 548 |
if ($form_state['values']['op'] == t('Add')) {
|
| 549 |
db_query("INSERT INTO {journal_patch} (uid, module, description, url, status, timestamp) VALUES (%d, '%s', '%s', '%s', '%s', %d)", $user->uid, implode(',', $patch['module']), $patch['description'], $patch['url'], $patch['status'], time());
|
| 550 |
}
|
| 551 |
else if ($form_state['values']['op'] == t('Save')) {
|
| 552 |
db_query("UPDATE {journal_patch} SET uid = %d, module = '%s', description = '%s', url = '%s', status = '%s' WHERE pid = %d", $user->uid, implode(',', $patch['module']), $patch['description'], $patch['url'], $patch['status'], $patch['pid']);
|
| 553 |
$form_state['redirect'] = 'admin/reports/journal/patches';
|
| 554 |
}
|
| 555 |
else if ($form_state['values']['op'] == t('Delete')) {
|
| 556 |
$form_state['redirect'] = 'admin/reports/journal/patches/delete/'. $patch['pid'];
|
| 557 |
}
|
| 558 |
}
|
| 559 |
|
| 560 |
/**
|
| 561 |
* Confirmation form to delete a patch record.
|
| 562 |
*/
|
| 563 |
function journal_patch_delete_confirm($form_state, $pid) {
|
| 564 |
$form = array();
|
| 565 |
$form['pid'] = array('#type' => 'value', '#value' => $pid);
|
| 566 |
$description = db_result(db_query("SELECT description FROM {journal_patch} WHERE pid = %d", $pid));
|
| 567 |
$form['patch_description'] = array(
|
| 568 |
'#type' => 'item',
|
| 569 |
'#title' => t('Description'),
|
| 570 |
'#value' => filter_xss_admin($description),
|
| 571 |
);
|
| 572 |
return confirm_form($form,
|
| 573 |
t('Are you sure you want to delete this patch record?'),
|
| 574 |
'admin/reports/journal/patches',
|
| 575 |
t('This action cannot be undone.'), t('Delete'), t('Cancel')
|
| 576 |
);
|
| 577 |
}
|
| 578 |
|
| 579 |
/**
|
| 580 |
* Form submit callback for patch record delete confirm form.
|
| 581 |
*/
|
| 582 |
function journal_patch_delete_confirm_submit($form, &$form_state) {
|
| 583 |
db_query("DELETE FROM {journal_patch} WHERE pid = %d", $form_state['values']['pid']);
|
| 584 |
$form_state['redirect'] = 'admin/reports/journal/patches';
|
| 585 |
}
|
| 586 |
|