diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml index c462164aa..3bcfc1032 100644 --- a/config/packages/messenger.yaml +++ b/config/packages/messenger.yaml @@ -82,9 +82,9 @@ framework: 'Chill\MainBundle\Workflow\Messenger\PostSignatureStateChangeMessage': priority 'Chill\MainBundle\Workflow\Messenger\PostPublicViewMessage': async 'Chill\MainBundle\Service\Workflow\CancelStaleWorkflowMessage': async - 'Chill\MainBundle\Notification\Email\SendImmediateNotificationEmailMessage': immediate_email - 'Chill\MainBundle\Notification\Email\ScheduleDailyNotificationEmailMessage': daily_email - 'Chill\MainBundle\Notification\Email\SendDailyDigestMessage': daily_email + 'Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendImmediateNotificationEmailMessage': immediate_email + 'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationEmailMessage': daily_email + 'Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendDailyDigestMessage': daily_email # end of routes added by chill-bundles recipes # Route your messages to the transports # 'App\Message\YourMessage': async diff --git a/src/Bundle/ChillMainBundle/Entity/Notification.php b/src/Bundle/ChillMainBundle/Entity/Notification.php index 1c01ddd88..38b4b195e 100644 --- a/src/Bundle/ChillMainBundle/Entity/Notification.php +++ b/src/Bundle/ChillMainBundle/Entity/Notification.php @@ -22,7 +22,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table(name: 'chill_main_notification')] -#[ORM\Index(name: 'chill_main_notification_related_entity_idx', columns: ['relatedentityclass', 'relatedentityid'])] +#[ORM\Index(columns: ['relatedentityclass', 'relatedentityid'], name: 'chill_main_notification_related_entity_idx')] class Notification implements TrackUpdateInterface { #[ORM\Column(type: Types::TEXT, nullable: false)] @@ -38,7 +38,15 @@ class Notification implements TrackUpdateInterface private Collection $addressees; /** - * a list of destinee which will receive notifications. + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: UserGroup::class)] + #[ORM\JoinTable(name: 'chill_main_notification_addressee_user_group')] + private Collection $addresseeUserGroups; + + /** + * @deprecated + * a list of destinee which will receive notifications * * @var array|string[] */ @@ -46,7 +54,8 @@ class Notification implements TrackUpdateInterface private array $addressesEmails = []; /** - * a list of emails adresses which were added to the notification. + * @deprecated + * a list of emails adresses which were added to the notification * * @var array|string[] */ @@ -107,22 +116,31 @@ class Notification implements TrackUpdateInterface public function __construct() { $this->addressees = new ArrayCollection(); + $this->addresseeUserGroups = new ArrayCollection(); $this->unreadBy = new ArrayCollection(); $this->comments = new ArrayCollection(); $this->setDate(new \DateTimeImmutable()); $this->accessKey = bin2hex(openssl_random_pseudo_bytes(24)); } - public function addAddressee(User $addressee): self + public function addAddressee(User|UserGroup $addressee): self { - if (!$this->addressees->contains($addressee)) { - $this->addressees[] = $addressee; - $this->addedAddresses[] = $addressee; + if ($addressee instanceof User) { + if (!$this->addressees->contains($addressee)) { + $this->addressees->add($addressee); + + return $this; + } } + $this->addresseeUserGroups->add($addressee); + return $this; } + /** + * @deprecated + */ public function addAddressesEmail(string $email) { if (!\in_array($email, $this->addressesEmails, true)) { @@ -156,13 +174,26 @@ class Notification implements TrackUpdateInterface #[Assert\Callback] public function assertCountAddresses(ExecutionContextInterface $context, $payload): void { - if (0 === (\count($this->getAddressesEmails()) + \count($this->getAddressees()))) { + if (0 === (\count($this->getAddresseeUserGroups()) + \count($this->getAddressees()))) { $context->buildViolation('notification.At least one addressee') ->atPath('addressees') ->addViolation(); } } + /** + * @return Collection + */ + public function getAddresseeUserGroups(): Collection + { + return $this->addresseeUserGroups; + } + + public function setAddresseeUserGroups(Collection $addresseeUserGroups): void + { + $this->addresseeUserGroups = $addresseeUserGroups; + } + public function getAccessKey(): string { return $this->accessKey; @@ -186,8 +217,27 @@ class Notification implements TrackUpdateInterface return $this->addressees; } + public function getAllAddressees(): array + { + $allUsers = []; + + foreach ($this->getAddressees() as $user) { + $allUsers[$user->getId()] = $user; + } + + foreach ($this->getAddresseeUserGroups() as $userGroup) { + foreach ($userGroup->getUsers() as $user) { + $allUsers[$user->getId()] = $user; + } + } + + return array_values($allUsers); + } + /** * @return array|string[] + * + * @deprecated */ public function getAddressesEmails(): array { @@ -196,6 +246,8 @@ class Notification implements TrackUpdateInterface /** * @return array|string[] + * + * @deprecated */ public function getAddressesEmailsAdded(): array { @@ -307,15 +359,24 @@ class Notification implements TrackUpdateInterface $this->addressesOnLoad = null; } - public function removeAddressee(User $addressee): self + public function removeAddressee(User|UserGroup $addressee): self { - if ($this->addressees->removeElement($addressee)) { - $this->removedAddresses[] = $addressee; + if ($addressee instanceof User) { + if ($this->addressees->contains($addressee)) { + $this->addressees->removeElement($addressee); + + return $this; + } } + $this->addresseeUserGroups->removeElement($addressee); + return $this; } + /** + * @deprecated + */ public function removeAddressesEmail(string $email) { if (\in_array($email, $this->addressesEmails, true)) { diff --git a/src/Bundle/ChillMainBundle/Form/NotificationType.php b/src/Bundle/ChillMainBundle/Form/NotificationType.php index 2bd8ba820..9db245d79 100644 --- a/src/Bundle/ChillMainBundle/Form/NotificationType.php +++ b/src/Bundle/ChillMainBundle/Form/NotificationType.php @@ -12,17 +12,13 @@ declare(strict_types=1); namespace Chill\MainBundle\Form; use Chill\MainBundle\Entity\Notification; -use Chill\MainBundle\Form\Type\ChillCollectionType; use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\PickUserDynamicType; +use Chill\MainBundle\Form\Type\PickUserGroupOrUserDynamicType; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Validator\Constraints\Email; -use Symfony\Component\Validator\Constraints\NotBlank; -use Symfony\Component\Validator\Constraints\NotNull; class NotificationType extends AbstractType { @@ -33,29 +29,13 @@ class NotificationType extends AbstractType 'label' => 'Title', 'required' => true, ]) - ->add('addressees', PickUserDynamicType::class, [ + ->add('addressees', PickUserGroupOrUserDynamicType::class, [ 'multiple' => true, - 'required' => false, + 'empty_data' => '[]', + 'required' => true, ]) ->add('message', ChillTextareaType::class, [ 'required' => false, - ]) - ->add('addressesEmails', ChillCollectionType::class, [ - 'label' => 'notification.dest by email', - 'help' => 'notification.dest by email help', - 'by_reference' => false, - 'allow_add' => true, - 'allow_delete' => true, - 'entry_type' => EmailType::class, - 'button_add_label' => 'notification.Add an email', - 'button_remove_label' => 'notification.Remove an email', - 'empty_collection_explain' => 'notification.Any email', - 'entry_options' => [ - 'constraints' => [ - new NotNull(), new NotBlank(), new Email(), - ], - 'label' => 'Email', - ], ]); } diff --git a/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php b/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php index 34e6f031a..5cda29b0d 100644 --- a/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php +++ b/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php @@ -72,16 +72,16 @@ readonly class NotificationMailer */ public function postPersistNotification(Notification $notification, PostPersistEventArgs $eventArgs): void { - $this->sendNotificationEmailsToAddresses($notification); - $this->sendNotificationEmailsToAddressesEmails($notification); + $this->sendNotificationEmailsToAddressees($notification); +// $this->sendNotificationEmailsToAddressesEmails($notification); } public function postUpdateNotification(Notification $notification, PostUpdateEventArgs $eventArgs): void { - $this->sendNotificationEmailsToAddressesEmails($notification); + $this->sendNotificationEmailsToAddressees($notification); } - private function sendNotificationEmailsToAddresses(Notification $notification): void + private function sendNotificationEmailsToAddressees(Notification $notification): void { if (null === $notification->getType()) { $this->logger->warning('[NotificationMailer] Notification has no type, skipping email processing', [ @@ -91,7 +91,7 @@ readonly class NotificationMailer return; } - foreach ($notification->getAddressees() as $addressee) { + foreach ($notification->getAllAddressees() as $addressee) { if (null === $addressee->getEmail()) { continue; } @@ -232,6 +232,9 @@ readonly class NotificationMailer } } + /** + * @deprecated + */ private function sendNotificationEmailsToAddressesEmails(Notification $notification): void { foreach ($notification->getAddressesEmailsAdded() as $emailAddress) { diff --git a/src/Bundle/ChillMainBundle/Resources/views/Notification/create.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Notification/create.html.twig index 4dfd340b6..8797c276a 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Notification/create.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Notification/create.html.twig @@ -21,8 +21,6 @@ {{ form_row(form.title, { 'label': 'notification.subject'|trans }) }} {{ form_row(form.addressees, { 'label': 'notification.sent_to'|trans }) }} - {{ form_row(form.addressesEmails) }} - {% include handler.template(notification) with handler.templateData(notification) %}
diff --git a/src/Bundle/ChillMainBundle/migrations/Version20250623120824.php b/src/Bundle/ChillMainBundle/migrations/Version20250623120824.php new file mode 100644 index 000000000..e5ef06f8c --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20250623120824.php @@ -0,0 +1,48 @@ +addSql(<<<'SQL' + CREATE TABLE chill_main_notification_addressee_user_group (notification_id INT NOT NULL, usergroup_id INT NOT NULL, PRIMARY KEY(notification_id, usergroup_id)) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_ECF81C07EF1A9D84 ON chill_main_notification_addressee_user_group (notification_id) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_ECF81C07D2112630 ON chill_main_notification_addressee_user_group (usergroup_id) + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_main_notification_addressee_user_group ADD CONSTRAINT FK_ECF81C07EF1A9D84 FOREIGN KEY (notification_id) REFERENCES chill_main_notification (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_main_notification_addressee_user_group ADD CONSTRAINT FK_ECF81C07D2112630 FOREIGN KEY (usergroup_id) REFERENCES chill_main_user_group (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE + SQL); + } + + public function down(Schema $schema): void + { + $this->addSql(<<<'SQL' + ALTER TABLE chill_main_notification_addressee_user_group DROP CONSTRAINT FK_ECF81C07EF1A9D84 + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_main_notification_addressee_user_group DROP CONSTRAINT FK_ECF81C07D2112630 + SQL); + $this->addSql(<<<'SQL' + DROP TABLE chill_main_notification_addressee_user_group + SQL); + } +}