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 here.', ['@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 File Hash module for selected files uploaded to the site.', ['@file_hash' => URL::fromRoute('help.page', ['name' => 'filehash'])->toString()], ); return $output; } }