Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/Events/CheckoutableCheckedOut.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Events;

use App\Models\CheckoutAcceptance;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
Expand All @@ -24,6 +25,13 @@ class CheckoutableCheckedOut

public bool $signInPlace;

/**
* Set by whichever notification listener (email or webhook) creates the
* CheckoutAcceptance first, so the other listener reuses it instead of
* creating a duplicate row for the same checkout.
*/
public ?CheckoutAcceptance $checkoutAcceptance = null;

/**
* Create a new event instance.
*
Expand Down
106 changes: 106 additions & 0 deletions app/Listeners/CheckoutableCheckedInEmailNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace App\Listeners;

use App\Events\CheckoutableCheckedIn;
use App\Mail\CheckinAccessoryMail;
use App\Mail\CheckinAssetMail;
use App\Mail\CheckinComponentMail;
use App\Mail\CheckinLicenseMail;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Component;
use App\Models\LicenseSeat;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\CheckinAccessoryNotification;
use App\Notifications\CheckinAssetNotification;
use App\Notifications\CheckinComponentNotification;
use App\Notifications\CheckinLicenseSeatNotification;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Notifications\Notification as BaseNotification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Osama\LaravelTeamsNotification\TeamsNotification;

class CheckoutableCheckedInEmailNotification extends CheckInOutNotificationsBase

Check warning on line 28 in app/Listeners/CheckoutableCheckedInEmailNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedInEmailNotification.php#L28

The class CheckoutableCheckedInEmailNotification has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
{
public function handle(CheckoutableCheckedIn $event)

Check warning on line 30 in app/Listeners/CheckoutableCheckedInEmailNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedInEmailNotification.php#L30

The method handle() has an NPath complexity of 492. The configured NPath complexity threshold is 200.
{
if ($this->shouldNotSendAnyNotifications($event->checkoutable)) {
return;
}

$shouldSendEmailToUser = $this->checkoutableCategoryShouldSendEmail($event->checkoutable);
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress();
if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress) {
return;
}

if ($shouldSendEmailToUser || $shouldSendEmailToAlertAddress) {
/**
* Send the appropriate notification
*/
if ($event->checkedOutTo && $event->checkoutable) {
$acceptances = CheckoutAcceptance::where('checkoutable_id', $event->checkoutable->id)
->where('assigned_to_id', $event->checkedOutTo->id)
->get();

foreach ($acceptances as $acceptance) {
if ($acceptance->isPending()) {
$acceptance->delete();
}
}
}

$mailable = $this->getCheckinMailType($event);
$notifiable = $this->getNotifiableUser($event);

$notifiableHasEmail = $notifiable instanceof User && $notifiable->email;

$shouldSendEmailToUser = $shouldSendEmailToUser && $notifiableHasEmail;

[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);

if (!empty($to)) {
try {
$toMail = (clone $mailable)->locale($notifiable->locale);
Mail::to(array_flatten($to))->send($toMail);
Log::info('Checkin Mail sent to checkin target');
} catch (ClientException $e) {
Log::debug('Exception caught during checkin email: ' . $e->getMessage());
} catch (Exception $e) {
Log::debug('Exception caught during checkin email: ' . $e->getMessage());
}
}
if (!empty($cc)) {
try {
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
Mail::cc(array_flatten($cc))->send($ccMail);
} catch (ClientException $e) {
Log::debug('Exception caught during checkin email: ' . $e->getMessage());
} catch (Exception $e) {
Log::debug('Exception caught during checkin email: ' . $e->getMessage());
}
}
}
}

protected function getCheckinMailType($event)
{
$lookup = [
Accessory::class => CheckinAccessoryMail::class,
Asset::class => CheckinAssetMail::class,
LicenseSeat::class => CheckinLicenseMail::class,
Component::class => CheckinComponentMail::class,
];
$mailable = $lookup[get_class($event->checkoutable)];

return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);

}


}
111 changes: 111 additions & 0 deletions app/Listeners/CheckoutableCheckedInWebhookNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

namespace App\Listeners;

