content_lock_timeout.module in Content locking (anti-concurrent editing) 8
Same filename and directory in other branches
- 8.2 modules/content_lock_timeout/content_lock_timeout.module
- 6.2 modules/content_lock_timeout/content_lock_timeout.module
- 6 modules/content_lock_timeout/content_lock_timeout.module
- 7.3 modules/content_lock_timeout/content_lock_timeout.module
- 7 modules/content_lock_timeout/content_lock_timeout.module
- 7.2 modules/content_lock_timeout/content_lock_timeout.module
Allowed time-based automatic unlocking of nodes.
File
modules/content_lock_timeout/content_lock_timeout.moduleView source
<?php
/**
* @file
* Allowed time-based automatic unlocking of nodes.
*/
use Drupal\Core\Session\SessionManager;
use Drupal\node\NodeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\Entity\User;
use Drupal\Core\Entity\EntityInterface;
use Drupal\taxonomy\TermInterface;
use Drupal\block_content\BlockContentInterface;
/**
* Implements hook_cron().
*
* Breaks batches of stale locks whenever the cron hooks are
* run. Inspired by original content_lock_cron() (leftover from the
* checkout module).
*/
function content_lock_timeout_cron() {
$config = \Drupal::config('content_lock_timeout.settings');
$timeout_minutes = $config
->get('content_lock_timeout_minutes');
$last_valid_time = Drupal::time()
->getCurrentTime() - 60 * $timeout_minutes;
/** @var \Drupal\content_lock\ContentLock\ContentLock $lock_service */
$lock_service = \Drupal::service('content_lock');
// We call release() for each lock so that the
// hook_content_lock_released may be invoked.
$query = \Drupal::database()
->select('content_lock', 'c');
$query
->fields('c')
->condition('c.timestamp', $last_valid_time, '<');
$count = 0;
foreach ($query
->execute() as $obj) {
$lock_service
->release($obj->entity_id, $obj->langcode, $obj->form_op, $obj->uid, $obj->entity_type);
$count++;
}
if ($count) {
$period = \Drupal::service('date.formatter')
->formatInterval($timeout_minutes * 60);
\Drupal::logger('content_lock_timeout')
->notice('Released @count stale node locks which lasted at least @period.', [
'@count' => $count,
'@period' => $period,
]);
}
}
/**
* Implements hook_entity_prepare_form().
*/
function content_lock_timeout_entity_prepare_form(EntityInterface $entity, $operation, FormStateInterface $form_state) {
// We support entity type Node, Term and Block Content.
if ($entity instanceof NodeInterface || $entity instanceof TermInterface || $entity instanceof BlockContentInterface) {
$user = \Drupal::currentUser();
$config = \Drupal::config('content_lock_timeout.settings');
if (!$config
->get('content_lock_timeout_on_edit')) {
return;
}
$timeout_minutes = $config
->get('content_lock_timeout_minutes');
$last_valid_time = Drupal::time()
->getCurrentTime() - 60 * $timeout_minutes;
/** @var \Drupal\content_lock\ContentLock\ContentLock $lock_service */
$lock_service = \Drupal::service('content_lock');
// This is a new, unsaved entity (which thus can't be locked).
// This is a stale lock.
// There already is a lock on this entity.
// A different user owns the lock.
// There is already a lock on this entity.
if (!empty($entity
->id()) && is_object($lock = $lock_service
->fetchLock($entity
->id(), $entity
->language()
->getId(), $operation, $entity
->getEntityTypeId())) && $lock->uid != $user
->id() && $lock->timestamp < $last_valid_time && $user
->hasPermission('break content lock') && $user
->id() > 0) {
$lock_service
->release($entity
->id(), $entity
->language()
->getId(), $operation, $lock->uid, $entity
->getEntityTypeId());
if ($lock_service
->verbose()) {
$username = User::load($lock->uid)
->getDisplayName();
$date = \Drupal::service('date.formatter')
->formatInterval(REQUEST_TIME - $lock->timestamp);
$stale_time = \Drupal::service('date.formatter')
->formatInterval($last_valid_time - $lock->timestamp);
\Drupal::messenger()
->addStatus(t('Breaking existing lock by @name so that you may edit this node. (This lock was set @date ago and was stale since @stale_time.)', [
'@name' => $username,
'@date' => $date,
'@stale_time' => $stale_time,
]));
}
}
}
}
/**
* Implements hook_user_logout().
*/
function content_lock_timeout_user_logout($account) {
/** @var \Drupal\Core\Session\AccountInterface $account */
// Only remove locks if there is a timeout given.
$config = \Drupal::config('content_lock_timeout.settings');
$timeout_minutes = $config
->get('content_lock_timeout_minutes');
if ($timeout_minutes == 0) {
return;
}
// Only do the database check if the original drupal session manager is used.
// Otherwise its not sure if sessions table has correct data. As it would be
// possible to extend the Class, instanceof is not used here!
if (get_class(Drupal::service('session_manager')) == SessionManager::class) {
$query = \Drupal::database()
->select('sessions');
$query
->condition('uid', $account
->id());
$query = $query
->countQuery();
$session_count = (int) $query
->execute()
->fetchField();
}
else {
$session_count = FALSE;
}
// Only remove all locks of user if its the last session of the user.
if ($session_count === 1) {
/** @var \Drupal\content_lock\ContentLock\ContentLock $lock_service */
$lock_service = \Drupal::service('content_lock');
$lock_service
->releaseAllUserLocks($account
->id());
}
}
Functions
Name | Description |
---|---|
content_lock_timeout_cron | Implements hook_cron(). |
content_lock_timeout_entity_prepare_form | Implements hook_entity_prepare_form(). |
content_lock_timeout_user_logout | Implements hook_user_logout(). |