Skip to content
Snippets Groups Projects
Commit 2ce65153 authored by Paul Mrvik's avatar Paul Mrvik
Browse files

Issue #3472492 by globexplorer: New Feature: Send notification including offset (Cron job)

parent 17dad8a4
No related branches found
No related tags found
No related merge requests found
Showing
with 993 additions and 105 deletions
......@@ -27,3 +27,7 @@ Current maintainers for Drupal 10:
- PAUL MRVIK (globexplorer) - https://www.drupal.org/u/globexplorer
## DOCUMENTATION
You can extend the modules way to get recipients for th
......@@ -4,3 +4,19 @@
* @file
* Install, update and uninstall functions for the Conditional Notification module.
*/
/**
* Adds new entity
* conditional_notification_log.
*/
function conditional_notification_update_10001() {
$entity_type_definition = \Drupal::service('entity_type.manager')->getDefinition('conditional_notification_log');
\Drupal::entityDefinitionUpdateManager()->installEntityType($entity_type_definition);
}
......@@ -7,11 +7,13 @@
use Drupal\conditional_notification\EntityTypeInfo;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Core\Datetime\DrupalDateTime;
/**
* Implements hook_entity_type_alter().
......@@ -27,19 +29,12 @@ function conditional_notification_entity_type_alter(array &$entity_types) {
if ($entity_bundle_of = $entity_type->getBundleOf()) {
if ($helper_service->isEntityTypeSupportedByEntityTypeId($entity_bundle_of) && $entity_type->hasLinkTemplate('edit-form')) {
$entity_type->setLinkTemplate('conditional-notification-default-templates', $entity_type->getLinkTemplate('edit-form') . "/conditional-notification");
}
}
if ($entity_type->hasLinkTemplate('canonical') || $entity_type->hasLinkTemplate('edit-form') && !$entity_type->getBundleOf()) {
if ($entity_type instanceof Drupal\Core\Entity\ContentEntityType) {
$entity_type->setLinkTemplate('conditional-notification-templates', $entity_type->getLinkTemplate('canonical') . "/conditional-notification");
}
}
}
if ($helper_service->isEntityTypeSupportedByEntityTypeId($entity_type->id()) && ($entity_type->hasLinkTemplate('canonical') || $entity_type->hasLinkTemplate('edit-form')) && !$entity_type->getBundleOf()) {
$entity_type->setLinkTemplate('conditional-notification-templates', $entity_type->getLinkTemplate('canonical') . "/conditional-notification");
}
}
}
......@@ -65,12 +60,13 @@ function conditional_notification_entity_operation(EntityInterface $entity) {
}
if ($entity->hasLinkTemplate('conditional-notification-templates')) {
/*
$operations['conditional-notification-templates'] = [
'title' => t('Manage Notifications'),
'weight' => 100,
'url' => Url::fromRoute("entity.{$entity_type_id}.conditional_notification_templates", [$entity_type_id => $entity_id]),
];
*/
}
......@@ -79,14 +75,77 @@ function conditional_notification_entity_operation(EntityInterface $entity) {
}
function conditional_notification_entity_insert(EntityInterface $entity) {
// If the conditional notification was set to action "cron",
// we have to create our conditional_notification_log here.
\Drupal::service('conditional_notification.notification_factory')->createNotificationLog($entity);
// Delegate to service
\Drupal::service('conditional_notification.notification_factory')->createDefaultNotifications($entity);
}
function conditional_notification_entity_update(EntityInterface $entity) {
// Delegate to service
\Drupal::service('conditional_notification.notification_factory')->createNotifications($entity);
}
// If the conditional notification was set to action "cron",
// we have to create our conditional_notification_log here.
\Drupal::service('conditional_notification.notification_factory')->createNotificationLog($entity);
// Delegate to service
\Drupal::service('conditional_notification.notification_factory')->createNotifications($entity);
}
/**
* Implements hook_cron().
*/
function conditional_notification_cron() {
// Get the actual date
$current_time = new DrupalDateTime('now');
// Set time format to hour.
$current_hour = $current_time->format('H');
// Set time format to day.
$current_day = $current_time->format('d.m.Y');
// Create an object of type Select and directly add extra detail
// to this query object: a condition, fields and a range.
$query = \Drupal::entityQuery('conditional_notification_log')
->condition('entity_date_string_day', $current_day)
->accessCheck(FALSE);
$results = $query->execute();
if (!empty($results)) {
$entities = \Drupal::entityTypeManager()->getStorage('conditional_notification_log')->loadMultiple($results);
foreach ($entities as $entity) {
if ($entity->entity_date_string_hour->value === $current_hour) {
$data[$entity->id()] = [
'entity_id' => $entity->entity_id->value,
'entity_type' => $entity->entity_type->value,
'notification_id' => $entity->notification_id->target_id,
];
}
else {
$data[$entity->id()] = [
'entity_id' => $entity->entity_id->value,
'entity_type' => $entity->entity_type->value,
'notification_id' => $entity->notification_id->target_id,
];
}
}
}
// Put our data into a queue.
if (!empty($data)) {
foreach ($data as $key => $data_to_process) {
if (
isset($data_to_process['entity_id']) &&
isset($data_to_process['entity_type']) &&
isset($data_to_process['notification_id'])
) {
\Drupal::service('conditional_notification.notification_factory')->createNotificationsOnCron($data_to_process);
}
}
}
}
\ No newline at end of file
......@@ -10,5 +10,8 @@ manage conditional_notification context:
title: 'Manage conditional notification context'
manage conditional_notification mail from:
title: 'Manage conditional notification mail from'
manage conditional_notification mail reply to:
title: 'Manage conditional notification reply to'
manage conditional_notification time offset:
title: 'Manage conditional notification time offset'
......@@ -40,6 +40,9 @@ conditional_notification.conditional_notification.*:
mail_from:
type: string
label: 'From'
mail_reply_to:
type: string
label: 'Mail Reply to'
mail_from_enabled:
type: boolean
label: 'Mail from enabled'
......
......@@ -30,4 +30,11 @@ class NotificationContext extends Plugin {
*/
public $label;
/**
* The array with entities for which this plugin is allowed.
*
* @var array
*/
public $entities;
}
......@@ -37,4 +37,12 @@ class NotificationEntityCondition extends Plugin {
*/
public $entities;
/**
* The array with actions for which this plugin is allowed.
*
* @var array
*/
public $actions;
}
<?php
namespace Drupal\conditional_notification\Annotation;
use Drupal\Component\Annotation\Plugin;
/**
* Defines a Notification condition item annotation object.
*
* @see \Drupal\conditional_notification\Plugin\NotificationConditionManager
* @see plugin_api
*
* @Annotation
*/
class NotificationOffsetCondition extends Plugin {
/**
* The plugin ID.
*
* @var string
*/
public $id;
/**
* The label of the plugin.
*
* @var \Drupal\Core\Annotation\Translation
*
* @ingroup plugin_translatable
*/
public $label;
/**
* The array with entities for which this plugin is allowed.
*
* @var array
*/
public $entities;
}
......@@ -51,6 +51,16 @@ interface ConditionalNotificationInterface extends ConfigEntityInterface {
*/
public function setMailFrom(string $mail_from);
/**
* {@inheritdoc}
*/
public function getMailReplyTo();
/**
* {@inheritdoc}
*/
public function setMailReplyTo(string $mail_reply_to);
/**
* {@inheritdoc}
*/
......@@ -176,6 +186,11 @@ interface ConditionalNotificationInterface extends ConfigEntityInterface {
*/
public function getTimeOffsetDateField();
/**
* {@inheritdoc}
*/
public function getTimeOffsetDateFieldOnly();
/**
* {@inheritdoc}
*/
......
<?php
namespace Drupal\conditional_notification;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\user\EntityOwnerInterface;
use Drupal\Core\Entity\EntityChangedInterface;
/**
* Provides an interface defining a Conditional Notification Log entity.
*
* @ingroup conditional_notification
* @package Drupal\conditional_notification
*/
interface ConditionalNotificationLogInterface extends ContentEntityInterface, EntityChangedInterface {
}
......@@ -48,6 +48,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
* "subject",
* "body",
* "mail_from",
* "mail_reply_to",
* "mail_from_enabled",
* "notification_entity_type",
* "notification_entity_bundle",
......@@ -92,6 +93,11 @@ final class ConditionalNotification extends ConfigEntityBase implements Conditio
*/
protected string $mail_from = '';
/**
* The mail reply to.
*/
protected string $mail_reply_to = '';
/**
* The mail from mail.
*/
......@@ -238,6 +244,21 @@ final class ConditionalNotification extends ConfigEntityBase implements Conditio
return $this;
}
/**
* {@inheritdoc}
*/
public function getMailReplyTo() {
return $this->mail_reply_to;
}
/**
* {@inheritdoc}
*/
public function setMailReplyTo(string $mail_reply_to) {
$this->mail_reply_to = $mail_reply_to;
return $this;
}
/**
* {@inheritdoc}
*/
......@@ -453,6 +474,13 @@ final class ConditionalNotification extends ConfigEntityBase implements Conditio
return $this->time_offset_date_field;
}
/**
* {@inheritdoc}
*/
public function getTimeOffsetDateFieldOnly() {
return strstr($this->time_offset_date_field, ":", true);
}
/**
* {@inheritdoc}
*/
......
<?php
namespace Drupal\conditional_notification\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\user\UserInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\conditional_notification\ConditionalNotificationLogInterface;
/**
* Provides the 'conditional_notification_log' Entity.
*
* @package Drupal\conditional_notification\Entity
*
* @ContentEntityType(
* id = "conditional_notification_log",
* label = @Translation("Notification log"),
* handlers = {
* "views_data" = "Drupal\views\EntityViewsData"
* },
* base_table = "conditional_notification_log",
* fieldable = FALSE,
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid"
* }
* )
*/
class ConditionalNotificationLog extends ContentEntityBase implements ConditionalNotificationLogInterface {
use EntityChangedTrait;
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['notification_id'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Notification ID'))
->setSetting('target_type', 'conditional_notification')
->setSetting('handler', 'default')
->setDescription(t('The notification ID.'));
$fields['entity_id'] = BaseFieldDefinition::create('integer')
->setLabel(t('Entity ID'))
->setDescription(t('The Entity ID.'));
$fields['entity_type'] = BaseFieldDefinition::create('string')
->setLabel(t('Entity type'))
->setDescription(t('The Entity type.'));
$fields['time_offset_type'] = BaseFieldDefinition::create('string')
->setLabel(t('Time offset type'))
->setDescription(t('The time offset type.'));
$fields['time_offset'] = BaseFieldDefinition::create('integer')
->setLabel(t('Time offset'));
$fields['entity_date_field'] = BaseFieldDefinition::create('string')
->setLabel(t('Entity date field'));
$fields['entity_date_field_part'] = BaseFieldDefinition::create('string')
->setLabel(t('Entity date field part'));
$fields['entity_date_field_timestamp'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Entity date field timestamp'));
$fields['entity_date_offset'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Entity date offset'));
$fields['entity_date_string_day'] = BaseFieldDefinition::create('string')
->setLabel(t('Entity date string day'));
$fields['entity_date_string_hour'] = BaseFieldDefinition::create('string')
->setLabel(t('Entity date string hour'));
$fields['processed'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Processed'));
$fields['processed_timestamp'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Processed on'));
return $fields;
}
}
......@@ -15,6 +15,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
final class ConditionalNotificationForm extends EntityForm {
protected $currentUser;
/**
* {@inheritdoc}
*/
......@@ -106,10 +108,60 @@ final class ConditionalNotificationForm extends EntityForm {
$form['tokens'] = \Drupal::service('token.tree_builder')->buildRenderable($available_tokens);
if ($this->entity->getEntityId()) {
$entity_action_type_access = FALSE;
}
else {
$entity_action_type_access = TRUE;
}
// Define options
$entity_action_type_options = [
'insert' => $this->t('Insert'),
'update' => $this->t('Update'),
'cron' => $this->t('Cron'),
];
$entity_action_type_default = $this->entity->getEntityActionType() ?? 'update';
$form['entity_action_type'] = [
'#type' => 'select',
'#title' => $this->t('Entity Action type'),
'#default_value' => $entity_action_type_default,
'#description' => $this->t('Select "insert" or "update" as your action type.'),
'#options' => $entity_action_type_options,
'#access' => $entity_action_type_access,
'#ajax' => [
'callback' => '::getSupportedEntityConditionsDropDownCallback',
'wrapper' => 'ajax-entity-conditions-wrapper',
],
];
$form['entity_condition_wrapper'] = [
'#type' => 'container',
'#attributes' => ['id' => 'ajax-entity-conditions-wrapper'],
];
if (empty($form_state->getValue('entity_action_type'))) {
$selected_entity_type_action = key($entity_action_type_options);
}
else {
$selected_entity_type_action = $form_state->getValue('entity_action_type');
}
$entity_condition_options = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$entity_type_bundle_info = $this->entity->getNotificationEntityTypeBundleInfo();
$entity_condition_options = $entity_condition_options->getOptionsList([$entity_type_bundle_info]);
if ($saved_action_type = $this->entity->getEntityActionType()) {
$entity_condition_options = $entity_condition_options->getOptionsList([$entity_type_bundle_info], [$saved_action_type]);
}
else {
$entity_condition_options = $entity_condition_options->getOptionsList([$entity_type_bundle_info], [$selected_entity_type_action]);
}
if ($this->currentUser->hasPermission('manage conditional_notification condition')) {
$notification_condition_disabled = FALSE;
}
......@@ -117,17 +169,27 @@ final class ConditionalNotificationForm extends EntityForm {
$notification_condition_disabled = TRUE;
}
$form['notification_condition'] = [
$form['entity_condition_wrapper']['notification_condition'] = [
'#type' => 'select',
'#title' => $this->t('Condition'),
'#description' => $this->t('Condition that trigger sending the notification.'),
'#default_value' => $this->entity->getNotificationCondition(),
'#options' => $entity_condition_options,
'#disabled' => $notification_condition_disabled
];
'#disabled' => $notification_condition_disabled,
];
if ($entity_type_id = $this->entity->getNotificationEntityType()) {
$entity_type_for_context = $entity_type_id;
}
else {
$entity_type_for_context = [];
}
$entity_type_for_context = $this->entity->getNotificationEntityType();
$notification_context_manager = \Drupal::service('plugin.manager.notification_context.processor');
$context_options = $notification_context_manager->getOptionsList();
$context_options = $notification_context_manager->getOptionsList([$entity_type_for_context]);
if ($this->currentUser->hasPermission('manage conditional_notification context')) {
$notification_context_disabled = FALSE;
......@@ -136,8 +198,6 @@ final class ConditionalNotificationForm extends EntityForm {
$notification_context_disabled = TRUE;
}
//dump($this->entity->getNotificationContext());
$form['notification_context'] = [
'#type' => 'select',
'#title' => $this->t('Context'),
......@@ -145,29 +205,50 @@ final class ConditionalNotificationForm extends EntityForm {
'#default_value' => $this->entity->getNotificationContext(),
'#options' => $context_options,
'#disabled' => $notification_context_disabled
];
];
if ($this->entity->getEntityId()) {
$entity_action_type_access = FALSE;
}
if ($this->currentUser->hasPermission('manage conditional_notification mail from')) {
$notification_mail_from_disabled = FALSE;
}
else {
$entity_action_type_access = TRUE;
$notification_mail_from_disabled = TRUE;
}
$form['entity_action_type'] = [
'#type' => 'select',
'#title' => $this->t('Entity Action type'),
'#default_value' => $this->entity->getEntityActionType() ?? '',
'#description' => $this->t('Select "insert" or "update" as your action type.'),
'#options' => [
'insert' => $this->t('Insert'),
'update' => $this->t('Update'),
],
'#access' => $entity_action_type_access,
$form['mail_from_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Define a custom from email instead of site mail.'),
'#default_value' => $this->entity->getMailFromEnabled(),
'#disabled' => $notification_mail_from_disabled
];
$form['mail_from'] = [
'#type' => 'email',
'#title' => $this->t('Mail form address'),
'#default_value' => $this->entity->getMailFrom(),
'#disabled' => $notification_mail_from_disabled,
'#states' => [
'visible' => [
':input[name="mail_from_enabled"]' => ['checked' => TRUE],
],
]
];
if (!empty($this->entity->getSupportedDateFields())) {
if ($this->currentUser->hasPermission('manage conditional_notification mail reply to')) {
$notification_mail_reply_to_disabled = FALSE;
}
else {
$notification_mail_reply_to_disabled = TRUE;
}
$form['mail_reply_to'] = [
'#type' => 'email',
'#title' => $this->t('Mail reply to'),
'#default_value' => $this->entity->getMailReplyTo(),
'#disabled' => $notification_mail_reply_to_disabled,
];
if (!empty($this->entity->getSupportedDateFields())) {
$supported_date_fields = $this->entity->getSupportedDateFields();
......@@ -176,33 +257,8 @@ final class ConditionalNotificationForm extends EntityForm {
}
else {
$selected_date_field = $form_state->getValue('time_offset_date_field');
}
if ($this->currentUser->hasPermission('manage conditional_notification mail from')) {
$notification_mail_from_disabled = FALSE;
}
else {
$notification_mail_from_disabled = TRUE;
}
$form['mail_from_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Define a custom from email instead of site mail.'),
'#default_value' => $this->entity->getMailFromEnabled(),
'#disabled' => $notification_mail_from_disabled
];
}
$form['mail_from'] = [
'#type' => 'email',
'#title' => $this->t('Mail form address'),
'#default_value' => $this->entity->getMailFrom(),
'#disabled' => $notification_mail_from_disabled,
'#states' => [
'visible' => [
':input[name="mail_from_enabled"]' => ['checked' => TRUE],
],
]
];
if ($this->currentUser->hasPermission('manage conditional_notification time offset')) {
$notification_time_offset_disabled = FALSE;
......@@ -215,8 +271,13 @@ final class ConditionalNotificationForm extends EntityForm {
'#type' => 'checkbox',
'#title' => $this->t('Enable time offset'),
'#default_value' => $this->entity->getTimeOffsetEnabled(),
'#disabled' => $notification_time_offset_disabled
];
'#disabled' => $notification_time_offset_disabled,
'#states' => [
'visible' => [
'select[name="entity_action_type"]' => ['value' => 'cron'],
],
]
];
$form['time_offset_wrapper'] = [
'#type' => 'container',
......@@ -226,7 +287,7 @@ final class ConditionalNotificationForm extends EntityForm {
':input[name="time_offset_enabled"]' => ['checked' => TRUE],
],
]
];
];
$form['time_offset_wrapper']['time_offset_date_field'] = [
'#type' => 'select',
......@@ -243,16 +304,30 @@ final class ConditionalNotificationForm extends EntityForm {
$helper_service = \Drupal::service('conditional_notification.helper');
if ($saved_date_field = $this->entity->getTimeOffsetDateField()) {
$time_offset_date_field_part_options = $helper_service->getSupportedDateParts($saved_date_field );
}
else {
$time_offset_date_field_part_options = $helper_service->getSupportedDateParts($selected_date_field);
}
$time_offset_date_field_part_options = $helper_service->getSupportedDateParts($selected_date_field);
if (empty($form_state->getValue('time_offset_date_field_part'))) {
$selected_date_field_part = key($time_offset_date_field_part_options);
}
else {
$selected_date_field_part = $form_state->getValue('time_offset_date_field_part');
}
$form['time_offset_wrapper']['time_offset_date_field_part'] = [
'#type' => 'select',
'#title' => $this->t('Date parts'),
'#options' => $time_offset_date_field_part_options,
'#disabled' => $notification_time_offset_disabled
];
'#disabled' => $notification_time_offset_disabled,
'#default_value' => $this->entity->getTimeOffsetDateFieldPart() ?? $selected_date_field_part,
];
$form['time_offset_wrapper']['time_offset'] = [
'#type' => 'number',
'#title' => $this->t('Time offset'),
......@@ -267,7 +342,7 @@ final class ConditionalNotificationForm extends EntityForm {
'days' => $this->t('Days'),
'hours' => $this->t('Hours'),
];
$form['time_offset_wrapper']['time_offset_type'] = [
'#type' => 'select',
'#title' => $this->t('Time offset unit'),
......@@ -276,12 +351,13 @@ final class ConditionalNotificationForm extends EntityForm {
'#options' => $time_offset_type_options,
'#disabled' => $notification_time_offset_disabled
];
}
}
......@@ -309,4 +385,8 @@ final class ConditionalNotificationForm extends EntityForm {
return $form['time_offset_wrapper'];
}
public function getSupportedEntityConditionsDropDownCallback(array $form, FormStateInterface $form_state) {
return $form['entity_condition_wrapper'];
}
}
......@@ -65,6 +65,9 @@ final class SettingsForm extends ConfigFormBase {
public function buildForm(array $form, FormStateInterface $form_state): array {
$entity_types = $this->helperService->getSupportedEntityBundles();
//\Drupal::moduleHandler()->alter('conditinal_notification_entitiy_types', $plugin_items);
$supported_entities_options = $entity_types;
$supported_entities_default = $this->config('conditional_notification.settings')->get('supported_entities') ?? [];
......
......@@ -12,6 +12,7 @@ use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\conditional_notification\ConditionalNotificationInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -216,12 +217,27 @@ final class Helper {
->getFieldDefinitions($entity_type_id,
$entity_bundle);
$base_fields = $this->entityFieldManager
->getBaseFieldDefinitions($entity_type_id,
$entity_bundle);
foreach ($base_fields as $key => $field) {
if (in_array($field->getType(), ['created','changed'])) {
$machine_name_and_type = $key . ':' . $field->getType();
$supported_fields[$machine_name_and_type] = $field->getName();
}
}
foreach ($fields as $key => $field) {
if ($field->getType() === 'datetime' || $field->getType() === 'smartdate') {
$machine_name_and_type = $key . ':' . $field->getType();
$supported_fields[$machine_name_and_type] = $field->getName();
}
}
}
return $supported_fields;
......@@ -277,8 +293,62 @@ final class Helper {
}
}
public function mailReplyToAvailable(ConditionalNotificationInterface $conditional_notification) {
$mail_reply_to = FALSE;
if (!empty($conditional_notification->getMailReplyTo())) {
$mail_reply_to = $conditional_notification->getMailReplyTo();
}
return $mail_reply_to;
}
public function getConditionalNotificationsWhenTimeOffset() {
$data = [];
$conditions = [
'time_offset_enabled' => TRUE
];
$conditional_notifications = $this->entityTypeManager->getStorage('conditional_notification')->loadByProperties($conditions);
if (!empty($conditional_notifications)) {
foreach ($conditional_notifications as $machine_name => $notification) {
$data['machine_name'] = [
'entity_type' => $notification->getNotificationEntityType(),
'entity_bundle' => $notification->getNotificationEntityBundle(),
'date' => [
'field' => $notification->getTimeOffsetDateField(),
'part' => $notification->getTimeOffsetDateFieldPart()
],
'time_offset' => $notification->getTimeOffset(),
'time_offset_type' => $notification->getTimeOffsetType(),
];
}
}
return $data;
}
/**
* Set notification logs to unprocessed.
*
* @param EntityInterface $entity
* @return void
*/
function setConditionalNotificationLogToUnprocessed(EntityInterface $entity) {
$query = \Drupal::entityQuery('conditional_notification_log')
->condition('entity_id', $entity->id())
->condition('entity_type', $entity->getEntityTypeId())
->accessCheck(FALSE);
$results = $query->execute();
if (!empty($results)) {
$logs = $this->entityTypeManager->getStorage('conditional_notification_log')->loadMultiple($results);
foreach ($logs as $log) {
$log->processed->value = 0;
$log->save();
}
}
}
}
......@@ -45,21 +45,30 @@ final class NotificationFactory {
if (!empty($conditional_notifications)) {
foreach ($conditional_notifications as $notification) {
$condition_plugin_manager = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$condition = $notification->getNotificationCondition();
if ($condition_plugin_manager->hasDefinition($condition)) {
$plugin = $condition_plugin_manager->createInstance($condition);
if ($plugin->isValidEntityCondition($entity)) {
$data['notification'] = $notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
$this->addToQueue($data);
if ($notification->status()) {
$condition_plugin_manager = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$condition = $notification->getNotificationCondition();
if ($condition_plugin_manager->hasDefinition($condition)) {
$plugin = $condition_plugin_manager->createInstance($condition);
if ($plugin->isValidEntityCondition($entity)) {
$data['notification'] = $notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
$this->addToQueue($data);
}
}
}
}
}
}
/**
* Creates notifications
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
* @return void
*/
public function createNotifications(EntityInterface $entity): void {
$conditions = [
......@@ -75,28 +84,88 @@ final class NotificationFactory {
if (!empty($conditional_notifications)) {
foreach ($conditional_notifications as $notification) {
$condition_plugin_manager = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$condition = $notification->getNotificationCondition();
if ($condition_plugin_manager->hasDefinition($condition)) {
$plugin = $condition_plugin_manager->createInstance($condition);
if ($plugin->isValidEntityCondition($entity)) {
if ($override_notification = $this->checkForNotificationOverride($notification, $entity)) {
$data['notification_id'] = $override_notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
}
else {
$data['notification_id'] = $notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
if ($notification->status()) {
$condition_plugin_manager = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$condition = $notification->getNotificationCondition();
if ($condition_plugin_manager->hasDefinition($condition)) {
$plugin = $condition_plugin_manager->createInstance($condition);
if ($plugin->isValidEntityCondition($entity)) {
if ($override_notification = $this->checkForNotificationOverride($notification, $entity)) {
$data['notification_id'] = $override_notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
}
else {
$data['notification_id'] = $notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
}
$this->addToQueue($data);
}
$this->addToQueue($data);
}
}
}
}
}
/**
* Creates notifications on a cron job
*
* @param array $data
* The data to create notifications for.
* @return void
*/
public function createNotificationsOnCron($data): void {
if (!empty($data)) {
$this->addToQueue($data);
// Set to processed as it now lives in queue.
$this->setNotificationLogToProcessed($data);
}
}
/**
* Set a notification log to processed
*
* @param array $data
* The data to create notifications for.
* @return void
*/
protected function setNotificationLogToProcessed($data) {
$conditions = [
'notification_id' => $data['notification_id'],
'entity_id' => $data['entity_id'],
'entity_type' => $data['entity_type'],
];
try {
$logs = $this->entityTypeManager->getStorage('conditional_notification_log')->loadByProperties($conditions);
if ($log = reset($logs)) {
if ($log instanceof EntityInterface) {
$log->processed->value = 1;
$log->processed_timestamp->value = time();
$log->save();
}
}
}
catch (\Exception $exception) {
$message = $exception->getMessage();
$this->getLogger('conditional_notification')->warning('Problem updating conditional notification log: @message',['@message' => $message]);
}
}
/**
* Check if we neeed an override for a notification.
*
* @param $conditional_notification
* The conditional notification object.
* @param $entity
* The entity object.
* @return void
*/
protected function checkForNotificationOverride($conditional_notification, $entity) {
$override = FALSE;
......@@ -113,15 +182,185 @@ final class NotificationFactory {
->loadByProperties($conditions);
if ($conditional_notification = reset($conditional_notifications)) {
$override = $conditional_notification;
if ($conditional_notification->status()) {
$override = $conditional_notification;
}
}
return $override;
}
protected function addToQueue($data) {
/**
* Adds data to a queue for later processing.
*
* @param array $data
* @return void
*/
protected function addToQueue($data) {
$queue = \Drupal::queue('conditional_notification_notification_queue')->createItem($data);
}
/**
* Adds data to create a log queue for later processing.
*
* @param array $data
* @return void
*/
protected function addToLogQueue($data) {
$queue = \Drupal::queue('conditional_notification_notification_log_queue')->createItem($data);
}
/**
* Creates a notification log for easy processing,
* on cron and avoiding querie over the whole entity table.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* @return void
*/
public function createNotificationLog(EntityInterface $entity) {
$conditions = [
'entity_action_type' => 'cron',
'notification_type' => 'default',
'notification_entity_type' => $entity->getEntityTypeId(),
'notification_entity_bundle' => $entity->bundle(),
];
$conditional_notifications = $this->entityTypeManager
->getStorage('conditional_notification')
->loadByProperties($conditions);
if (!empty($conditional_notifications)) {
foreach ($conditional_notifications as $notification) {
// Only process enabled notifications.
if ($notification->status()) {
$condition_plugin_manager = \Drupal::service('plugin.manager.notification_entity_condition.processor');
$condition = $notification->getNotificationCondition();
if ($condition_plugin_manager->hasDefinition($condition)) {
$plugin = $condition_plugin_manager->createInstance($condition);
if ($plugin->isValidEntityCondition($entity)) {
if ($override_notification = $this->checkForNotificationOverride($notification, $entity)) {
$data['notification_id'] = $override_notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
$data['time_offset_enabled'] = $override_notification->getTimeOffsetEnabled();
// Check field
if ($date_field = $override_notification->getTimeOffsetDateFieldOnly()) {
$data['entity_date_field'] = $date_field;
if ($date_field_part = $override_notification->getTimeOffsetDateFieldPart()) {
$data['entity_date_field_part'] = $date_field_part;
$data['entity_date_field_timestamp'] = $entity->{$date_field}->{$date_field_part};
}
else {
$data['entity_date_field_part'] = NULL;
$data['entity_date_field_timestamp'] = $entity->get($date_field)->value;
}
// Calculate offset
$time_offset = $override_notification->getTimeOffset();
$time_offset_type = $override_notification->getTimeOffsetType();
$data['time_offset_type'] = $time_offset_type;
$data['time_offset'] = $time_offset;
$data['entity_date_offset'] = $data['entity_date_field_timestamp'] + ($this->getCalculatedOffset($time_offset, $time_offset_type));
$data['entity_date_string_day'] = $this->getCalculatedOffsetString($data['entity_date_offset']);
$data['entity_date_string_hour'] = $this->getCalculatedOffsetString($data['entity_date_offset'], 'hours');
}
}
else {
$data['notification_id'] = $notification->getId();
$data['entity_type'] = $entity->getEntityTypeId();
$data['entity_id'] = $entity->id();
$data['time_offset_enabled'] = $notification->getTimeOffsetEnabled();
// Check field
if ($date_field = $notification->getTimeOffsetDateFieldOnly()) {
$data['entity_date_field'] = $date_field;
if ($date_field_part = $notification->getTimeOffsetDateFieldPart()) {
$data['entity_date_field_part'] = $date_field_part;
$data['entity_date_field_timestamp'] = $entity->{$date_field}->{$date_field_part};
}
else {
$data['entity_date_field_part'] = NULL;
$data['entity_date_field_timestamp'] = $entity->get($date_field)->value;
}
// Calculate offset
$time_offset = $notification->getTimeOffset();
$time_offset_type = $notification->getTimeOffsetType();
$data['time_offset_type'] = $time_offset_type;
$data['time_offset'] = $time_offset;
$data['entity_date_offset'] = $data['entity_date_field_timestamp'] + ($this->getCalculatedOffset($time_offset, $time_offset_type));
$data['entity_date_string_day'] = $this->getCalculatedOffsetString($data['entity_date_offset']);
$data['entity_date_string_hour'] = $this->getCalculatedOffsetString($data['entity_date_offset'], 'hours');
}
}
// Only Create log if all conditions met
if ($data['time_offset_enabled'] && $data['entity_date_offset']) {
$this->addToLogQueue($data);
}
}
}
}
}
}
}
/**
* Get the calculation offset
*
* @param int $time_offset
* The given offset.
* @param string $type
* If hour or day.
* @return integer
* The postive or negative time offset.
*/
protected function getCalculatedOffset($time_offset, $type) {
$result = 0;
if ($type === 'hours') {
$result = $time_offset * 3600;
}
elseif ($type === 'days') {
$result = $time_offset * 86400;
}
return $result;
}
/**
* Get calculated offset string.
*
* @param array $entity_date_offset
* The offest.
* @param string $format
* The format in days, hours.
* @return string
* The formatted string.
*/
protected function getCalculatedOffsetString($entity_date_offset, $format = 'days'):string {
if ($format === 'hours') {
// Hours format
$formatted_string = \Drupal::service('date.formatter')->format(
$entity_date_offset,
'custom',
'H'
);
}
else {
$formatted_string = $entity_date_string_day = \Drupal::service('date.formatter')->format(
$entity_date_offset,
'custom',
'd.m.Y'
);
}
return $formatted_string;
}
}
<?php
namespace Drupal\conditional_notification\Plugin\NotificationContext;
use Drupal\conditional_notification\Plugin\NotificationContextBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\Sql\QueryFactory;
use Drupal\group\Entity\GroupInterface;
use Drupal\user\EntityOwnerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\group\Entity\GroupRelationship;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a 'GroupMembersNotificationContext' notification context.
*
* @NotificationContext(
* id = "group_members_noticiation_context",
* label = @Translation("Group members"),
* entities = {"group"}
* )
*/
class GroupMembersNotificationContext extends NotificationContextBase {
/**
* Constructs a MentionActivityContext object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\Query\Sql\QueryFactory $entity_query
* The query factory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
QueryFactory $entity_query,
EntityTypeManagerInterface $entity_type_manager
) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_query, $entity_type_manager);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.query.sql'),
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function getRecipients(array $data): array {
$recipients = [];
// We only know the context if there is an entity_type and entity_id.
if (
isset($data['entity_type']) && !empty($data['entity_type']) &&
isset($data['entity_id']) && !empty($data['entity_id'])
) {
$group = $this->entityTypeManager->getStorage($data['entity_type'])->load($data['entity_id']);
if ($group instanceof GroupInterface) {
$members = $group->getMembers();
if (!empty($members)) {
foreach ($members as $member) {
$user = $member->getUser();
if ($user instanceof UserInterface && $user->getStatus() === TRUE ) {
$recipients[$user->id()] = $user->id();
}
}
}
}
}
return $recipients;
}
}
......@@ -37,11 +37,26 @@ class NotificationContextManager extends DefaultPluginManager {
* An associative array mapping the IDs of all available tracker plugins to
* their labels.
*/
public function getOptionsList() {
public function getOptionsList(array $entities = []) {
$options = [];
foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
$options[$plugin_id] = Html::escape($plugin_definition['label']);
if (empty($entities)) {
foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
$options[$plugin_id] = Html::escape($plugin_definition['label']);
}
}
else {
foreach ($entities as $entity) {
// Get all entity condition plugin definitions.
foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
if (in_array($entity, $plugin_definition['entities'])) {
$options[$plugin_id] = Html::escape($plugin_definition['label']);
}
}
}
}
return $options;
}
......
......@@ -40,7 +40,7 @@ class NotificationEntityConditionManager extends DefaultPluginManager {
* An associative array mapping the IDs of all available tracker plugins to
* their labels.
*/
public function getOptionsList(array $entities = []) {
public function getOptionsList(array $entities = [], array $actions = []) {
$options = [];
foreach ($entities as $entity) {
......@@ -64,6 +64,17 @@ class NotificationEntityConditionManager extends DefaultPluginManager {
}
}
// Let's filter now by actions
if (!empty($actions)) {
foreach ($actions as $action) {
foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
if (!in_array($action, $plugin_definition['actions'])) {
unset($options[$plugin_id]);
}
}
}
}
return $options;
}
......
<?php
namespace Drupal\conditional_notification\Plugin;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\Sql\QueryFactory;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base class for notification entity condition plugins.
*/
abstract class NotificationOffsetConditionBase extends PluginBase implements NotificationOffsetConditionInterface, ContainerFactoryPluginInterface {
/**
* The entity query.
*
* @var \Drupal\Core\Entity\Query\Sql\QueryFactory
*
* The unused private variable is ignored here. Removing it would be a BC
* break but most classes extending the base class also don't use it so making
* it protected would cause more code to maintain. We should remove this in a
* major version and update the constructor.
* @phpstan-ignore-next-line
*/
private $entityQuery;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* NotificationEntityConditionBase constructor.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\Query\Sql\QueryFactory $entity_query
* The entity query.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
QueryFactory $entity_query,
EntityTypeManagerInterface $entity_type_manager
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityQuery = $entity_query;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.query.sql'),
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function isValidOffsetCondition($entity) {
return TRUE;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment