You are here

edit_limit.module in Edit Limit 6

Same filename and directory in other branches
  1. 7 edit_limit.module

edit_limit.module Primary module file for Edit Limit. This contains all the hooks needed to run the module.

File

edit_limit.module
View source
<?php

/**
 * @file edit_limit.module
 * Primary module file for Edit Limit. This contains all the hooks needed to 
 * run the module.
 */
define('EDIT_LIMIT_NODE_COUNT_DEFAULT', 3);
define('EDIT_LIMIT_COMMENT_COUNT', 3);
define('EDIT_LIMIT_NODE_TIME_DEFAULT', 86400);

// in seconds, 1 day
define('EDIT_LIMIT_COMMENT_TIME', 300);

// in seconds, 5 minutes

/**
 * Implementation of hook_menu().
 */
function edit_limit_menu() {
  $items['admin/content/edit_limit'] = array(
    'title' => 'Edit Limit',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'edit_limit_settings',
    ),
    'access arguments' => array(
      'administer edit limit',
    ),
    'file' => 'edit_limit.admin.inc',
  );
  return $items;
}
function edit_limit_perm() {
  return array(
    'bypass edit limit',
    'administer edit limit',
  );
}

/**
 * Implement hook_menu_alter().
 *
 * This allows additional checks to be made for granting access checks. For instance,
 * the node menu items use node_access() to grant permissions to edit nodes, but we
 * want to not only check that, but also check to see if the user is allowed to continue
 * making edits.
 */
function edit_limit_menu_alter(&$items) {

  // node_access() overrides
  $items['node/%node/edit']['access callback'] = 'edit_limit_node_access';

  // Override comment edit access checks
  $items['comment/edit']['access callback'] = 'edit_limit_comment_access';
}

/**
 * Helper function to determine if the user has permissions to use whatever grants node_access()
 * grants to this user, as determined by the additional site membership checks.
 */
function edit_limit_node_access($op, $node, $account = NULL) {
  module_load_include('inc', 'node', 'node.pages');
  if (node_access($op, $node, $account)) {
    switch ($op) {
      case 'update':
        if (user_access('bypass edit limit')) {
          return TRUE;
        }
        return _edit_limit_user_acccess($node);
    }
  }
  return FALSE;
}

/**
 * Helper function to perform additional access checks after node_access() has been checked.
 */
function _edit_limit_user_acccess($node) {

  // Be liberal here. The user has already passed node_access() by this point.
  $return = TRUE;

  // If this is a new node, let it go.
  if (empty($node->nid)) {
    return $return;
  }

  // Only limit edits if the content type is in the list.
  $allowed_types = variable_get('edit_limit_node_types', array());
  if (empty($allowed_types[$node->type])) {
    return $return;
  }

  // Get the time limit settings
  $edit_limit_node_time_enabled = variable_get('edit_limit_node_time_enabled', FALSE);
  $time_limits['default'] = intval(variable_get('edit_limit_node_time_default', 10)) * 24 * 60 * 60;
  $time_limits['node'][$node->type] = intval(variable_get('edit_limit_node_time_' . $node->type, $time_limits['default']));

  // Get the edit count limit settings
  $edit_limit_node_count_enabled = variable_get('edit_limit_node_count_enabled', FALSE);
  $count_limits['default'] = intval(variable_get('edit_limit_node_count_default', EDIT_LIMIT_NODE_COUNT_DEFAULT));
  $count_limits['node'][$node->type] = intval(variable_get('edit_limit_node_count_' . $node->type, $count_limits['default']));

  // If no options are enabled, we're done.
  if (!$edit_limit_node_time_enabled && !$edit_limit_node_count_enabled) {
    return $return;
  }

  // Test that the node hasn't been edited more than the allowed number of times.
  $count_limit_reached == FALSE;
  if ($edit_limit_node_count_enabled && $return) {
    $edit_count = edit_limit_node_count($node->nid);
    $count_limit = $count_limits['node'][$node->type] ? $count_limits['node'][$node->type] : $count_limits['node']['default'];
    if ($count_limit <= $edit_count) {
      $return = FALSE;
      $count_limit_reached = TRUE;
    }
  }

  // Test that the node was not created longer ago than the allowed time limit.
  if ($edit_limit_node_time_enabled && $return) {
    $timeleft = intval($node->created) + intval(variable_get('edit_limit_node_time_default', EDIT_LIMIT_NODE_TIME_DEFAULT)) - time();
    if ($timeleft <= 0) {
      $time_limit_reached = TRUE;
      $return = FALSE;
    }
    elseif (!$count_limit_reached && arg(0) == 'node' && arg(2) == 'edit') {
      static $type;
      if (empty($type)) {
        $type = 'status';
        drupal_add_js(drupal_get_path('module', 'edit_limit') . '/edit_limit.js');
        drupal_set_message(t('You have !seconds seconds left to edit this content.', array(
          '!seconds' => $timeleft,
        )), $type, FALSE);
      }
    }
  }
  return $return;
}

/**
 * Access check function to see if the user can still edit the comment or not.
 * It must, at minimum, perform the comment module's access checks first.
 */
