diff --git a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php index 33c77fb2..6ecdbfca 100644 --- a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php @@ -12,12 +12,20 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Component; use CachetHQ\Cachet\Bus\Events\Component\ComponentStatusWasChangedEvent; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Notifications\Component\ComponentStatusChangedNotification; class SendComponentUpdateEmailNotificationHandler { + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * The subscriber instance. * @@ -32,8 +40,9 @@ class SendComponentUpdateEmailNotificationHandler * * @return void */ - public function __construct(Subscriber $subscriber) + public function __construct(System $system, Subscriber $subscriber) { + $this->system = $system; $this->subscriber = $subscriber; } @@ -48,8 +57,8 @@ class SendComponentUpdateEmailNotificationHandler { $component = $event->component; - // If we're silent, then don't send this. - if ($event->silent) { + // If we're silent or the notifications are suppressed don't send this. + if ($event->silent || !$this->system->canNotifySubscribers()) { return; } diff --git a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php index b85b8fc8..d30916d1 100644 --- a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php @@ -12,11 +12,19 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Incident; use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasCreatedEvent; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Notifications\Incident\NewIncidentNotification; class SendIncidentEmailNotificationHandler { + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * The subscriber instance. * @@ -27,12 +35,14 @@ class SendIncidentEmailNotificationHandler /** * Create a new send incident email notification handler. * - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * @param \CachetHQ\Cachet\Integrations\Contracts\System $system + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber * * @return void */ - public function __construct(Subscriber $subscriber) + public function __construct(System $system, Subscriber $subscriber) { + $this->system = $system; $this->subscriber = $subscriber; } @@ -47,7 +57,7 @@ class SendIncidentEmailNotificationHandler { $incident = $event->incident; - if (!$event->notify) { + if (!$event->notify || !$this->system->canNotifySubscribers()) { return false; } diff --git a/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php b/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php index 7b392200..44760481 100644 --- a/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php @@ -12,11 +12,19 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\IncidentUpdate; use CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasReportedEvent; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Notifications\IncidentUpdate\IncidentUpdatedNotification; class SendIncidentUpdateEmailNotificationHandler { + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * The subscriber instance. * @@ -27,12 +35,14 @@ class SendIncidentUpdateEmailNotificationHandler /** * Create a new send incident email notification handler. * - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * @param \CachetHQ\Cachet\Integrations\Contracts\System $system + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber * * @return void */ - public function __construct(Subscriber $subscriber) + public function __construct(System $system, Subscriber $subscriber) { + $this->system = $system; $this->subscriber = $subscriber; } @@ -48,8 +58,8 @@ class SendIncidentUpdateEmailNotificationHandler $update = $event->update; $incident = $update->incident; - // Only send emails for public incidents. - if (!$incident->visible) { + // Only send emails for public incidents while the system is not under scheduled maintenance. + if (!$incident->visible || !$this->system->canNotifySubscribers()) { return; } diff --git a/app/Http/Controllers/Dashboard/IncidentController.php b/app/Http/Controllers/Dashboard/IncidentController.php index 94494386..3822a812 100644 --- a/app/Http/Controllers/Dashboard/IncidentController.php +++ b/app/Http/Controllers/Dashboard/IncidentController.php @@ -17,6 +17,7 @@ use CachetHQ\Cachet\Bus\Commands\Incident\RemoveIncidentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand; use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\CreateIncidentUpdateCommand; use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Incident; @@ -48,6 +49,13 @@ class IncidentController extends Controller */ protected $auth; + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * Creates a new incident controller instance. * @@ -55,9 +63,10 @@ class IncidentController extends Controller * * @return void */ - public function __construct(Guard $auth) + public function __construct(Guard $auth, System $system) { $this->auth = $auth; + $this->system = $system; View::share('sub_title', trans('dashboard.incidents.title')); } @@ -87,6 +96,7 @@ class IncidentController extends Controller ->withPageTitle(trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard')) ->withComponentsInGroups(ComponentGroup::with('components')->get()) ->withComponentsOutGroups(Component::where('group_id', '=', 0)->get()) + ->withNotificationsEnabled($this->system->canNotifySubscribers()) ->withIncidentTemplates(IncidentTemplate::all()); } @@ -225,7 +235,8 @@ class IncidentController extends Controller ->withPageTitle(trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard')) ->withIncident($incident) ->withComponentsInGroups(ComponentGroup::with('components')->get()) - ->withComponentsOutGroups(Component::where('group_id', '=', 0)->get()); + ->withComponentsOutGroups(Component::where('group_id', '=', 0)->get()) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); } /** @@ -309,7 +320,9 @@ class IncidentController extends Controller */ public function showCreateIncidentUpdateAction(Incident $incident) { - return View::make('dashboard.incidents.updates.add')->withIncident($incident); + return View::make('dashboard.incidents.updates.add') + ->withIncident($incident) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); } /** @@ -351,7 +364,8 @@ class IncidentController extends Controller { return View::make('dashboard.incidents.updates.edit') ->withIncident($incident) - ->withUpdate($incidentUpdate); + ->withUpdate($incidentUpdate) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); } /** diff --git a/app/Integrations/Contracts/System.php b/app/Integrations/Contracts/System.php index 385ad501..a064e710 100644 --- a/app/Integrations/Contracts/System.php +++ b/app/Integrations/Contracts/System.php @@ -25,6 +25,13 @@ interface System */ public function getStatus(); + /** + * Determine if Cachet is allowed to send notifications to users, subscribers or third party tools. + * + * @return bool + */ + public function canNotifySubscribers(); + /** * Get the cachet version. * diff --git a/app/Integrations/Core/System.php b/app/Integrations/Core/System.php index ccf5bb0c..87afeafc 100644 --- a/app/Integrations/Core/System.php +++ b/app/Integrations/Core/System.php @@ -14,6 +14,7 @@ namespace CachetHQ\Cachet\Integrations\Core; use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; +use CachetHQ\Cachet\Models\Schedule; use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Config\Repository; @@ -102,6 +103,21 @@ class System implements SystemContract return $status; } + /** + * Determine if Cachet is allowed to send notifications to users, subscribers or third party tools. + * + * @return bool + */ + public function canNotifySubscribers() + { + $maintenancePeriods = Schedule::inProgress()->count(); + if ($maintenancePeriods === 0) { + return true; + } + + return !$this->config->get('setting.suppress_notifications_in_maintenance'); + } + /** * Get the cachet version. * diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index 46b57389..6202952b 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -16,6 +16,7 @@ use CachetHQ\Cachet\Models\Traits\SearchableTrait; use CachetHQ\Cachet\Models\Traits\SortableTrait; use CachetHQ\Cachet\Presenters\SchedulePresenter; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use McCool\LaravelAutoPresenter\HasPresenter; @@ -151,6 +152,20 @@ class Schedule extends Model implements HasPresenter return $this->morphMany(Meta::class, 'meta'); } + /** + * Scope schedules that are in progress. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeInProgress(Builder $query) + { + return $query->where('scheduled_at', '<=', Carbon::now())->where('status', '!=', self::COMPLETE)->where(function ($query) { + $query->whereNull('completed_at')->orWhere('completed_at', '>', Carbon::now()); + }); + } + /** * Scopes schedules to those in the future. * diff --git a/config/setting.php b/config/setting.php index e438690a..4f58d404 100644 --- a/config/setting.php +++ b/config/setting.php @@ -33,6 +33,18 @@ return [ 'enable_subscribers' => true, + /* + |-------------------------------------------------------------------------- + | Suppress notifications while in maintenance + |-------------------------------------------------------------------------- + | + | Whether to suppress notification channels if an issue is created during + | planned or in-progress maintenance periods. + | + */ + + 'suppress_notifications_in_maintenance' => true, + /* |-------------------------------------------------------------------------- | Automatic Localization diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index 3d4523b0..cb1ed400 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -54,6 +54,7 @@ return [ 'message-help' => 'You may also use Markdown.', 'occurred_at' => 'When did this incident occur?', 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', 'visibility' => 'Incident Visibility', 'stick_status' => 'Stick Incident', 'stickied' => 'Stickied', @@ -147,20 +148,21 @@ return [ 'settings' => [ // Application setup 'app-setup' => [ - 'site-name' => 'Site Name', - 'site-url' => 'Site URL', - 'display-graphs' => 'Display graphs on status page?', - 'about-this-page' => 'About this page', - 'days-of-incidents' => 'How many days of incidents to show?', - 'time_before_refresh' => 'Status page refresh rate (in seconds).', - 'banner' => 'Banner Image', - 'banner-help' => "It's recommended that you upload files no bigger than 930px wide .", - 'subscribers' => 'Allow people to signup to email notifications?', - 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', - 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', - 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', - 'show_timezone' => 'Show the timezone the status page is running in.', - 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds).', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide .", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in.', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', ], 'analytics' => [ 'analytics_google' => 'Google Analytics code', diff --git a/resources/views/dashboard/incidents/add.blade.php b/resources/views/dashboard/incidents/add.blade.php index fb3891a9..eb758484 100644 --- a/resources/views/dashboard/incidents/add.blade.php +++ b/resources/views/dashboard/incidents/add.blade.php @@ -13,6 +13,11 @@