diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php index 7c81a37d3a..ba84625ad2 100644 --- a/app/Console/Commands/SendUpcomingAuditReport.php +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -2,13 +2,12 @@ namespace App\Console\Commands; +use App\Mail\SendUpcomingAuditMail; use App\Models\Asset; -use App\Models\Recipients\AlertRecipient; use App\Models\Setting; -use App\Notifications\SendUpcomingAuditNotification; use Carbon\Carbon; -use Illuminate\Support\Facades\DB; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Mail; class SendUpcomingAuditReport extends Command { @@ -48,19 +47,19 @@ class SendUpcomingAuditReport extends Command $today = Carbon::now(); $interval_date = $today->copy()->addDays($interval); - $assets = Asset::whereNull('deleted_at')->DueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get(); - $this->info($assets->count().' assets must be audited in on or before '.$interval_date.' is deadline'); + $assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get(); + $this->info($assets->count() . ' assets must be audited in on or before ' . $interval_date . ' is deadline'); - if (($assets) && ($assets->count() > 0) && ($settings->alert_email != '')) { + if ((count($assets) !== 0) && ($assets->count() > 0) && ($settings->alert_email != '')) { // Send a rollup to the admin, if settings dictate - $recipients = collect(explode(',', $settings->alert_email))->map(function ($item) { - return new AlertRecipient($item); - }); + $recipients = collect(explode(',', $settings->alert_email)) + ->map(fn($item) => trim($item)) + ->all(); - $this->info('Sending Admin SendUpcomingAuditNotification to: '.$settings->alert_email); - \Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days)); + $this->info('Sending Admin SendUpcomingAuditNotification to: ' . $settings->alert_email); + Mail::to($recipients)->send(new SendUpcomingAuditMail($assets, $settings->audit_warning_days)); } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 8d512f303b..664c8edc62 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -5,6 +5,7 @@ namespace App\Console; use App\Console\Commands\ImportLocations; use App\Console\Commands\ReEncodeCustomFieldNames; use App\Console\Commands\RestoreDeletedUsers; +use App\Models\Setting; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -18,12 +19,14 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - $schedule->command('snipeit:inventory-alerts')->daily(); - $schedule->command('snipeit:expiring-alerts')->daily(); - $schedule->command('snipeit:expected-checkin')->daily(); + if(Setting::getSettings()->alerts_enabled === 1) { + $schedule->command('snipeit:inventory-alerts')->daily(); + $schedule->command('snipeit:expiring-alerts')->daily(); + $schedule->command('snipeit:expected-checkin')->daily(); + $schedule->command('snipeit:upcoming-audits')->daily(); + } $schedule->command('snipeit:backup')->weekly(); $schedule->command('backup:clean')->daily(); - $schedule->command('snipeit:upcoming-audits')->daily(); $schedule->command('auth:clear-resets')->everyFifteenMinutes(); $schedule->command('saml:clear_expired_nonces')->weekly(); } diff --git a/app/Mail/SendUpcomingAuditMail.php b/app/Mail/SendUpcomingAuditMail.php new file mode 100644 index 0000000000..03faa081eb --- /dev/null +++ b/app/Mail/SendUpcomingAuditMail.php @@ -0,0 +1,65 @@ +assets = $params; + $this->threshold = $threshold; + } + + /** + * Get the message envelope. + */ + public function envelope(): Envelope + { + $from = new Address(config('mail.from.address'), config('mail.from.name')); + + return new Envelope( + from: $from, + subject: trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count(), 'threshold' => $this->threshold]), + ); + } + + /** + * Get the message content definition. + */ + public function content(): Content + { + + + return new Content( + + markdown: 'notifications.markdown.upcoming-audits', + with: [ + 'assets' => $this->assets, + 'threshold' => $this->threshold, + ], + ); + } + + /** + * Get the attachments for the message. + * + * @return array + */ + public function attachments(): array + { + return []; + } +} diff --git a/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php b/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php index 220f6543c8..5bc034ba5a 100644 --- a/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php +++ b/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Notifications\Email; use App\Mail\ExpiringAssetsMail; use App\Mail\ExpiringLicenseMail; +use App\Mail\SendUpcomingAuditMail; use App\Models\Asset; use App\Models\License; use App\Models\Setting; @@ -88,4 +89,38 @@ class ExpiringAlertsNotificationTest extends TestCase return $mail->licenses->contains($expiredLicense) || $mail->licenses->contains($notExpiringLicense); }); } + + public function testAuditWarningThresholdEmailNotification() + { + $this->markIncompleteIfSqlite(); + Mail::fake(); + $this->settings->enableAlertEmail('admin@example.com'); + $this->settings->setAuditWarningDays(15); + + $alert_email = Setting::first()->alert_email; + + $upcomingAuditableAsset = Asset::factory()->create([ + 'next_audit_date' => now()->addDays(14)->format('Y-m-d'), + 'deleted_at' => null, + ]); + + $overDueForAuditableAsset = Asset::factory()->create([ + 'next_audit_date' => now()->subDays(1)->format('Y-m-d'), + 'deleted_at' => null, + ]); + + $notAuditableAsset = Asset::factory()->create([ + 'next_audit_date' => now()->addDays(30)->format('Y-m-d'), + 'deleted_at' => null, + ]); + + $this->artisan('snipeit:upcoming-audits')->assertExitCode(0); + + Mail::assertSent(SendUpcomingAuditMail::class, function($mail) use ($alert_email, $upcomingAuditableAsset, $overDueForAuditableAsset) { + return $mail->hasTo($alert_email) && ($mail->assets->contains($upcomingAuditableAsset) && $mail->assets->contains($overDueForAuditableAsset)); + }); + Mail::assertNotSent(SendUpcomingAuditMail::class, function($mail) use ($alert_email, $notAuditableAsset) { + return $mail->hasTo($alert_email) && $mail->assets->contains($notAuditableAsset); + }); + } } \ No newline at end of file diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 09d40974c1..8680d1c3b1 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -32,6 +32,12 @@ class Settings 'alert_threshold' => $days, ]); } + public function setAuditWarningDays(int $days): Settings + { + return $this->update([ + 'audit_warning_days' => $days, + ]); + } public function disableAlertEmail(): Settings { return $this->update([