It was bugging me that the "you have updates" emails don't tell you what updates are available. Attached is a patch to the dev version that appends that info to the emails, as well as lets you know how long the update has been available; this is particularly useful when you want to wait a week or two when a new patch to a major module comes out and you want to sit on it a week or two so as not to get cut by some bleeding edge bug.

If you want to install this patch into the production version, just append the following code to update_advanced.module

/**
 * Appends information about modules that can be updated to the body of update emails.
 * 2010-Apr-12 by MadOverlord
 *
 * Implements hook_mail_alter().
 *
 * One line is added per module that has a newer release or security update.
 * This line says what module, what the status is, and how long the update
 * has been available.
 *
 * Directly calls functions inside the Drupal 6 core update module.
 *
 * @param &$message
 *   Array containing the message to be altered; see hook_mail_alter()
 *   documentation for the structure of this array.  $message is passed
 *   by reference, so it can be directly modified.
 *
 * @return
 *   No return value (but $message may be modified as a side-effect)
 *
 * @see hook_mail_alter()
 * @see http://api.drupal.org/api/function/hook_mail_alter/6
 * @see update.module
 */

function update_advanced_mail_alter(&$message) {

  // Quit if not an update_status_notify email.

  if ($message['id'] != 'update_status_notify') {
    return;
  }

  $message['body'][] = t('Summary of available updates:');

  // Get the update requirements and output data.

  if ($available = update_get_available(TRUE)) {

    // Get the update data structure (cribbed from update module).

    module_load_include('inc', 'update', 'update.compare');
    $data = update_calculate_project_data($available);

    // Sort so updates come first, subsorted by age.

    uasort($data, '_update_advanced_mail_alter_sort');

    // Process each project, generating one line of output for each module
    // for which an update is available.  Due to the sorting, as soon as
    // we see a module for which output is not required, we are done.

    foreach ($data as $project) {

      switch ($project['status']) {

        case UPDATE_NOT_SECURE:
          $state = t('SECURITY UPDATE REQUIRED');
          break;

        case UPDATE_REVOKED:
          $state = t('Revoked');
          break;

        case UPDATE_NOT_SUPPORTED:
          $state = t('Not supported');
          break;

        case UPDATE_NOT_CURRENT:
          $state = t('Update available');
          break;

        default:
          return; // Our work is done! (function exits here!)

      } // switch

      // Add a line to the email describing the update; !escapes are used with t()
      // because this is text that is going into a plain-text email (though given
      // the data the escapes insert, @ would work just as well).

      // which version is recommended?

      $recommended = _update_advanced_mail_alter_recommended($project);

      if ($recommended != NULL) {

        // how long has recommended email been available?

        $age = floor((time() - $recommended['date']) / 86400);

        if ($age <= 0) {
          $status = t('!state as of today.', array('!state' => $state));
        }
        elseif ($age == 1) {
          $status = t('!state since yesterday.', array('!state' => $state));
        }
        else {
          $status = t('!state for !days days.', array('!state' => $state, '!days' => $age));
        }

      }
      else {

        $status = t('!state for an unknown period of time.', array('!state' => $state));

      }

      $message['body'][] = '  ' . t('!project : !status', array('!project' => $project['info']['name'], '!status' => $status));

    } // foreach

  }

} // function update_advanced_mail_alter

/**
 * Private sort function to order projects based on status and age.
 *
 * More critical statuses (like security alerts) sort lower/to the top.
 * Within each category, more recently changed projects sort lower.
 *
 * @param a
 *   A project record.
 * @param b
 *   Another project record.
 * @return
 *   Sorting order of (a,b) using standard <0,0,>0 <,=,> coding.
 *
 * @see update_advanced_mail_alter()
 * @see uasort()
 */

