'Journal entries', 'description' => 'View journal entries.', 'page callback' => 'journal_view', 'access arguments' => array('access journal'), ); return $items; } /** * Add Journal fields to all forms. * * Any form, except user-defined form_ids, will be extended by a fieldset * to enter a journal entry. All journal form ids are stored in one variable * array; having form_ids as keys and a boolean value whether to skip a form id * (0) or force/require a journal entry for it (1). * * @see journal_form_ids_default() */ function journal_form_alter(&$form, &$form_state, $form_id) { if (!user_access('access journal')) { return; } $entry_required = FALSE; if (!isset($form['#submit'])) { $form['#submit'] = array(); } // Check whether form has to/must not be extended. $journal_ids = variable_get('journal_form_ids', journal_form_ids_default()); if (isset($journal_ids[$form_id]) || in_array('system_settings_form_submit', $form['#submit'])) { if (isset($journal_ids[$form_id]) && !$journal_ids[$form_id]) { // No journal entry for 'form_id' => 0. return; } else { // Require journal entry for 'form_id' => 1 or system settings forms. $entry_required = TRUE; } } // Shift system_settings_form buttons. if (in_array('system_settings_form_submit', $form['#submit'])) { $weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0; $form['buttons']['#weight'] = $weight + 1; $journal_weight = $weight; $entry_required = TRUE; } else { $journal_weight = 100; } // Prepend our journal submit handler, so we can eliminate the form value of // journal_entry, which would be saved as a variable in system_settings_form() // otherwise. array_unshift($form['#submit'], 'journal_form_submit'); // Store the path on which this form was initially displayed. // We need to store this in a hidden field, since forms with custom '#action's // (like admin/build/modules) will reset our value to $_GET['q'] otherwise. $form['journal']['journal_location'] = array( '#type' => 'hidden', '#value' => (!empty($_REQUEST['journal_location']) ? $_REQUEST['journal_location'] : $_GET['q']), ); // Add journal entry field. $form['journal']['journal_entry'] = array( '#type' => 'textarea', '#title' => t('Journal entry'), '#description' => t('If not empty, contents of this field will be logged to the system journal.'), '#required' => $entry_required, '#weight' => $journal_weight, '#wysiwyg' => FALSE, ); } /** * Save a new journal entry and clean out form values. */ function journal_form_submit($form, &$form_state) { if (!empty($form_state['values']['journal_entry'])) { journal_add_entry($form_state['values']['journal_entry'], $form_state['values']['journal_location']); } unset($form_state['values']['journal_entry'], $form_state['values']['journal_location']); } /** * Indicate if a form must not extended. * * @param string $form_id * A form_id to check against. * * @return bool * True if form should be skipped, false if form can be extended. * * @todo Introduce a new FAPI attribute #journal = TRUE to require a journal * entry if Journal module is enabled - OR - introduce a new hook_journal? */ function journal_form_ids_default() { return array( 'devel_admin_settings' => 0, 'devel_execute_form' => 0, 'devel_switch_user_form' => 0, 'search_block_form' => 0, 'search_theme_form' => 0, 'search_box' => 0, 'user_filter_form' => 0, 'user_login_block' => 0, 'views_ui_list_views_form' => 0, 'views_ui_analyze_view_button' => 0, 'views_ui_edit_details_form' => 0, 'views_ui_add_display_form' => 0, 'views_ui_edit_display_form' => 0, 'views_ui_remove_display_form' => 0, 'views_ui_config_item_form' => 0, 'views_ui_config_type_form' => 0, 'views_ui_add_item_form' => 0, 'views_ui_rearrange_form' => 0, 'views_ui_preview_form' => 0, 'views_ui_export_page' => 0, 'views_exposed_form' => 0, ); } /** * Implementation of hook_user(). */ function journal_user($op, &$edit, &$user) { if ($op == 'delete') { db_query('UPDATE {journal} SET uid = 0 WHERE uid = %d', $user->uid); } } /** * Implementation of hook_block(). */ function journal_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $blocks = array(); $blocks['backlog'] = array( 'info' => t('Journal entries'), 'weight' => -10, 'enabled' => 1, 'region' => 'right', ); return $blocks; } else if ($op == 'view' && user_access('access journal')) { $block = array(); switch($delta) { case 'backlog': $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']); if ($output = journal_output($result, 'list')) { drupal_add_css(drupal_get_path('module', 'journal') .'/journal.css', 'module', 'all', FALSE); $block = array( 'subject' => t('Journal entries'), 'content' => $output, ); } break; } return $block; } } /** * Output a sortable table containing all journal entries. */ function journal_view() { $sql = "SELECT j.*, u.name FROM {journal} j INNER JOIN {users} u ON j.uid = u.uid"; $header = array( array('data' => t('Date'), 'field' => 'j.timestamp', 'sort' => 'desc'), array('data' => t('User'), 'field' => 'u.name'), t('Message'), t('Location'), ); $tablesort = tablesort_sql($header); $result = pager_query($sql . $tablesort, 50); return journal_output($result, 'table', $header); } /** * Render journal entries. * * Use this function to render and return * - a journal provided as a database query result resource or * - a custom journal provided as an array containing journal entry objects. * * This function may look insane to some, but it ensures that implementation of * journal module into other modules is as easy as possible. * * @param array $journal * A database query result resource or an array containing journal entry * objects to output. * @param string $format * Whether to output all log entries as 'table', 'list' or plain 'text'. * @param array $header * An array containing header data for 'table' output. * * @todo Add XML output format. */ function journal_output($journal, $format = 'table', $header = array()) { switch ($format) { case 'text': // Output delimiter in first line, since this may chance. $output = '\t' . "\n"; while ($entry = (is_array($journal) ? array_shift($journal) : db_fetch_object($journal))) { $row = array( $entry->timestamp, $entry->uid, $entry->message, $entry->location, ); $output .= implode("\t", $row) ."\n"; } break; case 'list': $output = ''; while ($entry = (is_array($journal) ? array_shift($journal) : db_fetch_object($journal))) { $output .= '