-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
continue; // Try the next DSN in the list
Unhandled channels
===========================================================
<?php
declare(strict_types=1);
namespace Glued\Lib;
use Http\Client\Exception;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport\Dsn as MailerDsn;
use Symfony\Component\Mailer\Transport\FailoverTransport;
use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
use Symfony\Component\Mime\Address;
use Symfony\Component\Notifier\Message\EmailMessage;
use Symfony\Component\Notifier\Message\ChatMessage;
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\Message\PushMessage;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Notifier;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;
use Symfony\Component\Notifier\Bridge\Symfony\Mailer\NotifierSymfonyMailerTransport;
use Symfony\Component\Notifier\Bridge\Symfony\Mailer\SymfonyMailerTransport;
use Symfony\Component\Notifier\Transport\Dsn as NotifierDsn;
use Symfony\Component\Notifier\Bridge\Telegram\TelegramTransportFactory;
use Symfony\Component\Notifier\Chatter;
use Symfony\Component\Notifier\Channel\ChatChannel;
use Symfony\Component\Notifier\Channel\EmailChannel;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\RawMessage;
use Symfony\Component\Mailer\Envelope;
class Notify
{
protected $recipients;
protected $settings;
protected $logger;
protected $adminDsts;
public function __construct($settings, $logger)
{
$this->settings = $settings['notify'];
$this->logger = $logger;
$this->users = [];
// on class invocation, get the admin destinations from $this->settings
$this->admins = $this->destinations();
// remove admin destinations (the method actually clears all the destinations, but at class invocation
// only admin destinations are defined). To later send notifications to admins, $this->settings needs to be
// merged with $this->admins
$this->clear_to();
}
public function destinations(): array {
foreach ($this->settings['network'] as $k => $v) {
$ret[$k] = $v['dst'] ?? [];
}
return $ret ?? [];
}
public function getadmins(): array {
return $this->admins;
}
public function clear_to(): self {
foreach ($this->settings['network'] as $k => &$v) {
$v['dst'] = [];
}
return $this;
}
public function getusers(): array {
return $this->users;
}
public function to(array $r): self {
$this->users = array_merge_recursive($this->users, $r);
foreach ($this->settings['network'] as $channel => &$config) {
$recipients = $config['dst'] ?? [];
$newRecipients = array_filter(array_column($r, $channel));
$recipients = array_unique(array_merge($recipients, $newRecipients));
$config['dst'] = $recipients;
}
return $this;
}
public function status(): array {
return $this->settings;
}
public function send(string $content, string $subject = 'Glued notification', bool $notify_admins = false)
{
$c = $this->settings['network'];
if ($notify_admins === true) {
$this->settings['network'] = array_merge_recursive($this->settings['network'], $this->getadmins());
}
$chat = new ChatMessage($content);
$push = new PushMessage($subject, $content);
$mail = (new Email())
->from($c['email']['config']['src'])
->subject($subject)
->text($content);
foreach ($c as $type => $network) {
// ===========================================================
// Channels requiring a separate transport for every recipient
// ===========================================================
if ($type == 'telegram') {
$success = false; // Flag to help iterate over all provided channel DSNs
foreach ($c[$type]['channels'] as $channel) {
try {
foreach ($network['dst'] as $key => $dst) {
$dsn = new NotifierDsn($channel['dsn'] . $dst);
$transport = (new TelegramTransportFactory)->create($dsn);
$transport->send($chat);
unset($c[$type]['dst'][$key]); // On successful send remove destination (recipient)
}
$success = true;
break; // Exit the loop if the email was sent successfully with current DSN
} catch (\Exception $e) {
// TODO Handle the exception better (e.g. log it)
continue; // Try the next DSN in the list
}
}
if (!$success) {
$this->logger->error("lib.notify failed to send some " . $type . " notifications.");
}
}
// ===========================================================
// Channels ok with a single transport for multiple recipients
// ===========================================================
elseif ($type == 'email') {
$success = false; // Flag to help iterate over all provided channel DSNs
foreach ($c[$type]['channels'] as $channel) {
$dsn = MailerDsn::fromString($channel['dsn']);
try {
$transport = (new EsmtpTransportFactory)->create($dsn);
foreach ($network['dst'] as $key => $dst) {
$envelope = new Envelope(new Address($c[$type]['config']['src']), [new Address($dst)]);
$transport->send(new RawMessage($mail->to($dst)->toString()), $envelope);
unset($c[$type]['dst'][$key]); // On successful send remove destination (recipient)
}
$success = true;
break; // Exit the loop if the email was sent successfully with current DSN
} catch (\Exception $e) {
// TODO Handle the exception better (e.g. log it)
continue; // Try the next DSN in the list
}
}
if (!$success) {
$this->logger->error("lib.notify failed to send some " . $type . " notifications.");
}
}
// ===========================================================
// Unhandled channels
// ===========================================================
else {
$this->logger->error("lib.notify configured to send unsupported type of notifications (" . $type . ").");
}
}
}
// TODO: add a property to store recipients to which the notification could not be sent successfully
// basically just extract the recipients from $this->config after send()
}