function _update_advanced_mail_alter_sort($a, $b) {

  // set all negative statuses (which we should not see because they have
  // to be non-error for the email to get sent in the first place) to sort
  // to the bottom of the list.  The current max valid status is 5.

  $a_status = $a['status'] > 0 ? $a['status'] : 999;
  $b_status = $b['status'] > 0 ? $b['status'] : 999;

  // Roughly figure out # of days since recommended version was released.
  // Use 0 if there is no recommended release for some reason.

  $a_rec = _update_advanced_mail_alter_recommended($a);

  if ($a_rec != NULL) {
    $a_age = floor((time() - $a_rec['date']) / 86400);
  }
  else {
    $a_age = 0;
  }

  $b_rec = _update_advanced_mail_alter_recommended($b);

  if ($b_rec != NULL) {
    $b_age = floor((time() - $b_rec['date']) / 86400);
  }
  else {
    $b_age = 0;
  }

  // Combine so things sort with status levels sorted by age.
  // Note this will break if the update has been around for over a million
  // days.  However, since I expect that I will break well before this
  // happens, you will forgive me for not being too concerned about it.

  $a_status = (1000000 * $a_status) + $a_age;
  $b_status = (1000000 * $b_status) + $b_age;

  return $a_status - $b_status;

} // function _update_advanced_mail_alter__sort

/**
 * Private function that accesses the subarray for the recommended
 * release of a module.
 *
 * @param $project
 *   A project record (generated by the update module).
 *
 * @return
 *   Recommended version subrecord, or NULL if there isn't one.
 */

function _update_advanced_mail_alter_recommended($project) {

  if (isset($project['recommended'])) {
    return $project['releases'][$project['recommended']];
  }
  else {
    return NULL;
  }

} // function _update_advanced_mail_alter_recommended

Comments

MadOverlord’s picture

Status: Active » Needs review
Leeteq’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev
Status: Needs review » Needs work

Big +1 for this.
Can this be adapted to 7.x too? No activity in this thread for long time, so changing to the current major Drupal version may trigger more attention.

dww’s picture

See https://drupal.org/patch/create for how to actually generate a patch for this so it can be reviewed, tested, and eventually applied.

However, update_advanced is very low on my list of priorities (as you can tell from the age of this issue!) so I can't promise a speedy turn-around. ;)

Cheers,
-Derek

MadOverlord’s picture

Version: 7.x-1.x-dev » 6.x-1.x-dev
StatusFileSize
new6.03 KB

Sorry for the delay in noticing this.

Here is a patch against 6.x-1.x that implements a slightly improved version of the original tweak. None of the original module code is touched, it just adds a mail_alter hook into update_advanced.module.

I am not running 7.x so I can't tell if it will work with that, but as long as the data structures and a few core functions haven't changed, it ought to.

Best,
Robert

PS: for those who want to just plonk this at the end of their .module file, here's the current version. Only tweak from original posted version is a fix to display the proper main module name.

/**
 * Appends information about modules that can be updated to the body of update emails.
 * 2012-May-22 by MadOverlord
 *
 * Implements hook_mail_alter().
 *
 * One line is added per module that has a newer release or security update.
 * This line says what module, what the status is, and how long the update
 * has been available.
 *
 * Directly calls functions inside the Drupal 6 core update module.
 *
 * @param &$message
 *   Array containing the message to be altered; see hook_mail_alter()
 *   documentation for the structure of this array.  $message is passed
 *   by reference, so it can be directly modified.
 *
 * @return
 *   No return value (but $message may be modified as a side-effect)
 *
 * @see hook_mail_alter()
 * @see http://api.drupal.org/api/function/hook_mail_alter/6
 * @see update.module
 */

