handle invalid email address

This commit is contained in:
Denis Duliçi 2023-04-24 11:02:45 +03:00
parent d1cd9a5cd4
commit c15d9349b0
11 changed files with 286 additions and 0 deletions

View File

@ -0,0 +1,51 @@
<?php
namespace App\Events\Email;
use App\Abstracts\Event;
use App\Models\Auth\User;
use App\Models\Common\Contact;
class InvalidEmailDetected extends Event
{
public $email;
public $error;
public $contact = null;
public $user = null;
public function __construct(string $email, string $error)
{
$this->email = $email;
$this->error = $error;
$this->setContact();
$this->setUser();
}
public function setContact()
{
$contact = Contact::email($this->email)->enabled()->first();
if (empty($contact)) {
return;
}
$this->contact = $contact;
}
public function setUser()
{
$user = User::email($this->email)->enabled()->first();
if (empty($user)) {
return;
}
$this->user = $user;
}
}

View File

@ -3,6 +3,7 @@
namespace App\Exceptions;
use Akaunting\Money\Exceptions\UnexpectedAmountException;
use App\Events\Email\InvalidEmailDetected;
use App\Exceptions\Http\Resource as ResourceException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -15,6 +16,7 @@ use Illuminate\View\ViewException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Mailer\Exception\HttpTransportException as MailerHttpTransportException;
use Throwable;
class Handler extends ExceptionHandler
@ -194,6 +196,21 @@ class Handler extends ExceptionHandler
}
}
if ($exception instanceof MailerHttpTransportException) {
/**
* Couldn't access the SentMessage object to get the email address
* https://symfony.com/doc/current/mailer.html#debugging-emails
*
* https://codespeedy.com/extract-email-addresses-from-a-string-in-php
* https://phpliveregex.com/p/IMG
*/
preg_match("/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/", $exception->getMessage(), $matches);
if (! empty($matches[0])) {
event(new InvalidEmailDetected($matches[0], $exception->getMessage()));
}
}
return parent::render($request, $exception);
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Listeners\Email;
use App\Events\Email\InvalidEmailDetected as Event;
class DisablePersonDueToInvalidEmail
{
public function handle(Event $event): void
{
$this->disableContact($event);
$this->disableUser($event);
}
public function disableContact(Event $event): void
{
if (empty($event->contact)) {
return;
}
$event->contact->enabled = false;
$event->contact->save();
}
public function disableUser(Event $event): void
{
if (empty($event->user)) {
return;
}
$event->user->enabled = false;
$event->user->save();
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Listeners\Email;
use App\Events\Email\InvalidEmailDetected as Event;
use App\Notifications\Email\InvalidEmail;
use Illuminate\Support\Str;
class SendInvalidEmailNotification
{
public function handle(Event $event): void
{
$users = company()->users;
$this->notifyAdminsAboutInvalidContactEmail($event, $users);
$this->notifyAdminsAboutInvalidUserEmail($event, $users);
}
public function notifyAdminsAboutInvalidContactEmail(Event $event, $users): void
{
if (empty($event->contact)) {
return;
}
if ($event->contact->isCustomer() || $event->contact->isVendor() || $event->contact->isEmployee()) {
$type = trans('general.' . Str::plural($event->contact->type), 1);
} else {
$type = ucfirst($event->contact->type);
}
foreach ($users as $user) {
if ($user->cannot('read-notifications')) {
continue;
}
$user->notify(new InvalidEmail($event->email, $type, $event->error));
}
}
public function notifyAdminsAboutInvalidUserEmail(Event $event, $users): void
{
if (empty($event->user)) {
return;
}
$type = trans('general.users', 1);
foreach ($users as $user) {
if ($user->cannot('read-notifications')) {
continue;
}
if ($user->email == $event->email) {
continue;
}
$user->notify(new InvalidEmail($event->email, $type, $event->error));
}
}
}

View File

@ -244,6 +244,11 @@ class User extends Authenticatable implements HasLocalePreference
return $query->wherePermissionIs('read-admin-panel');
}
public function scopeEmail($query, $email)
{
return $query->where('email', '=', $email);
}
/**
* Attach company_ids attribute to model.
*

View File

@ -0,0 +1,76 @@
<?php
namespace App\Notifications\Email;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class InvalidEmail extends Notification implements ShouldQueue
{
use Queueable;
protected string $email;
protected string $type;
protected string $error;
/**
* Create a notification instance.
*/
public function __construct(string $email, string $type, string $error)
{
$this->email = $email;
$this->type = $type;
$this->error = $error;
$this->onQueue('notifications');
}
/**
* Get the notification's channels.
*
* @param mixed $notifiable
* @return array|string
*/
public function via($notifiable)
{
return ['mail', 'database'];
}
/**
* Build the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$dashboard_url = route('dashboard', ['company_id' => company_id()]);
return (new MailMessage)
->subject(trans('notifications.email.invalid.title', ['type' => $this->type]))
->line(trans('notifications.email.invalid.description', ['email' => $this->email]))
->line($this->error)
->action(trans_choice('general.dashboards', 1), $dashboard_url);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'title' => trans('notifications.menu.invalid_email.title', ['type' => $this->type]),
'description' => trans('notifications.menu.invalid_email.description', ['email' => $this->email]),
'email' => $this->email,
];
}
}

View File

@ -108,6 +108,10 @@ class Event extends Provider
'App\Listeners\Email\ReportTooManyEmailsSent',
'App\Listeners\Email\TellFirewallTooManyEmailsSent',
],
'App\Events\Email\InvalidEmailDetected' => [
'App\Listeners\Email\DisablePersonDueToInvalidEmail',
'App\Listeners\Email\SendInvalidEmailNotification',
],
];
/**

View File

@ -18,6 +18,13 @@ trait Contacts
return in_array($type, $this->getVendorTypes());
}
public function isEmployee()
{
$type = $this->type ?? $this->contact->type ?? $this->model->type ?? 'employee';
return in_array($type, $this->getEmployeeTypes());
}
public function getCustomerTypes($return = 'array')
{
return $this->getContactTypes('customer', $return);
@ -28,6 +35,11 @@ trait Contacts
return $this->getContactTypes('vendor', $return);
}
public function getEmployeeTypes($return = 'array')
{
return $this->getContactTypes('employee', $return);
}
public function getContactTypes($index, $return = 'array')
{
$types = (string) setting('contact.type.' . $index);
@ -45,6 +57,11 @@ trait Contacts
$this->addContactType($new_type, 'vendor');
}
public function addEmployeeType($new_type)
{
$this->addContactType($new_type, 'employee');
}
public function addContactType($new_type, $index)
{
$types = explode(',', setting('contact.type.' . $index));

View File

@ -171,6 +171,7 @@ return [
'type' => [
'customer' => env('SETTING_FALLBACK_CONTACT_TYPE_CUSTOMER', Contact::CUSTOMER_TYPE),
'vendor' => env('SETTING_FALLBACK_CONTACT_TYPE_VENDOR', Contact::VENDOR_TYPE),
'employee' => env('SETTING_FALLBACK_CONTACT_TYPE_EMPLOYEE', Contact::EMPLOYEE_TYPE),
],
],
'transaction' => [

View File

@ -72,6 +72,7 @@ return [
'attachments' => 'Attachment|Attachments',
'histories' => 'History|Histories',
'your_notifications' => 'Your notification|Your notifications',
'employees' => 'Employee|Employees',
'welcome' => 'Welcome',
'banking' => 'Banking',

View File

@ -63,6 +63,17 @@ return [
],
'email' => [
'invalid' => [
'title' => 'Invalid :type Email',
'description' => '<strong>:email</strong> email address has been reported as invalid and the person has been disabled. Please check the following error message and fix the email address:',
],
],
'menu' => [
'export_completed' => [
@ -177,6 +188,13 @@ return [
],
'invalid_email' => [
'title' => 'Invalid :type Email',
'description' => '<strong>:email</strong> email address has been reported as invalid and the person has been disabled. Please check and fix the email address.',
],
],
'messages' => [