use App\Events\CheckoutableCheckedIn;
use App\Mail\CheckinAccessoryMail;
use App\Mail\CheckinAssetMail;
use App\Mail\CheckinComponentMail;
use App\Mail\CheckinLicenseMail;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\Component;
use App\Models\LicenseSeat;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\CheckinAccessoryNotification;
use App\Notifications\CheckinAssetNotification;
use App\Notifications\CheckinComponentNotification;
use App\Notifications\CheckinLicenseSeatNotification;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Notifications\Notification as BaseNotification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Osama\LaravelTeamsNotification\TeamsNotification;

class CheckoutableCheckedInWebhookNotification extends CheckInOutNotificationsBase

Check warning on line 28 in app/Listeners/CheckoutableCheckedInWebhookNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedInWebhookNotification.php#L28

The class CheckoutableCheckedInWebhookNotification has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
{
public function handle(CheckoutableCheckedIn $event)
{
Log::debug('CheckoutableCheckedInWebhookNotification fired');

if ($this->shouldNotSendAnyNotifications($event->checkoutable)) {
return;
}

$shouldSendWebhookNotification = $this->shouldSendWebhookNotification();

if ($shouldSendWebhookNotification) {
// Send Webhook notification
try {
if ($this->newMicrosoftTeamsWebhookEnabled()) {
$message = $this->getCheckinNotification($event, true)->toMicrosoftTeams();
$notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
$notification->success()->sendMessage($message[0], $message[1]); // Send the message to Microsoft Teams
} else {

Check notice on line 47 in app/Listeners/CheckoutableCheckedInWebhookNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedInWebhookNotification.php#L47

The method handle uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
Notification::route($this->webhookSelected(), Setting::getSettings()->webhook_endpoint)
->notify($this->getCheckinNotification($event, true));
}
} catch (ClientException $e) {
$status = $e->getResponse()->getStatusCode();

if (strpos($e->getMessage(), 'channel_not_found') !== false) {
Log::warning(Setting::getSettings()->webhook_selected . ' notification failed: ' . $e->getMessage());

return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_channel_not_found'));
} else {
if ($status >= 500 || $status === null) {
Log::error(Setting::getSettings()->webhook_selected . ' notification failed: ' . $e->getMessage());
} else {
Log::warning('ClientException caught during checkin notification: ' . $e->getMessage());

return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
}
}
} catch (Exception $e) {
Log::warning(ucfirst(Setting::getSettings()->webhook_selected) . ' webhook notification failed:', [
'error' => $e->getMessage(),
'webhook_endpoint' => Setting::getSettings()->webhook_endpoint,
'event' => $event,
]);

return redirect()->back()->with('warning', ucfirst(Setting::getSettings()->webhook_selected) . trans('admin/settings/message.webhook.webhook_fail'));
}
}
}

/**
* Get the appropriate notification for the event
*
* @param CheckoutableCheckedIn $event
* @return Notification
*/
protected function getCheckinNotification($event, bool $refreshCheckoutable = false): BaseNotification
{
$notificationClass = null;
$checkoutable = $this->getCheckoutableForNotification($event->checkoutable, $refreshCheckoutable);

switch (get_class($checkoutable)) {
case Accessory::class:
$notificationClass = CheckinAccessoryNotification::class;
break;
case Asset::class:
$notificationClass = CheckinAssetNotification::class;
break;
case LicenseSeat::class:
$notificationClass = CheckinLicenseSeatNotification::class;
break;
case Component::class:
$notificationClass = CheckinComponentNotification::class;
break;
}

Log::debug('Notification class: ' . $notificationClass);

return new $notificationClass($checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
}


}
142 changes: 142 additions & 0 deletions app/Listeners/CheckoutableCheckedOutEmailNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

namespace App\Listeners;

use App\Actions\Acceptances\CreateCheckoutAcceptanceAction;
use App\Events\CheckoutableCheckedOut;
use App\Mail\CheckoutAccessoryMail;
use App\Mail\CheckoutAssetMail;
use App\Mail\CheckoutComponentMail;
use App\Mail\CheckoutConsumableMail;
use App\Mail\CheckoutLicenseMail;
use App\Models\Accessory;
use App\Models\Asset;
use App\Models\Category;
use App\Models\CheckoutAcceptance;
use App\Models\Component;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\CheckoutAccessoryNotification;
use App\Notifications\CheckoutAssetNotification;
use App\Notifications\CheckoutComponentNotification;
use App\Notifications\CheckoutConsumableNotification;
use App\Notifications\CheckoutLicenseSeatNotification;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notification as BaseNotification;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Osama\LaravelTeamsNotification\TeamsNotification;

class CheckoutableCheckedOutEmailNotification extends CheckInOutNotificationsBase

Check warning on line 35 in app/Listeners/CheckoutableCheckedOutEmailNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedOutEmailNotification.php#L35

The class CheckoutableCheckedOutEmailNotification has a coupling between objects value of 19. Consider to reduce the number of dependencies under 13.
{
public function handle(CheckoutableCheckedOut $event)

Check warning on line 37 in app/Listeners/CheckoutableCheckedOutEmailNotification.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/Listeners/CheckoutableCheckedOutEmailNotification.php#L37

The method handle() has an NPath complexity of 216. The configured NPath complexity threshold is 200.
{
if ($this->shouldNotSendAnyNotifications($event->checkoutable)) {
return;
}

$acceptance = $this->getCheckoutAcceptance($event);

$shouldSendEmailToUser = $this->shouldSendCheckoutEmailToUser($event->checkoutable);
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress($acceptance);

if ($this->shouldSkipInitialAcceptanceEmail($event, $acceptance)) {
$shouldSendEmailToUser = false;
$shouldSendEmailToAlertAddress = false;
}

if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress) {
return;
}

if ($shouldSendEmailToUser || $shouldSendEmailToAlertAddress) {
$mailable = $this->getCheckoutMailType($event, $acceptance);
$notifiable = $this->getNotifiableUser($event);

$notifiableHasEmail = $notifiable instanceof User && $notifiable->email;

$shouldSendEmailToUser = $shouldSendEmailToUser && $notifiableHasEmail;

[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);

if (!empty($to)) {
try {
$toMail = (clone $mailable)->locale($notifiable->locale);
Mail::to(array_flatten($to))->send($toMail);
Log::info('Checkout Mail sent to checkout target');
} catch (ClientException $e) {
Log::debug('Exception caught during checkout email: ' . $e->getMessage());
} catch (Exception $e) {
Log::debug('Exception caught during checkout email: ' . $e->getMessage());
}
}
if (!empty($cc)) {
try {
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
Mail::cc(array_flatten($cc))->send($ccMail);
} catch (ClientException $e) {
Log::debug('Exception caught during checkout email: ' . $e->getMessage());
} catch (Exception $e) {
Log::debug('Exception caught during checkout email: ' . $e->getMessage());
}
}
}
}

/**
* Generates a checkout acceptance
*
* @param Event $event
* @return mixed
*/

protected function getCheckoutMailType($event, $acceptance)
{
$lookup = [
Accessory::class => CheckoutAccessoryMail::class,
Asset::class => CheckoutAssetMail::class,
LicenseSeat::class => CheckoutLicenseMail::class,
Consumable::class => CheckoutConsumableMail::class,
Component::class => CheckoutComponentMail::class,
];
$mailable = $lookup[get_class($event->checkoutable)];

return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedOutBy, $acceptance, $event->note);

}

protected function shouldSendCheckoutEmailToUser(Model $checkoutable): bool
{
/**
* Send an email if we didn't get here from a bulk checkout
* and any of the following conditions are met:
* 1. The asset requires acceptance
* 2. The item has a EULA
* 3. The item should send an email at check-in/check-out
*/
if (Context::get('action') === 'bulk_asset_checkout') {
return false;
}

if ($checkoutable->requireAcceptance()) {
return true;
}

if ($checkoutable->getEula()) {
return true;
}

if ($this->checkoutableCategoryShouldSendEmail($checkoutable)) {
return true;
}

return false;
}


}
Loading
Loading