function update_advanced_mail_alter(&$message) {

  // Quit if not an update_status_notify email.

  if ($message['id'] != 'update_status_notify') {
    return;
  }

  $message['body'][] = t('Summary of available updates:');

  // Get the update requirements and output data.

  if ($available = update_get_available(TRUE)) {

    // Get the update data structure (cribbed from update module).

    module_load_include('inc', 'update', 'update.compare');
    $data = update_calculate_project_data($available);

    // Sort so updates come first, subsorted by age.

    uasort($data, '_update_advanced_mail_alter_sort');

    // Process each project, generating one line of output for each module
    // for which an update is available.  Due to the sorting, as soon as
    // we see a module for which output is not required, we are done.

    foreach ($data as $project) {

      switch ($project['status']) {

        case UPDATE_NOT_SECURE:
          $state = t('SECURITY UPDATE REQUIRED');
          break;

        case UPDATE_REVOKED:
          $state = t('Revoked');
          break;

        case UPDATE_NOT_SUPPORTED:
          $state = t('Not supported');
          break;

        case UPDATE_NOT_CURRENT:
          $state = t('Update available');
          break;

        default:
          return; // Our work is done! (function exits here!)

      } // switch

      // Add a line to the email describing the update; !escapes are used with t()
      // because this is text that is going into a plain-text email (though given
      // the data the escapes insert, @ would work just as well).

      // which version is recommended?

      $recommended = _update_advanced_mail_alter_recommended($project);

      if ($recommended != NULL) {

        // how long has recommended email been available?

        $age = floor((time() - $recommended['date']) / 86400);

        if ($age <= 0) {
          $status = t('!state as of today.', array('!state' => $state));
        }
        elseif ($age == 1) {
          $status = t('!state since yesterday.', array('!state' => $state));
        }
        else {
          $status = t('!state for !days days.', array('!state' => $state, '!days' => $age));
        }

      }
      else {

        $status = t('!state for an unknown period of time.', array('!state' => $state));

      }

 		if (isset($project['title'])) {
			$name = $project['title'];
		 } else {
			$name = $project['name'];
		 }

      $message['body'][] = '  ' . t('!project : !status', array('!project' => $name, '!status' => $status));

    } // foreach

  }

} // function update_advanced_mail_alter

/**
 * Private sort function to order projects based on status and age.
 *
 * More critical statuses (like security alerts) sort lower/to the top.
 * Within each category, more recently changed projects sort lower.
 *
 * @param a
 *   A project record.
 * @param b
 *   Another project record.
 * @return
 *   Sorting order of (a,b) using standard <0,0,>0 <,=,> coding.
 *
 * @see update_advanced_mail_alter()
 * @see uasort()
 */

function _update_advanced_mail_alter_sort($a, $b) {

  // set all negative statuses (which we should not see because they have
  // to be non-error for the email to get sent in the first place) to sort
  // to the bottom of the list.  The current max valid status is 5.

  $a_status = $a['status'] > 0 ? $a['status'] : 999;
  $b_status = $b['status'] > 0 ? $b['status'] : 999;

  // Roughly figure out # of days since recommended version was released.
  // Use 0 if there is no recommended release for some reason.

  $a_rec = _update_advanced_mail_alter_recommended($a);

  if ($a_rec != NULL) {
    $a_age = floor((time() - $a_rec['date']) / 86400);
  }
  else {
    $a_age = 0;
  }

  $b_rec = _update_advanced_mail_alter_recommended($b);

  if ($b_rec != NULL) {
    $b_age = floor((time() - $b_rec['date']) / 86400);
  }
  else {
    $b_age = 0;
  }

  // Combine so things sort with status levels sorted by age.
  // Note this will break if the update has been around for over a million
  // days.  However, since I expect that I will break well before this
  // happens, you will forgive me for not being too concerned about it.

  $a_status = (1000000 * $a_status) + $a_age;
  $b_status = (1000000 * $b_status) + $b_age;

  return $a_status - $b_status;

} // function _update_advanced_mail_alter__sort

/**
 * Private function that accesses the subarray for the recommended
 * release of a module.
 *
 * @param $project
 *   A project record (generated by the update module).
 *
 * @return
 *   Recommended version subrecord, or NULL if there isn't one.
 */

function _update_advanced_mail_alter_recommended($project) {

  if (isset($project['recommended'])) {
    return $project['releases'][$project['recommended']];
  }
  else {
    return NULL;
  }

} // function _update_advanced_mail_alter_recommended
klonos’s picture

Status: Needs work » Closed (won't fix)

Now that we have Update Status Detailed Email, perhaps we can close this issue here. Either that, or repurpose the issue to merge the functionality of these modules in a single project.

izmeez’s picture

Title: Patch to dev version that appends info about what updates are available to the updates-available email » Better email about available updates

Just updating title of issue for simplicity and clarity with no need to change issue status as another module is identified that solves this.