You are here

update_detailed_email.module in Update Status Detailed Email 7

Same filename and directory in other branches
  1. 6 update_detailed_email.module

Adds detail to the email message Drupal core's Update Status sends.

The information sent in the email is based on the information seen at /admin/reports/updates.

File

update_detailed_email.module
View source
<?php

/**
 * @file
 * Adds detail to the email message Drupal core's Update Status sends.
 *
 * The information sent in the email is based on the information seen
 * at /admin/reports/updates.
 */

/**
 * Implements hook_help().
 */
function update_detailed_email_help($page, $arg) {
  switch ($page) {
    case 'admin/help#update_detailed_email':
      return '<p>' . t('The Update Detailed Email module modifies the basic email that the core Update Status module sends. It includes detailed information about what modules need updating, and uses a customizable subject line. The information sent in the email is based on the information seen on the <a href="@update-report">update report</a> page. Go to <a href="@update-settings">Update status module settings page</a> to set a customized subject line.', array(
        '@update-report' => url('admin/reports/updates'),
        '@update-settings' => url('admin/reports/updates/settings'),
      )) . '</p>';
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add subject line text field to the update settings form.
 */
function update_detailed_email_form_update_settings_alter(&$form, &$form_state) {
  $form['update_detailed_email_subject'] = array(
    '#type' => 'textfield',
    '#title' => 'Subject',
    '#default_value' => variable_get('update_detailed_email_subject', _update_detailed_email_default_subject()),
    '#size' => 78,
    '#maxlength' => 78,
    '#required' => TRUE,
    '#description' => 'The subject line of the email message.',
    '#weight' => 0,
  );
  if (module_exists('token')) {
    $form['update_detailed_email_subject']['#description'] .= ' May contain replacement patterns from the list below.';
    $form['token_help'] = array(
      '#title' => t('Replacement patterns'),
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#weight' => 0,
    );
    $form['token_help']['info'] = array(
      '#theme' => 'token_tree',
      '#token_types' => array(
        'global',
      ),
    );
  }
  $form['#submit'][] = 'update_detailed_email_subject_submit';
}

/**
 * Submit handle for the subject field.
 */
function update_detailed_email_subject_submit($form, $form_state) {
  variable_set('update_detailed_email_subject', $form['update_detailed_email_subject']['#value']);
}

/**
 * Implements hook_mail_alter().
 *
 * The update status email needs to be intercepted so it can be changed to HTML.
 */
function update_detailed_email_mail_alter(&$message) {
  if ($message['id'] == 'update_status_notify') {
    if (module_exists('update')) {
      module_load_include('inc', 'update', 'update.report');
      if (function_exists('update_status')) {
        if (_update_detailed_email_is_html()) {
          $message['headers']['Content-Type'] = 'text/html';
        }
        if (module_exists('token')) {
          $message['subject'] = token_replace(variable_get('update_detailed_email_subject', _update_detailed_email_default_subject()));
        }
        else {
          $message['subject'] = variable_get('update_detailed_email_subject', _update_detailed_email_default_subject());
        }
        foreach ($message['body'] as &$part) {
          $part = '<p>' . $part . '</p>';
        }
        $message['body'] = array(
          implode("\n\n", $message['body']),
        );
        $message['body'][] = update_status();
      }
    }
  }
}

/**
 * Implements hook_theme_registry_alter().
 *
 * The registry needs to be changed to override the update status
 * theme function. The "if" will check to see if the original theme
 * function is in place. If not, no override. This allows a theme
 * (template.php) to still override the original function.
 */
function update_detailed_email_theme_registry_alter(&$theme_registry) {
  if (!empty($theme_registry['update_report']) && $theme_registry['update_report']['function'] == 'theme_update_report') {
    $theme_registry['update_report']['function'] = 'theme_update_detailed_email';
  }
}

/**
 * Implements hook_theme().
 *
 * theme_update_detailed_email_message() is being registered so a
 * theme can override it and change the HTML being sent.
 */
function update_detailed_email_theme() {
  return array(
    'update_detailed_email_message' => array(
      'arguments' => array(
        'data' => NULL,
      ),
    ),
    'update_detailed_email_message_version' => array(
      'arguments' => array(
        'version' => NULL,
        'title' => NULL,
      ),
    ),
  );
}

/**
 * Theme function to override the original update theme function.
 *
 * If on the updates page, use the original function.
 *
 * @param array $variables
 *   An array of update information for installed modules.
 *
 * @return string
 *   Return either the orignal theme rendering of the data or the new one.
 */
function theme_update_detailed_email($variables) {
  if (current_path() != 'admin/reports/updates') {
    return theme('update_detailed_email_message', $variables);
  }
  else {
    return theme_update_report($variables);
  }
}

/**
 * Theme the detailed update email.
 *
 * Much of the code is taken from the original
 * theme_update_report(). The changes are primarily focused on making
 * the outputted HTML more email-friendly.
 *
 * @param array $variables
 *   An array of update information for installed modules.
 *
 * @return string
 *   Themed output.
 */
function theme_update_detailed_email_message($variables) {
  $output = '<style type="text/css"><!-- body { margin: 1em; font-size: 100%; background: none; } --></style>';
  $sep = "<br />\n";
  $data = $variables['data'];
  if (!is_array($data)) {
    $output .= '<p>' . $data . '</p>';
    return $output;
  }
  $rows = array();
  $notification_level = variable_get('update_notification_threshold', 'all');
  foreach ($data as $project) {

    // Don't include modules that are up to date.
    //
    // If set to only notify of security updates, don't include
    // non-security updates in the email.
    if ($notification_level == 'all' && $project['status'] != UPDATE_CURRENT || $notification_level == 'security' && $project['status'] == UPDATE_NOT_SECURE) {
      $row = '<p>';
      switch ($project['status']) {
        case UPDATE_NOT_SECURE:
          $row .= t('Security update required!');
          break;
        case UPDATE_REVOKED:
          $row .= t('Revoked!');
          break;
        case UPDATE_NOT_SUPPORTED:
          $row .= t('Not supported!');
          break;
        case UPDATE_NOT_CURRENT:
          $row .= t('Update available');
          break;
        default:
          $row .= check_plain($project['reason']);
          break;
      }
      $row .= $sep;

      // Project title.
      if (isset($project['title'])) {
        if (isset($project['link'])) {
          $row .= l($project['title'], $project['link']);
        }
        else {
          $row .= check_plain($project['title']);
        }
      }
      else {
        $row .= check_plain($project['name']);
      }

      // Project version.
      $row .= ' ' . check_plain($project['existing_version']);

      // Project date.
      if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) {
        $row .= ' (' . format_date($project['datestamp'], 'custom', 'Y-M-d') . ')';
      }

      // Versions.
      if (isset($project['recommended'])) {

        // Recommended.
        if ($project['existing_version'] !== $project['recommended']) {
          $row .= theme('update_detailed_email_message_version', array(
            'version' => $project['releases'][$project['recommended']],
            'title' => 'Recommended version:',
          ));

          // Now, print any security updates.
          if (!empty($project['security updates'])) {
            foreach ($project['security updates'] as $security_update) {
              $row .= theme('update_detailed_email_message_version', array(
                'version' => $security_update,
                'title' => 'Security update:',
              ));
            }
          }
        }

        // Latest.
        if ($project['recommended'] !== $project['latest_version']) {
          $row .= theme('update_detailed_email_message_version', array(
            'version' => $project['releases'][$project['latest_version']],
            'title' => 'Latest version:',
          ));
        }

        // Development.
        if ($project['install_type'] == 'dev' && isset($project['dev_version']) && $project['recommended'] !== $project['dev_version']) {
          $row .= theme('update_detailed_email_message_version', array(
            'version' => $project['releases'][$project['dev_version']],
            'title' => 'Development version:',
          ));
        }
      }

      // Also available.
      if (isset($project['also'])) {
        foreach ($project['also'] as $also) {
          $row .= theme('update_detailed_email_message_version', array(
            'version' => $project['releases'][$also],
            'title' => 'Also available:',
          ));
        }
      }
      $row .= $sep;

      // Extra.
      if (!empty($project['extra'])) {
        foreach ($project['extra'] as $key => $value) {
          $row .= check_plain($value['label']) . ': ';
          $row .= theme('placeholder', $value['data']);
          $row .= $sep;
        }
      }

      // Includes.
      sort($project['includes']);
      $row .= t('Includes: %includes', array(
        '%includes' => implode(', ', $project['includes']),
      ));

      // Base themes.
      if (!empty($project['base_themes'])) {
        sort($project['base_themes']);

        // We use !dependencies and manually call theme('placeholder')
        // here to avoid breaking the D6 string freeze. This identical
        // string is already in modules/system/system.admin.inc.
        $row .= $sep;
        $dep_args = array(
          '!dependencies' => theme('placeholder', implode(', ', $project['base_themes'])),
        );
        $row .= t('Depends on: !dependencies', $dep_args);
      }

      // Sub-themes.
      if (!empty($project['sub_themes'])) {
        sort($project['sub_themes']);

        // We use !required and manually call theme('placeholder')
        // here to avoid breaking the D6 string freeze. This identical
        // string is already in modules/system/system.admin.inc.
        $row .= $sep;
        $req_args = array(
          '!required' => theme('placeholder', implode(', ', $project['sub_themes'])),
        );
        $row .= t('Required by: !required', $req_args);
      }
      $row .= "</p>\n\n";
      if (!isset($rows[$project['project_type']])) {
        $rows[$project['project_type']] = array();
      }
      $row_key = isset($project['title']) ? drupal_strtolower($project['title']) : drupal_strtolower($project['name']);
      $rows[$project['project_type']][$row_key] = array(
        'data' => array(
          $row,
        ),
      );
    }
  }
  $project_types = array(
    'core' => t('Drupal core'),
    'module' => t('Modules'),
    'theme' => t('Themes'),
    'disabled-module' => t('Disabled modules'),
    'disabled-theme' => t('Disabled themes'),
  );
  foreach ($project_types as $type_name => $type_label) {
    if (!empty($rows[$type_name])) {
      ksort($rows[$type_name]);
      $output .= '<p><strong>' . $type_label . "</strong></p>\n\n";
      foreach ($rows[$type_name] as $list) {
        $output .= $list['data'][0] . "\n\n";
      }
    }
  }
  return $output;
}

/**
 * Theme a project version.
 *
 * @param array $variables
 *   An array of variables, including:
 *    - version
 *    - title
 *
 * @return string
 *   Themed output.
 */
function theme_update_detailed_email_message_version($variables) {
  $version = $variables['version'];
  $output = "<br />\n";
  $output .= t($variables['title']);
  $output .= ' ' . l($version['version'], $version['release_link']);
  $output .= ' (' . format_date($version['date'], 'custom', 'Y-M-d') . ') ';
  $output .= ' ' . l(t('Download'), $version['download_link']);
  $output .= ' | ' . l(t('Release notes'), $version['release_link']);
  return $output;
}

/**
 * Default subject.
 */
function _update_detailed_email_default_subject() {
  if (module_exists('token')) {
    return 'New release(s) available for [site:name] @ [site:url]';
  }
  else {
    $subject_args = array(
      '!site_name' => variable_get('site_name', 'Drupal'),
      '!site_url' => url('', array(
        'absolute' => TRUE,
      )),
    );
    return t('New release(s) available for !site_name @ !site_url', $subject_args);
  }
}

/**
 * Identify whether the email will be sent as HTML or plaintext.
 *
 * This may need improving for per-user configuration?
 */
function _update_detailed_email_is_html() {
  $mail_system = variable_get('mail_system', array());
  if (isset($mail_system['update_status_notify']) && $mail_system['update_status_notify'] == 'MimeMailSystem') {
    return TRUE;
  }
}

Functions

Namesort descending Description
theme_update_detailed_email Theme function to override the original update theme function.
theme_update_detailed_email_message Theme the detailed update email.
theme_update_detailed_email_message_version Theme a project version.
update_detailed_email_form_update_settings_alter Implements hook_form_FORM_ID_alter().
update_detailed_email_help Implements hook_help().
update_detailed_email_mail_alter Implements hook_mail_alter().
update_detailed_email_subject_submit Submit handle for the subject field.
update_detailed_email_theme Implements hook_theme().
update_detailed_email_theme_registry_alter Implements hook_theme_registry_alter().
_update_detailed_email_default_subject Default subject.
_update_detailed_email_is_html Identify whether the email will be sent as HTML or plaintext.