Skip to content

Commit a10db6f

Browse files
sodu-parsievsodudriesvints
authored
Add setting to turn off notifications (#938)
* feature #827 * feature #827 * feature #827 * fixing minor code formatting issues * feature #827 refactoring: taking out setting check from model to respective listeners * feature #827 added success message after saving settings * wip * wip * wip * wip --------- Co-authored-by: sodu <sparsiev@firmidea.com> Co-authored-by: Dries Vints <dries@vints.be>
1 parent f02967a commit a10db6f

21 files changed

+1804
-268
lines changed

app/Enums/NotificationType.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Enums;
4+
5+
use App\Notifications\MentionNotification;
6+
use App\Notifications\NewReplyNotification;
7+
8+
enum NotificationType: string
9+
{
10+
case MENTION = 'mention';
11+
case REPLY = 'reply';
12+
13+
public function getClass(): string
14+
{
15+
return match ($this) {
16+
self::MENTION => MentionNotification::class,
17+
self::REPLY => NewReplyNotification::class,
18+
};
19+
}
20+
21+
public function label(): string
22+
{
23+
return match ($this) {
24+
self::MENTION => 'Mentions',
25+
self::REPLY => 'Replies',
26+
};
27+
}
28+
29+
public static function getTypes(): array
30+
{
31+
return [
32+
self::MENTION->value => self::MENTION,
33+
self::REPLY->value => self::REPLY,
34+
];
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Settings;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Http\Requests\NotificationSettingsRequest;
7+
use App\Jobs\SaveNotificationSettings;
8+
use Illuminate\Auth\Middleware\Authenticate;
9+
10+
class NotificationSettingsController extends Controller
11+
{
12+
public function __construct()
13+
{
14+
$this->middleware(Authenticate::class);
15+
}
16+
17+
public function store(NotificationSettingsRequest $request)
18+
{
19+
$this->dispatchSync(new SaveNotificationSettings(
20+
$request->user(),
21+
(array) $request->validated('allowed_notifications')
22+
));
23+
24+
$this->success('settings.notifications.updated');
25+
26+
return redirect()->route('settings.profile');
27+
}
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Http\Requests;
4+
5+
use App\Enums\NotificationType;
6+
use Illuminate\Foundation\Http\FormRequest;
7+
use Illuminate\Validation\Rule;
8+
9+
class NotificationSettingsRequest extends FormRequest
10+
{
11+
public function rules(): array
12+
{
13+
return [
14+
'allowed_notifications.*' => Rule::enum(NotificationType::class),
15+
];
16+
}
17+
}

app/Jobs/RegisterUser.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Jobs;
44

5+
use App\Enums\NotificationType;
56
use App\Exceptions\CannotCreateUser;
67
use App\Http\Requests\RegisterRequest;
78
use App\Models\User;
@@ -44,6 +45,10 @@ public function handle(): void
4445
'type' => User::DEFAULT,
4546
'bio' => '',
4647
'remember_token' => '',
48+
'allowed_notifications' => [
49+
NotificationType::MENTION,
50+
NotificationType::REPLY,
51+
],
4752
]);
4853
$user->save();
4954
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\Jobs;
4+
5+
use App\Models\User;
6+
7+
final class SaveNotificationSettings
8+
{
9+
public function __construct(private User $user, private readonly array $allowedNotifications)
10+
{
11+
}
12+
13+
public function handle(): void
14+
{
15+
$this->user->allowed_notifications = $this->allowedNotifications;
16+
$this->user->save();
17+
}
18+
}

app/Listeners/NotifyUsersMentionedInReply.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,19 @@ final class NotifyUsersMentionedInReply
1212
public function handle(ReplyWasCreated $event): void
1313
{
1414
$event->reply->mentionedUsers()->each(function ($user) use ($event) {
15-
if (! $user->hasBlocked($event->reply->author()) && ! $event->reply->replyAble()->participants()->contains($user)) {
16-
$user->notify(new MentionNotification($event->reply));
15+
if (! $user->isNotificationAllowed(MentionNotification::class)) {
16+
return;
1717
}
18+
19+
if ($user->hasBlocked($event->reply->author())) {
20+
return;
21+
}
22+
23+
if ($event->reply->replyAble()->participants()->contains($user)) {
24+
return;
25+
}
26+
27+
$user->notify(new MentionNotification($event->reply));
1828
});
1929
}
2030
}

app/Listeners/NotifyUsersMentionedInThread.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@ final class NotifyUsersMentionedInThread
1212
public function handle(ThreadWasCreated $event): void
1313
{
1414
$event->thread->mentionedUsers()->each(function ($user) use ($event) {
15-
if (! $user->hasBlocked($event->thread->author())) {
16-
$user->notify(new MentionNotification($event->thread));
15+
if (! $user->isNotificationAllowed(MentionNotification::class)) {
16+
return;
1717
}
18+
19+
if ($user->hasBlocked($event->thread->author())) {
20+
return;
21+
}
22+
23+
$user->notify(new MentionNotification($event->thread));
1824
});
1925
}
2026
}

app/Listeners/SendNewReplyNotification.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@ public function handle(ReplyWasCreated $event): void
1616
$thread = $event->reply->replyAble();
1717

1818
foreach ($thread->subscriptions() as $subscription) {
19-
if ($this->replyAuthorDoesNotMatchSubscriber($event->reply->author(), $subscription)) {
20-
$subscription->user()->notify(new NewReplyNotification($event->reply, $subscription));
19+
if (! $subscription->user()->isNotificationAllowed(NewReplyNotification::class)) {
20+
continue;
2121
}
22+
23+
if (! $this->replyAuthorDoesNotMatchSubscriber($event->reply->author(), $subscription)) {
24+
continue;
25+
}
26+
27+
$subscription->user()->notify(new NewReplyNotification($event->reply, $subscription));
2228
}
2329
}
2430

app/Models/User.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
namespace App\Models;
44

55
use App\Concerns\HasTimestamps;
6+
use App\Enums\NotificationType;
67
use Illuminate\Contracts\Auth\MustVerifyEmail;
8+
use Illuminate\Contracts\Notifications\Dispatcher;
79
use Illuminate\Database\Eloquent\Builder;
810
use Illuminate\Database\Eloquent\Factories\HasFactory;
911
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
1012
use Illuminate\Database\Eloquent\Relations\HasMany;
1113
use Illuminate\Foundation\Auth\User as Authenticatable;
1214
use Illuminate\Notifications\Notifiable;
15+
use Illuminate\Support\Arr;
1316
use Illuminate\Support\Facades\Auth;
1417
use Laravel\Sanctum\HasApiTokens;
1518

@@ -52,6 +55,13 @@ final class User extends Authenticatable implements MustVerifyEmail
5255
'banned_reason',
5356
];
5457

58+
/**
59+
* {@inheritdoc}
60+
*/
61+
protected $casts = [
62+
'allowed_notifications' => 'array',
63+
];
64+
5565
/**
5666
* {@inheritdoc}
5767
*/
@@ -351,4 +361,12 @@ public function scopeWithUsersWhoArentBlockedBy(Builder $query, User $user)
351361
$query->where('user_id', $user->getKey());
352362
});
353363
}
364+
365+
public function isNotificationAllowed(string $notification): bool
366+
{
367+
return collect($this->allowed_notifications ?? [])
368+
->contains(function ($notificationType) use ($notification) {
369+
return NotificationType::from($notificationType)->getClass() === $notification;
370+
});
371+
}
354372
}

app/Notifications/MentionNotification.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace App\Notifications;
44

55
use App\Contracts\MentionAble;
6+
use App\Enums\NotificationType;
67
use App\Mail\MentionEmail;
78
use App\Models\User;
89
use Illuminate\Bus\Queueable;
@@ -34,7 +35,7 @@ public function toDatabase(User $user)
3435
$replyAble = $this->mentionAble->mentionedIn();
3536

3637
return [
37-
'type' => 'mention',
38+
'type' => NotificationType::MENTION,
3839
'replyable_id' => $replyAble->id,
3940
'replyable_type' => array_search(get_class($replyAble), Relation::morphMap()),
4041
'replyable_subject' => $this->mentionAble->mentionedIn()->subject(),

0 commit comments

Comments
 (0)