diff --git a/app/Bus/Commands/Subscriber/SubscribeSubscriberCommand.php b/app/Bus/Commands/Subscriber/SubscribeSubscriberCommand.php index b7be8986..a9e7b55f 100644 --- a/app/Bus/Commands/Subscriber/SubscribeSubscriberCommand.php +++ b/app/Bus/Commands/Subscriber/SubscribeSubscriberCommand.php @@ -32,13 +32,6 @@ final class SubscribeSubscriberCommand */ public $verified; - /** - * The subscriptions that we want to add. - * - * @var array|null - */ - public $subscriptions; - /** * The validation rules. * @@ -53,14 +46,12 @@ final class SubscribeSubscriberCommand * * @param string $email * @param bool $verified - * @param null|array $subscriptions * * @return void */ - public function __construct($email, $verified = false, $subscriptions = null) + public function __construct($email, $verified = false) { $this->email = $email; $this->verified = $verified; - $this->subscriptions = $subscriptions; } } diff --git a/app/Bus/Commands/Subscriber/UpdateSubscriberSubscriptionCommand.php b/app/Bus/Commands/Subscriber/UpdateSubscriberSubscriptionCommand.php new file mode 100644 index 00000000..a1b5a338 --- /dev/null +++ b/app/Bus/Commands/Subscriber/UpdateSubscriberSubscriptionCommand.php @@ -0,0 +1,50 @@ + + */ +final class UpdateSubscriberSubscriptionCommand +{ + /** + * The subscriber email. + * + * @var \CachetHQ\Cachet\Models\Subscriber + */ + public $subscriber; + + /** + * The subscriptions that we want to add. + * + * @var array|null + */ + public $subscriptions; + + /** + * Create a new subscribe subscriber command instance. + * + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * @param null|array $subscriptions + * + * @return void + */ + public function __construct($subscriber, $subscriptions = null) + { + $this->subscriber = $subscriber; + $this->subscriptions = $subscriptions; + } +} diff --git a/app/Bus/Exceptions/Subscriber/AlreadySubscribedException.php b/app/Bus/Exceptions/Subscriber/AlreadySubscribedException.php deleted file mode 100644 index 8e88578c..00000000 --- a/app/Bus/Exceptions/Subscriber/AlreadySubscribedException.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @author James Brooks - */ -class AlreadySubscribedException extends Exception implements ExceptionInterface -{ - // -} diff --git a/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php index 309d79c0..46f9e2ce 100644 --- a/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php +++ b/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php @@ -14,8 +14,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Subscriber; use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand; use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasSubscribedEvent; -use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUpdatedSubscriptionsEvent; -use CachetHQ\Cachet\Bus\Exceptions\Subscriber\AlreadySubscribedException; +use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Subscription; @@ -31,35 +30,27 @@ class SubscribeSubscriberCommandHandler * * @param \CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand $command * - * @throws \CachetHQ\Cachet\Exceptions\AlreadySubscribedException - * * @return \CachetHQ\Cachet\Models\Subscriber */ public function handle(SubscribeSubscriberCommand $command) { - if (Subscriber::where('email', $command->email)->first() && $command->subscriptions === null) { - throw new AlreadySubscribedException("Cannot subscribe {$command->email} because they're already subscribed."); + if ($subscriber = Subscriber::where('email', $command->email)->first()) { + return $subscriber; } $subscriber = Subscriber::firstOrCreate(['email' => $command->email]); - if ($subscriptions = $command->subscriptions) { - foreach ($subscriptions as $subscription => $subscriptionValue) { - Subscription::firstOrCreate([ - 'subscriber_id' => $subscriber->id, - $subscription => $subscriptionValue, - ]); - } + foreach (Component::all() as $component) { + Subscription::create([ + 'subscriber_id' => $subscriber->id, + 'component_id' => $component->id, + ]); } - if ($subscriber->is_verified === false) { - if ($command->verified) { - dispatch(new VerifySubscriberCommand($subscriber)); - } else { - event(new SubscriberHasSubscribedEvent($subscriber)); - } + if ($command->verified) { + dispatch(new VerifySubscriberCommand($subscriber)); } else { - event(new SubscriberHasUpdatedSubscriptionsEvent($subscriber)); + event(new SubscriberHasSubscribedEvent($subscriber)); } return $subscriber; diff --git a/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php new file mode 100644 index 00000000..6ac9d2c0 --- /dev/null +++ b/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php @@ -0,0 +1,64 @@ + + */ +class UpdateSubscriberSubscriptionCommandHandler +{ + /** + * Handle the subscribe subscriber command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand $command + * + * @return \CachetHQ\Cachet\Models\Subscriber + */ + public function handle(UpdateSubscriberSubscriptionCommand $command) + { + $subscriber = $command->subscriber; + $subscriptions = $command->subscriptions ?: []; + + $components = Component::all(); + + $updateSubscriptions = $components->filter(function ($item) use ($subscriptions) { + return in_array($item->id, $subscriptions); + }); + + $subscriber->global = ($updateSubscriptions->count() === $components->count()); + + $subscriber->subscriptions()->delete(); + + if (!$updateSubscriptions->isEmpty()) { + foreach ($updateSubscriptions as $subscription) { + Subscription::firstOrCreate([ + 'subscriber_id' => $subscriber->id, + 'component_id' => $subscription->id, + ]); + } + } + + $subscriber->save(); + + event(new SubscriberHasUpdatedSubscriptionsEvent($subscriber)); + + return $subscriber; + } +} diff --git a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php index 695b351a..960e32db 100644 --- a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php @@ -12,8 +12,8 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Component; use CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent; +use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Component; -use CachetHQ\Cachet\Models\Subscription; use Illuminate\Contracts\Mail\MailQueue; use Illuminate\Mail\Message; use McCool\LaravelAutoPresenter\Facades\AutoPresenter; @@ -27,16 +27,25 @@ class SendComponentUpdateEmailNotificationHandler */ protected $mailer; + /** + * The subscriber instance. + * + * @var \CachetHQ\Cachet\Models\Subscriber + */ + protected $subscriber; + /** * Create a new send incident email notification handler. * * @param \Illuminate\Contracts\Mail\Mailer $mailer + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber * * @return void */ - public function __construct(MailQueue $mailer) + public function __construct(MailQueue $mailer, Subscriber $subscriber) { $this->mailer = $mailer; + $this->subscriber = $subscriber; } /** @@ -50,24 +59,53 @@ class SendComponentUpdateEmailNotificationHandler { $component = AutoPresenter::decorate($event->component); + // First notify all global subscribers. + $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); + + foreach ($globalSubscribers as $subscriber) { + $this->notify($event, $subscriber); + } + + $notified = $globalSubscribers->pluck('id')->all(); + + // Notify the remaining component specific subscribers. + $componentSubscribers = $this->subscriber + ->isVerified() + ->forComponent($component->id) + ->get() + ->reject(function ($subscriber) use ($notified) { + return in_array($subscriber->id, $notified); + }); + + foreach ($componentSubscribers as $subscriber) { + $this->notify($event, $subscriber); + } + } + + /** + * Send notification to subscriber. + * + * @param \CachetHQ\Cachet\Bus\Events\ComponentWasUpdatedEvent $event + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function notify(ComponentWasUpdatedEvent $event, $subscriber) + { $mail = [ 'subject' => trans('cachet.subscriber.email.component.subject'), 'component_name' => $component->name, 'component_human_status' => $component->human_status, ]; - foreach (Subscription::isVerifiedForComponent($component->id)->with('subscriber')->get() as $subscription) { - $subscriber = $subscription->subscriber; - $mail['email'] = $subscriber->email; - $mail['manage_link'] = route('subscribe.manage', ['code' => $subscriber->verify_code]); - $mail['unsubscribe_link'] = route('subscribe.unsubscribe', ['code' => $subscriber->verify_code, 'subscription' => $subscription->id]); + $mail['email'] = $subscriber->email; + $mail['manage_link'] = route('subscribe.manage', ['code' => $subscriber->verify_code]); - $this->mailer->queue([ - 'html' => 'emails.components.update-html', - 'text' => 'emails.components.update-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); - } + $this->mailer->queue([ + 'html' => 'emails.components.update-html', + 'text' => 'emails.components.update-text', + ], $mail, function (Message $message) use ($mail) { + $message->to($mail['email'])->subject($mail['subject']); + }); } } diff --git a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php index 177b910a..f55c263d 100644 --- a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php @@ -50,7 +50,7 @@ class SendIncidentEmailNotificationHandler /** * Handle the event. * - * @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentHasReportedEvent $event + * @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent $event * * @return void */ @@ -60,32 +60,69 @@ class SendIncidentEmailNotificationHandler return false; } + // Only send emails for public incidents. + if ($event->incident->visible === 0) { + return; + } + + // First notify all global subscribers. + $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); + + foreach ($globalSubscribers as $subscriber) { + $this->notify($event, $subscriber); + } + + if (!$event->incident->component) { + return; + } + + $notified = $globalSubscribers->pluck('id')->all(); + + // Notify the remaining component specific subscribers. + $componentSubscribers = $this->subscriber + ->isVerified() + ->forComponent($event->incident->component->id) + ->get() + ->reject(function ($subscriber) use ($notified) { + return in_array($subscriber->id, $notified); + }); + + foreach ($componentSubscribers as $subscriber) { + $this->notify($event, $subscriber); + } + } + + /** + * Send notification to subscriber. + * + * @param \CachetHQ\Cachet\Bus\Events\IncidentWasReportedEvent $event + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function notify(IncidentWasReportedEvent $event, $subscriber) + { $incident = AutoPresenter::decorate($event->incident); $component = AutoPresenter::decorate($event->incident->component); - // Only send emails for public incidents. - if ($event->incident->visible === 1) { - foreach ($this->subscriber->isVerified()->get() as $subscriber) { - $mail = [ - 'email' => $subscriber->email, - 'subject' => 'New incident reported.', - 'has_component' => ($event->incident->component) ? true : false, - 'component_name' => $component ? $component->name : null, - 'status' => $incident->human_status, - 'html_content' => $incident->formattedMessage, - 'text_content' => $incident->message, - 'token' => $subscriber->token, - 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), - 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), - ]; + $mail = [ + 'email' => $subscriber->email, + 'subject' => 'New incident reported.', + 'has_component' => ($event->incident->component) ? true : false, + 'component_name' => $component ? $component->name : null, + 'status' => $incident->human_status, + 'html_content' => $incident->formattedMessage, + 'text_content' => $incident->message, + 'token' => $subscriber->token, + 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), + 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), + ]; - $this->mailer->queue([ - 'html' => 'emails.incidents.new-html', - 'text' => 'emails.incidents.new-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); - } - } + $this->mailer->queue([ + 'html' => 'emails.incidents.new-html', + 'text' => 'emails.incidents.new-text', + ], $mail, function (Message $message) use ($mail) { + $message->to($mail['email'])->subject($mail['subject']); + }); } } diff --git a/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php index f3e51c00..7d9d9708 100644 --- a/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php @@ -50,7 +50,7 @@ class SendMaintenanceEmailNotificationHandler /** * Handle the event. * - * @param \CachetHQ\Cachet\Bus\Events\MaintenanceHasScheduledEvent $event + * @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event * * @return void */ @@ -60,27 +60,69 @@ class SendMaintenanceEmailNotificationHandler return false; } - $data = AutoPresenter::decorate($event->incident); + // Only send emails for public incidents. + if ($event->incident->visible === 0) { + return; + } - foreach ($this->subscriber->isVerified()->get() as $subscriber) { - $mail = [ - 'email' => $subscriber->email, - 'subject' => 'Scheduled maintenance.', - 'status' => $data->human_status, - 'html_content' => $data->formattedMessage, - 'text_content' => $data->message, - 'scheduled_at' => $data->scheduled_at_formatted, - 'token' => $subscriber->token, - 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), - 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), - ]; + // First notify all global subscribers. + $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); - $this->mailer->queue([ - 'html' => 'emails.incidents.maintenance-html', - 'text' => 'emails.incidents.maintenance-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); + foreach ($globalSubscribers as $subscriber) { + $this->notify($event, $subscriber); + } + + if (!$event->incident->component) { + return; + } + + $notified = $globalSubscribers->pluck('id')->all(); + + // Notify the remaining component specific subscribers. + $componentSubscribers = $this->subscriber + ->isVerified() + ->forComponent($event->incident->component->id) + ->get() + ->reject(function ($subscriber) use ($notified) { + return in_array($subscriber->id, $notified); }); + + foreach ($componentSubscribers as $subscriber) { + $this->notify($event, $subscriber); } } + + /** + * Send notification to subscriber. + * + * @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public function notify(MaintenanceWasScheduledEvent $event, $subscriber) + { + $incident = AutoPresenter::decorate($event->incident); + $component = AutoPresenter::decorate($event->incident->component); + + $mail = [ + 'email' => $subscriber->email, + 'subject' => 'Scheduled maintenance.', + 'has_component' => ($event->incident->component) ? true : false, + 'component_name' => $component ? $component->name : null, + 'status' => $incident->human_status, + 'html_content' => $incident->formattedMessage, + 'text_content' => $incident->message, + 'token' => $subscriber->token, + 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), + 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), + ]; + + $this->mailer->queue([ + 'html' => 'emails.incidents.maintenance-html', + 'text' => 'emails.incidents.maintenance-text', + ], $mail, function (Message $message) use ($mail) { + $message->to($mail['email'])->subject($mail['subject']); + }); + } } diff --git a/app/Http/Controllers/Dashboard/IncidentController.php b/app/Http/Controllers/Dashboard/IncidentController.php index 80b5bd50..3acb41c5 100644 --- a/app/Http/Controllers/Dashboard/IncidentController.php +++ b/app/Http/Controllers/Dashboard/IncidentController.php @@ -120,6 +120,7 @@ class IncidentController extends Controller null )); } catch (ValidationException $e) { + dd($e->getMessageBag()); return Redirect::route('dashboard.incidents.add') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.add.failure'))) diff --git a/app/Http/Controllers/SubscribeController.php b/app/Http/Controllers/SubscribeController.php index 8a52882a..451928db 100644 --- a/app/Http/Controllers/SubscribeController.php +++ b/app/Http/Controllers/SubscribeController.php @@ -15,8 +15,10 @@ use AltThree\Validator\ValidationException; use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriptionCommand; +use CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand; use CachetHQ\Cachet\Bus\Exceptions\Subscriber\AlreadySubscribedException; +use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Subscription; use GrahamCampbell\Binput\Facades\Binput; @@ -57,11 +59,9 @@ class SubscribeController extends Controller $subscriptions = Binput::get('subscriptions'); try { - $subscription = dispatch(new SubscribeSubscriberCommand($email, false, $subscriptions)); - } catch (AlreadySubscribedException $e) { - return Redirect::route('subscribe.manage', $subscription->id) - ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure'))) - ->withErrors(trans('cachet.subscriber.email.already-subscribed', ['email' => $email])); + $verified = false; + + $subscription = dispatch(new SubscribeSubscriberCommand($email, $verified)); } catch (ValidationException $e) { return Redirect::route('status-page') ->withInput(Binput::all()) @@ -69,8 +69,12 @@ class SubscribeController extends Controller ->withErrors($e->getMessageBag()); } - return Redirect::route('status-page') - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed'))); + $message = $subscription->is_verified ? + trans('cachet.subscriber.email.already-subscribed', ['email' => $email]) : + trans('cachet.subscriber.email.subscribed'); + + return Redirect::route('subscribe.manage', $subscription->verify_code) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), $message)); } /** @@ -88,11 +92,13 @@ class SubscribeController extends Controller $subscriber = Subscriber::where('verify_code', '=', $code)->first(); - if (!$subscriber || $subscriber->is_verified) { + if (!$subscriber) { throw new BadRequestHttpException(); } - dispatch(new VerifySubscriberCommand($subscriber)); + if (!$subscriber->is_verified) { + dispatch(new VerifySubscriberCommand($subscriber)); + } return Redirect::route('status-page') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.verified'))); @@ -143,10 +149,46 @@ class SubscribeController extends Controller $subscriber = Subscriber::where('verify_code', '=', $code)->first(); - if (!$subscriber || !$subscriber->is_verified) { + if (!$subscriber) { throw new BadRequestHttpException(); } - return View::make('subscribe.manage')->withSubscriber($subscriber); + return View::make('subscribe.manage') + ->withComponents(Component::all()) + ->withSubscriber($subscriber) + ->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all()); + } + + /** + * Updates the subscription manager for a subscriber. + * + * @param string|null $code + * + * @return \Illuminate\View\View + */ + public function postManage($code = null) + { + if ($code === null) { + throw new NotFoundHttpException(); + } + + $subscriber = Subscriber::where('verify_code', '=', $code)->first(); + + if (!$subscriber) { + throw new BadRequestHttpException(); + } + + try { + dispatch(new UpdateSubscriberSubscriptionCommand($subscriber, Binput::get('subscriptions'))); + } catch (ValidationException $e) { + dd($e->getMessageBag()); + return Redirect::route('subscribe.manage', $subscriber->verify_code) + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure'))) + ->withErrors($e->getMessageBag()); + } + + return Redirect::route('subscribe.manage', $subscriber->verify_code) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed'))); } } diff --git a/app/Http/Routes/SubscribeRoutes.php b/app/Http/Routes/SubscribeRoutes.php index 9c7c2db0..cc0dc0f2 100644 --- a/app/Http/Routes/SubscribeRoutes.php +++ b/app/Http/Routes/SubscribeRoutes.php @@ -44,6 +44,11 @@ class SubscribeRoutes 'uses' => 'SubscribeController@showManage', ]); + $router->post('subscribe/manage/{code}', [ + 'as' => 'manage', + 'uses' => 'SubscribeController@postManage', + ]); + $router->get('subscribe/verify/{code}', [ 'as' => 'verify', 'uses' => 'SubscribeController@getVerify', diff --git a/app/Models/Subscriber.php b/app/Models/Subscriber.php index be456719..f5789e3d 100644 --- a/app/Models/Subscriber.php +++ b/app/Models/Subscriber.php @@ -30,6 +30,7 @@ class Subscriber extends Model implements HasPresenter 'email' => 'string', 'verify_code' => 'string', 'verified_at' => 'date', + 'global' => 'bool', ]; /** @@ -91,6 +92,33 @@ class Subscriber extends Model implements HasPresenter return $query->whereNotNull('verified_at'); } + /** + * Scope global subscribers. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeIsGlobal(Builder $query) + { + return $query->where('global', true); + } + + /** + * Finds all verified subscriptions for a component. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $component_id + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForComponent(Builder $query, $component_id) + { + return $query->select('subscribers.*') + ->join('subscriptions', 'subscribers.id', '=', 'subscriptions.subscriber_id') + ->where('subscriptions.component_id', $component_id); + } + /** * Determines if the subscriber is verified. * diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 36d536fd..3a1396c7 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -107,7 +107,10 @@ class Subscription extends Model { return $query->select('subscriptions.*') ->join('subscribers', 'subscriptions.subscriber_id', '=', 'subscribers.id') - ->where('component_id', $component_id) + ->where(function ($query) { + $query->where('subscriptions.component_id', $component_id) + ->orWhere('subscribers.global'); + }) ->whereNotNull('subscribers.verified_at'); } } diff --git a/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php b/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php new file mode 100644 index 00000000..0b828622 --- /dev/null +++ b/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php @@ -0,0 +1,31 @@ +boolean('global')->after('verified_at')->default(1); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('subscribers', function (Blueprint $table) { + $table->dropColumn('global'); + }); + } +} diff --git a/resources/assets/sass/_helpers.scss b/resources/assets/sass/_helpers.scss index 089f89bf..ace84e4f 100755 --- a/resources/assets/sass/_helpers.scss +++ b/resources/assets/sass/_helpers.scss @@ -1,3 +1,11 @@ .uppercase { text-transform: uppercase; } + +.margin-top { + margin-top: 20px; +} + +.margin-bottom { + margin-bottom: 20px; +} diff --git a/resources/views/emails/components/update-html.blade.php b/resources/views/emails/components/update-html.blade.php index d8fb0555..abe4bdc0 100644 --- a/resources/views/emails/components/update-html.blade.php +++ b/resources/views/emails/components/update-html.blade.php @@ -13,7 +13,4 @@

{!! trans('cachet.subscriber.email.manage') !!}

-

- {!! trans('cachet.subscriber.email.unsubscribe') !!} -

@stop diff --git a/resources/views/emails/components/update-text.blade.php b/resources/views/emails/components/update-text.blade.php index 10b880fb..f1f12454 100644 --- a/resources/views/emails/components/update-text.blade.php +++ b/resources/views/emails/components/update-text.blade.php @@ -5,5 +5,3 @@ @endif {!! trans('cachet.subscriber.email.manage') !!} {{ $manage_link }} - -{!! trans('cachet.subscriber.email.unsubscribe') !!} {{ $unsubscribe_link }} diff --git a/resources/views/subscribe/manage.blade.php b/resources/views/subscribe/manage.blade.php index 00e0899e..0069dfcb 100644 --- a/resources/views/subscribe/manage.blade.php +++ b/resources/views/subscribe/manage.blade.php @@ -9,21 +9,51 @@ @include('dashboard.partials.errors') -
-
{{ $subscriber->email }}
- @if($subscriber->subscriptions->count() > 0) -
-

{{ trans('cachet.subscriber.manage.my_subscriptions') }}

+
+
+
+

{{ $app_name }} Notifications

+

+ Manage notifications for {{ $subscriber->email }} +

+
+ @if($components->count() > 0) +
+ +
+
+ {{ trans('cachet.subscriber.manage.my_subscriptions') }} +
+
+ @foreach($components as $component) +
+
+ +
+
+ @endforeach +
+
+
+ +
+
+ @else +
+
+

{{ trans('cachet.subscriber.manage.no_subscriptions') }}

+
+
+ @endif
-
- @foreach($subscriber->subscriptions as $subscription) -
{{ $subscription->component->name }}
- @endforeach -
- @else -
-

{{ trans('cachet.subscriber.manage.no_subscriptions') }}

-
- @endif
@stop diff --git a/tests/Bus/Commands/Subscriber/SubscribeSubscriberCommandTest.php b/tests/Bus/Commands/Subscriber/SubscribeSubscriberCommandTest.php index 55287bdb..0a7205ab 100644 --- a/tests/Bus/Commands/Subscriber/SubscribeSubscriberCommandTest.php +++ b/tests/Bus/Commands/Subscriber/SubscribeSubscriberCommandTest.php @@ -28,8 +28,8 @@ class SubscribeSubscriberCommandTest extends AbstractTestCase protected function getObjectAndParams() { - $params = ['email' => 'support@cachethq.io', 'verified' => true, 'subscriptions' => null]; - $object = new SubscribeSubscriberCommand($params['email'], $params['verified'], $params['subscriptions']); + $params = ['email' => 'support@cachethq.io', 'verified' => true]; + $object = new SubscribeSubscriberCommand($params['email'], $params['verified']); return compact('params', 'object'); }