You are here

user_revision.module in User Revision 7

Same filename and directory in other branches
  1. 8 user_revision.module
  2. 7.2 user_revision.module

Enables user revision.

File

user_revision.module
View source
<?php

/**
 * @file
 * Enables user revision.
 */

// Count of accounts that will be processed per batch iteration.
define('USER_REVISION_BATCH_USERS_LIMIT', 100);

/**
 * Implements hook_views_api().
 */
function user_revision_views_api() {
  return array(
    'api' => '3.0-alpha1',
    'path' => drupal_get_path('module', 'user_revision') . '/views',
  );
}

/**
 * Implements hook_menu().
 */
function user_revision_menu() {
  $items['user/%user/revisions'] = array(
    'title' => 'Revisions',
    'page callback' => 'user_revision_overview',
    'page arguments' => array(
      1,
    ),
    'access callback' => '_user_revision_access',
    'access arguments' => array(
      1,
      array(
        'view user revisions',
        'view own user revisions',
      ),
    ),
    'weight' => 2,
    'type' => MENU_LOCAL_TASK,
    'file' => 'user_revision.pages.inc',
  );
  $items['user/%user/revisions/%/view'] = array(
    'title' => 'Revisions',
    'page callback' => 'user_revision_show',
    'page arguments' => array(
      1,
      3,
    ),
    'access callback' => '_user_revision_access',
    'access arguments' => array(
      1,
      array(
        'view user revisions',
        'view own user revisions',
      ),
    ),
  );
  $items['user/%user_revision/revisions/%/revert'] = array(
    'title' => 'Revert to earlier revision',
    'load arguments' => array(
      3,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'user_revision_revert_confirm',
      1,
    ),
    'access callback' => '_user_revision_access',
    'access arguments' => array(
      1,
      array(
        'revert user revisions',
        'revert own user revisions',
      ),
    ),
    'file' => 'user_revision.pages.inc',
  );
  $items['user/%user_revision/revisions/%/delete'] = array(
    'title' => 'Delete earlier revision',
    'load arguments' => array(
      3,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'user_revision_delete_confirm',
      1,
    ),
    'access callback' => '_user_revision_access',
    'access arguments' => array(
      1,
      array(
        'delete user revisions',
        'delete own user revisions',
      ),
    ),
    'file' => 'user_revision.pages.inc',
  );
  $items['admin/config/people/revisions'] = array(
    'title' => 'Revision settings',
    'description' => 'Configure revision settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'user_revision_admin_settings',
    ),
    'access arguments' => array(
      'view user revisions',
    ),
    'file' => 'user_revision.admin.inc',
    'weight' => 10,
  );
  return $items;
}

/**
 * Access callback.
 */
function _user_revision_access($u, $perm) {
  global $user;
  if (!is_array($perm)) {
    $perm = array(
      $perm,
    );
  }
  $access = FALSE;
  foreach ($perm as $permission) {
    if ($u->uid == $user->uid) {
      $access = user_access($permission) || $access;
    }
    elseif (strpos($permission, 'own') === FALSE) {
      $access = user_access($permission) || $access;
    }
  }
  $count = db_select('user_revision', 'ur')
    ->condition('ur.uid', $u->uid)
    ->countQuery()
    ->execute()
    ->fetchField();
  return $access && $count > 1;
}

/**
 * Implements hook_permission().
 */
function user_revision_permission() {
  return array(
    'view user revisions' => array(
      'title' => t('View revisions'),
      'restrict access' => TRUE,
    ),
    'revert user revisions' => array(
      'title' => t('Revert revisions'),
      'restrict access' => TRUE,
    ),
    'delete user revisions' => array(
      'title' => t('Delete revisions'),
    ),
    'choose user revisions' => array(
      'title' => t('Choose to create revisions'),
      'description' => t('Allow users to create user revisions'),
    ),
    'view own user revisions' => array(
      'title' => t('View own revisions'),
      'description' => t('Allow users to view their own user revisions'),
    ),
    'revert own user revisions' => array(
      'title' => t('Revert own revisions'),
      'description' => t('Allow users to revert their own user revisions'),
    ),
    'delete own user revisions' => array(
      'title' => t('Delete own revisions'),
      'description' => t('Allow users to delete their own user revisions'),
    ),
  );
}

/**
 * Implements hook_admin_paths().
 */
function user_revision_admin_paths() {
  if (variable_get('node_admin_theme')) {
    $paths = array(
      'user/*/revisions' => TRUE,
      'user/*/revisions/*/revert' => TRUE,
      'user/*/revisions/*/delete' => TRUE,
    );
    return $paths;
  }
}

/**
 * Controller class for user_revision.
 *
 * This extends the UserController class, adding required
 * revision handling for user objects.
 */
class UserRevisionController extends UserController {

  /**
   * {@inheritdoc}
   */
  function attachLoad(&$queried_users, $revision_id = FALSE) {
    parent::attachLoad($queried_users, $revision_id);
    foreach ($queried_users as $key => $record) {
      $queried_users[$key]->revision = 1;
    }
  }