function edit_limit_comment_access() {
  if (user_access('post comments')) {
    if (user_access('bypass edit limit')) {
      return TRUE;
    }
    $return = TRUE;
    if (variable_get('edit_limit_comment_time_enabled', FALSE)) {

      // By this point, we want to return false if the time has passed.
      $cid = intval(arg(2));
      $timestamp = db_result(db_query("SELECT timestamp FROM {comments} WHERE cid=%d", $cid));
      if ($timestamp + intval(variable_get('edit_limit_comment_time', EDIT_LIMIT_COMMENT_TIME)) < time()) {
        $return = FALSE;
      }
      else {
        static $seconds;
        if (empty($seconds)) {
          drupal_add_js(drupal_get_path('module', 'edit_limit') . '/edit_limit.js');
          $seconds = $timestamp + intval(variable_get('edit_limit_comment_time', EDIT_LIMIT_COMMENT_TIME)) - time();
        }
        $type = 'status';
        drupal_set_message(t('You have !seconds seconds left to edit this comment.', array(
          '!seconds' => $seconds,
        )), $type, FALSE);
      }
    }
    return $return;
  }
  return FALSE;
}

/**
 * Implementation of hook_nodeapi().
 */
function edit_limit_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

  // On update, ignore users with 'bypass edit limit' when updating the edit
  // count. We don't want to penalize other users. Also, we'll skip this if
  // the edit count setting is disabled, for the same reason.
  $allowed_types = variable_get('edit_limit_node_types', array());
  if (!user_access('bypass edit limit') && !empty($allowed_types[$node->type])) {
    if ($op == 'update') {
      if (variable_get('edit_limit_node_count_enabled', FALSE)) {

        // Update the count of edit limits.
        $count_data = db_fetch_array(db_query("SELECT * FROM {edit_limit_node_count} WHERE nid=%d", $node->nid));
        $edit_count = 0;
        $update = array();
        if (!empty($count_data)) {
          $edit_count = $count_data['count'];
          $update = array(
            'nid',
          );
        }
        $edit_count++;
        $data = array(
          'nid' => $node->nid,
          'count' => $edit_count,
        );
        drupal_write_record('edit_limit_node_count', $data, $update);
      }
    }

    // On prepare, compare the number of times a node has been edited to the limit,
    // and set a message for the user to let them know how many edits are left, if any.
    if ($op == 'prepare' && !empty($node->nid)) {
      if (variable_get('edit_limit_node_count_enabled', FALSE)) {
        $limit = variable_get('edit_limit_node_count_default', EDIT_LIMIT_NODE_COUNT_DEFAULT);
        $count = edit_limit_node_count($node->nid);

        // If the edit count is getting close to the limit, make this a warning instead of a simple status
        $type = $count + 2 > $limit ? 'warning' : 'status';
        drupal_set_message("This node has been edit {$count} out of {$limit} times, after which it will be locked.", $type);
      }
    }
  }
}

/**
 * Helper function to get the number of times a particular node
 * has been edited.
 */
function edit_limit_node_count($nid) {
  $count = db_result(db_query("SELECT count FROM {edit_limit_node_count} WHERE nid=%d", $nid));
  $count = empty($count) ? 0 : $count;
  return $count;
}

/**
 * Implementation of hook_link_alter().
 * This removes comment edit links if the comment is no longer editable.
 */
function edit_limit_link_alter(&$links, $node, $comment = NULL) {
  if (!empty($links['comment_edit'])) {

    // Allow edit links if the edit count hasn't been reached yet.
    // TODO: Complete this functionality.
    if (0) {
      $results = db_query("SELECT * FROM {edit_limit_comment_time} WHERE cid=%d", $comment->cid);
    }

    // Allow edit links if there is enough time left based on the system variable edit_limit_comment_time.
    // We don't have to do much user access checking, since this link will only exist if the user passed
    // the comment_access() check for this given comment.
    if (!user_access('bypass edit limit') && variable_get('edit_limit_comment_time_enabled', FALSE)) {
      $time_limit = $comment->timestamp + intval(variable_get('edit_limit_comment_time', EDIT_LIMIT_COMMENT_TIME));

      // If too much time has passed, destroy the link.
      if ($time_limit < time()) {
        unset($links['comment_edit']);
      }
      else {

        // Add the javascript that will handle the countdown.
        drupal_add_js(drupal_get_path('module', 'edit_limit') . '/edit_limit.js');

        // Modify the link to add the remaining seconds (only users that can't pass 'bypass edit limit' get this far).
        $links['comment_edit']['title'] .= ' (' . ($time_limit - time()) . ' seconds left)';
      }
    }
  }
}

Functions

Namesort descending Description
edit_limit_comment_access Access check function to see if the user can still edit the comment or not. It must, at minimum, perform the comment module's access checks first.
edit_limit_link_alter Implementation of hook_link_alter(). This removes comment edit links if the comment is no longer editable.
edit_limit_menu Implementation of hook_menu().
edit_limit_menu_alter Implement hook_menu_alter().
edit_limit_nodeapi Implementation of hook_nodeapi().
edit_limit_node_access Helper function to determine if the user has permissions to use whatever grants node_access() grants to this user, as determined by the additional site membership checks.
edit_limit_node_count Helper function to get the number of times a particular node has been edited.
edit_limit_perm
_edit_limit_user_acccess Helper function to perform additional access checks after node_access() has been checked.

Constants

Namesort descending Description
EDIT_LIMIT_COMMENT_COUNT
EDIT_LIMIT_COMMENT_TIME
EDIT_LIMIT_NODE_COUNT_DEFAULT @file edit_limit.module Primary module file for Edit Limit. This contains all the hooks needed to run the module.
EDIT_LIMIT_NODE_TIME_DEFAULT