You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
6.8 KiB
207 lines
6.8 KiB
3 years ago
|
<?php
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
* General hook implementations.
|
||
|
*/
|
||
|
|
||
|
use Drupal\Core\Cache\Cache;
|
||
|
use Drupal\Core\Config\FileStorage;
|
||
|
use Drupal\Core\Config\InstallStorage;
|
||
|
use Drupal\Core\Config\StorageInterface;
|
||
|
use Drupal\Core\Entity\EntityInterface;
|
||
|
use Drupal\Core\Mail\MailFormatHelper;
|
||
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||
|
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||
|
use Drupal\Core\Url;
|
||
|
use Drupal\dgi_fixity\EntityTypeInfo;
|
||
|
use Drupal\dgi_fixity\Form\SettingsForm;
|
||
|
use Drupal\user\Entity\User;
|
||
|
|
||
|
/**
|
||
|
* Implements hook_modules_installed().
|
||
|
*/
|
||
|
function dgi_fixity_modules_installed($modules) {
|
||
|
// Install optional configuration for islandora / action.
|
||
|
if (in_array('islandora_defaults', $modules) || in_array('action', $modules)) {
|
||
|
$optional_install_path = \Drupal::moduleHandler()
|
||
|
->getModule('dgi_fixity')
|
||
|
->getPath() . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
|
||
|
/** @var \Drupal\Core\Config\ConfigInstallerInterface $config_installer */
|
||
|
$config_installer = \Drupal::service('config.installer');
|
||
|
$storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
|
||
|
// This will not overwrite the existing optional configuration if already
|
||
|
// installed.
|
||
|
$config_installer->installOptionalConfig($storage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_mail().
|
||
|
*/
|
||
|
function dgi_fixity_mail($key, &$message, $params) {
|
||
|
switch ($key) {
|
||
|
case 'notify':
|
||
|
$config = \Drupal::config(SettingsForm::CONFIG_NAME);
|
||
|
$last = \Drupal::state()->get(SettingsForm::STATE_LAST_NOTIFICATION);
|
||
|
|
||
|
if ($last !== NULL) {
|
||
|
// If enough time has not elapsed since the last notification do not
|
||
|
// send again.
|
||
|
$threshold = strtotime($config->get(SettingsForm::NOTIFY_USER_THRESHOLD));
|
||
|
if ($last > $threshold) {
|
||
|
$message['send'] = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if the configuration has enabled notifications.
|
||
|
$notify_status = $config->get(SettingsForm::NOTIFY_STATUS);
|
||
|
if ($notify_status === SettingsForm::NOTIFY_STATUS_NEVER) {
|
||
|
$message['send'] = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/** @var \Drupal\dgi_fixity\FixityCheckServiceInterface $fixity */
|
||
|
$fixity = \Drupal::service('dgi_fixity.fixity_check');
|
||
|
$stats = $fixity->stats();
|
||
|
// Only notify if an error has occurred.
|
||
|
if ($notify_status == SettingsForm::NOTIFY_STATUS_ERROR && $stats['failed'] === FALSE) {
|
||
|
$message['send'] = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$now = \Drupal::time()->getRequestTime();
|
||
|
$subject = (new TranslatableMarkup('Fixity Check Report - @now', ['@now' => date(DATE_RFC7231, $now)]))->render();
|
||
|
$body = $fixity->summary($stats);
|
||
|
if ($stats['failed'] !== 0) {
|
||
|
$body[] = (new TranslatableMarkup(
|
||
|
'There are failed checks which require your attention please review the current state of checks <a href="@site">here</a>.',
|
||
|
['@site' => Url::fromRoute('entity.fixity_check.collection', [], ['absolute' => TRUE])->toString()]
|
||
|
))->render();
|
||
|
}
|
||
|
|
||
|
$message['subject'] = $subject;
|
||
|
foreach ($body as $line) {
|
||
|
$message['body'][] = MailFormatHelper::htmlToText($line);
|
||
|
}
|
||
|
|
||
|
// Track when the last message was sent.
|
||
|
\Drupal::state()->set(SettingsForm::STATE_LAST_NOTIFICATION, $now);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_cron().
|
||
|
*/
|
||
|
function dgi_fixity_cron() {
|
||
|
$queued = \Drupal::time()->getRequestTime();
|
||
|
$settings = \Drupal::config(SettingsForm::CONFIG_NAME);
|
||
|
$threshold = strtotime($settings->get(SettingsForm::THRESHOLD));
|
||
|
$sources = $settings->get(SettingsForm::SOURCES);
|
||
|
|
||
|
// Update enabled periodic checks.
|
||
|
$queue = \Drupal::queue('dgi_fixity.process_source');
|
||
|
foreach ($sources as $source) {
|
||
|
// It safe to have queue processing a source multiple times,
|
||
|
// they will steal work from each other but will not conflict.
|
||
|
$queue->createItem($source);
|
||
|
}
|
||
|
|
||
|
/** @var \Drupal\dgi_fixity\FixityCheckStorageInterface $storage */
|
||
|
$storage = \Drupal::entityTypeManager()->getStorage('fixity_check');
|
||
|
|
||
|
// Queue items that exceed the current threshold.
|
||
|
$storage->queue($queued, $threshold, 100);
|
||
|
|
||
|
// Dequeued items after 6 hours assuming the check has failed.
|
||
|
// They will be re-queued if appropriate on the next cron run.
|
||
|
$storage->dequeue($queued - (3600 * 6));
|
||
|
|
||
|
// Send notification if appropriate.
|
||
|
$uid = $settings->get(SettingsForm::NOTIFY_USER);
|
||
|
$user = User::load($uid);
|
||
|
if ($user) {
|
||
|
\Drupal::service('plugin.manager.mail')->mail('dgi_fixity', 'notify', $user->getEmail(), $user->getPreferredAdminLangcode(TRUE));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_entity_type_alter().
|
||
|
*/
|
||
|
function dgi_fixity_entity_type_alter(array &$entity_types) {
|
||
|
return \Drupal::service('class_resolver')
|
||
|
->getInstanceFromDefinition(EntityTypeInfo::class)
|
||
|
->entityTypeAlter($entity_types);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_entity_operation().
|
||
|
*/
|
||
|
function dgi_fixity_entity_operation(EntityInterface $entity) {
|
||
|
return \Drupal::service('class_resolver')
|
||
|
->getInstanceFromDefinition(EntityTypeInfo::class)
|
||
|
->entityOperation($entity);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_ENTITY_TYPE_insert().
|
||
|
*/
|
||
|
function dgi_fixity_file_insert(EntityInterface $entity) {
|
||
|
// Make sure the fixity_check table contains a row for every file.
|
||
|
\Drupal::entityTypeManager()
|
||
|
->getStorage('fixity_check')
|
||
|
->create([
|
||
|
'file' => $entity->id(),
|
||
|
])
|
||
|
->save();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_ENTITY_TYPE_delete().
|
||
|
*/
|
||
|
function dgi_fixity_file_delete(EntityInterface $entity) {
|
||
|
/** @var \Drupal\dgi_fixity\FixityCheckStorageInterface $storage */
|
||
|
$storage = \Drupal::entityTypeManager()->getStorage('fixity_check');
|
||
|
$checks = $storage->loadByProperties([
|
||
|
'file' => $entity->id(),
|
||
|
]);
|
||
|
// Remove checks for non-existent files.
|
||
|
$storage->delete($checks);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_ENTITY_TYPE_revision_create().
|
||
|
*/
|
||
|
function dgi_fixity_fixity_check_revision_create(EntityInterface $entity) {
|
||
|
Cache::invalidateTags([
|
||
|
'fixity_check:' . $entity->id() . ':revisions_list',
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_ENTITY_TYPE_revision_delete().
|
||
|
*/
|
||
|
function dgi_fixity_fixity_check_revision_delete(EntityInterface $entity) {
|
||
|
Cache::invalidateTags([
|
||
|
'fixity_check:' . $entity->id() . ':revisions_list',
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_help().
|
||
|
*/
|
||
|
function dgi_fixity_help($route_name, RouteMatchInterface $route_match) {
|
||
|
switch ($route_name) {
|
||
|
case 'help.page.dgi_fixity':
|
||
|
case 'dgi_fixity.settings':
|
||
|
$output = array_fill(0, 2, ['#type' => 'html_tag', '#tag' => 'p']);
|
||
|
$output[0]['#value'] = new TranslatableMarkup(
|
||
|
'The Fixity module validates selected files by generating hashes and comparing it against stored values produced by the <a href="@file_hash">File Hash module</a> for selected files uploaded to the site.',
|
||
|
['@file_hash' => URL::fromRoute('help.page', ['name' => 'filehash'])->toString()],
|
||
|
);
|
||
|
return $output;
|
||
|
}
|
||
|
}
|