  /**
   * {@inheritdoc}
   */
  function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
    $query = parent::buildQuery($ids, $conditions, $revision_id);
    $fields =& $query
      ->getFields();
    unset($fields['timestamp']);
    $query
      ->addField('revision', 'timestamp', 'revision_timestamp');
    $query
      ->addField('revision', 'authorid', 'revision_uid');
    $fields['uid']['table'] = 'base';
    return $query;
  }

}

/**
 * Implements hook_schema_alter().
 */
function user_revision_schema_alter(&$schema) {
  $schema['users']['fields']['vid'] = array(
    'description' => 'The current {user_revision}.vid version identifier.',
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  );
  $schema['users']['fields']['ip'] = array(
    'description' => 'The users\'s ip address',
    'type' => 'varchar',
    'length' => 256,
    'not null' => TRUE,
    'default' => '',
  );
  $schema['users']['foreign keys']['user_revision'] = array(
    'table' => 'user_revision',
    'columns' => array(
      'vid' => 'vid',
    ),
  );
  $schema['users']['unique keys']['vid'] = array(
    'vid',
  );
}

/**
 * Implements hook_entity_info_alter().
 */
function user_revision_entity_info_alter(&$entity_info) {
  module_load_install('user_revision');
  $entity_info['user']['revision table'] = 'user_revision';
  $entity_info['user']['entity keys']['revision'] = 'vid';
  $entity_info['user']['controller class'] = 'UserRevisionController';
  $schema = user_revision_schema();
  foreach ($schema['user_revision']['fields'] as $k => $field) {
    $entity_info['user']['schema_fields_sql']['revision table'][] = $k;
  }
}

/**
 * Implements hook_entity_property_info_alter().
 */
function user_revision_entity_property_info_alter(&$info) {
  $info['user']['properties']['vid'] = array(
    'label' => t('Revision ID'),
    'type' => 'integer',
    'description' => t('The unique ID of the user\'s revision.'),
    'schema field' => 'vid',
  );
  $info['user']['properties']['ip'] = array(
    'label' => t('IP'),
    'type' => 'text',
    'description' => t('The user\'s ip address.'),
    'schema field' => 'ip',
  );
}

/**
 * Implements hook_form_alter().
 */
function user_revision_form_user_register_form_alter(&$form, &$form_state, $form_id) {
  $form['vid'] = array(
    '#type' => 'value',
    '#value' => NULL,
  );
  $form['revision'] = array(
    '#type' => 'value',
    '#value' => TRUE,
  );
}

/**
] * Implements hook_form_alter().
*/
function user_revision_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
  $account = $form_state['user'];
  $form['revision_information'] = array(
    '#type' => 'fieldset',
    '#title' => t('Revision information'),
    '#collapsible' => FALSE,
    '#attributes' => array(
      'class' => array(
        'user-profile-form-revision-information',
      ),
    ),
    '#weight' => 20,
    '#access' => user_access('choose user revisions'),
  );
  $form['revision_information']['revision'] = array(
    '#type' => 'checkbox',
    '#title' => t('Create new revision'),
    '#default_value' => variable_get('user_revision_by_default', 1),
    '#states' => array(
      'invisible' => array(
        'input[name="revision"]' => array(
          'checked' => TRUE,
        ),
      ),
    ),
  );
  $form['revision_information']['log'] = array(
    '#type' => 'textarea',
    '#title' => t('Revision log message'),
    '#rows' => 4,
    '#description' => t('Provide an explanation of the changes you are making. This will help other authors understand your motivations.'),
  );
  $form['revision_information']['log']['#states'] = array(
    'invisible' => array(
      'input[name="revision"]' => array(
        'checked' => FALSE,
      ),
    ),
  );
  $form['#submit'][] = 'user_revision_user_profile_form_submit';
  $form['vid'] = array(
    '#type' => 'value',
    '#value' => isset($account->vid) ? $account->vid : NULL,
  );
  $form['ip'] = array(
    '#type' => 'value',
    '#value' => ip_address(),
  );
}

/**
 * Submit function for the user account and profile editing form.
 */
function user_revision_user_profile_form_submit($form, &$form_state) {
  $form_state['user']->revision = $form_state['values']['revision'];
  $form_state['user']->log = $form_state['values']['log'];
  $form_state['user']->ip = $form_state['values']['ip'];
}

/**
 * Show a revision.
 */
function user_revision_show($user, $vid) {
  $account = user_revision_load($user->uid, $vid);
  drupal_set_title(t('Revision of %title from %date', array(
    '%title' => $user->name,
    '%date' => format_date($account->revision_timestamp),
  )), PASS_THROUGH);
  return user_view_page($account, 'full');
}

/**
 * Load a revision.
 *
 * Loads a user object with revision support
 */
function user_revision_load($uid, $vid = NULL, $reset = FALSE) {
  if (isset($vid)) {
    $conditions = isset($vid) ? array(
      'vid' => $vid,
    ) : array();
    $users = user_load_multiple(array(
      $uid,
    ), $conditions, $reset);
    foreach ($users as $key => $user) {
      $fid = db_select('user_revision', 'ur')
        ->condition('ur.vid', $vid)
        ->fields('ur', array(
        'picture',
      ))
        ->execute()
        ->fetchField();
      if ($fid) {
        $file = new stdClass();
        $file->fid = $fid;
        $users[$key]->picture = file_load($file->fid);
      }
    }
    return reset($users);
  }
}

/**
 * Implements hook_user_insert().
 */
function user_revision_user_insert(&$edit, $account, $category) {
  db_update('user_revision')
    ->condition('vid', $account->vid)
    ->fields(array(
    'uid' => $account->uid,
  ))
    ->execute();
}

/**
 * Implements hook_user_presave().
 */
function user_revision_user_presave(&$edit, $account, $category) {
  global $user;
  $edit['log'] = empty($edit['log']) ? '' : $edit['log'];
  $edit = array_merge((array) $account, $edit);
  $edit['timestamp'] = REQUEST_TIME;
  $edit['authorid'] = $user->uid;

  // Loading the old hashed password again.
  if (empty($edit['pass']) && !empty($edit['original']->pass)) {
    $edit['pass'] = $edit['original']->pass;
  }

  // Allow this module to be extended.
  $custom_fields = _user_revision_get_custom_fields($edit);
  foreach ($custom_fields as $field => $value) {
    $edit[$field] = $value;
  }
  $edit = array_merge((array) $custom_fields, $edit);
  if (isset($edit['revision']) && $edit['revision'] == 1 || $account->is_new || !isset($edit['revision']) && variable_get('user_revision_by_default', 1)) {
    if (isset($edit['vid'])) {
      $edit['old_vid'] = $edit['vid'];
      unset($edit['vid']);
    }
    _user_save_revision($edit);
  }
  else {
    _user_save_revision($edit, array(
      'vid',
    ));
  }
}

/**
 * Adds a hook_user_revision_custom_fields() function.
 */
function _user_revision_get_custom_fields($edit = NULL) {
  $custom_fields = array();
  foreach (module_implements('user_revision_custom_fields') as $module) {
    $invoke = module_invoke($module, 'user_revision_custom_fields', $edit);
    $custom_fields = array_merge($invoke, $custom_fields);
  }
  return $custom_fields;
}

/**
 * Implements hook_user_delete().
 */
function user_revision_user_delete($account) {
  $revisions = db_select('user_revision', 'ur')
    ->condition('ur.uid', $account->uid)
    ->fields('ur', array(
    'vid',
  ))
    ->execute()
    ->fetchCol();
  foreach ($revisions as $revision_id) {
    $revision = user_revision_load($account->uid, $revision_id);
    user_revision_delete($revision);
  }
}

/**
 * Save record to the database.
 */
function _user_save_revision(&$edit, $update = NULL) {
  $picture = NULL;
  if (isset($edit['picture']) && is_object($edit['picture'])) {
    $picture = $edit['picture'];
    $edit['picture'] = $picture->fid;
  }

  // Add timestamp and author.
  if (isset($update)) {
    drupal_write_record('user_revision', $edit, $update);
  }
  else {
    drupal_write_record('user_revision', $edit);
  }
  if (is_object($picture)) {
    file_usage_add($picture, 'user_revision', 'user', $edit['vid']);
    $edit['picture'] = $picture;
  }

  // Pass new vid to user_save?
}

/**
 * Return a list of all the existing revision numbers.
 */
function user_revision_list($user) {
  $revisions = array();
  $result = db_select('user_revision', 'ur')
    ->fields('ur', array(
    'vid',
    'log',
    'authorid',
    'ip',
    'timestamp',
  ));
  $user_alias = $result
    ->leftJoin('users', 'u', "%alias.vid = ur.vid");
  $user_alias2 = $result
    ->leftJoin('users', 'u2', "%alias.uid = ur.authorid");
  $result
    ->addField($user_alias, 'vid', 'current_vid');
  $result
    ->addField($user_alias2, 'name', 'current_name');
  $result
    ->fields($user_alias2, array(
    'uid',
    'name',
  ));
  $result = $result
    ->condition('ur.uid', $user->uid)
    ->orderBy('ur.vid', 'DESC')
    ->execute()
    ->fetchAll();
  foreach ($result as $revision) {
    $revisions[$revision->vid] = $revision;
  }
  return $revisions;
}

/**
 * Delete a user revision.
 *
 * @param object $revision
 *   The revision to delete, should have at least uid and vid.
 */
function user_revision_delete($revision) {
  db_delete('user_revision')
    ->condition('uid', $revision->uid)
    ->condition('vid', $revision->vid)
    ->execute();
  module_invoke_all('user_revision_delete', $revision);
  field_attach_delete_revision('user', $revision);
  return TRUE;
}

/**
 * Implements hook_ctools_plugin_directory().
 */
function user_revision_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'ctools') {
    return 'plugins/' . $plugin_type;
  }
  if ($owner == 'page_manager') {
    return 'plugins/' . $plugin_type;
  }
}

Functions

Constants

Classes

Namesort descending Description
UserRevisionController Controller class for user_revision.