1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Jobs;
7
8use App\Events\NotificationReadEvent;
9use App\Libraries\MorphMap;
10use App\Models\Forum\Post as ForumPost;
11use App\Models\Notification;
12use App\Models\UserNotification;
13use App\Traits\NotificationQueue;
14use Exception;
15use Illuminate\Bus\Queueable;
16use Illuminate\Contracts\Queue\ShouldQueue;
17use Illuminate\Queue\SerializesModels;
18
19class MarkNotificationsRead implements ShouldQueue
20{
21 use NotificationQueue, Queueable, SerializesModels;
22
23 private $object;
24 private $user;
25
26 public function __construct($object, $user)
27 {
28 $this->object = $object;
29 $this->user = $user;
30 }
31
32 public function handle()
33 {
34 if (!($this->object instanceof ForumPost)) {
35 throw new Exception('Unknown object to be marked as read: '.get_class($this->object));
36 }
37
38 $notifiable = $this->object->topic()->withTrashed()->first();
39
40 if ($notifiable === null) {
41 throw new Exception("Can't find topic {$this->object->getKey()} of post {$this->object->getKey()}");
42 }
43
44 // TODO: should look at supporting marking stacks up to a certain point as read client side.
45 $userNotifications = UserNotification::where('user_id', $this->user->getKey())
46 ->where('is_read', false)
47 ->whereHas('notification', function ($query) use ($notifiable) {
48 $query
49 ->where('notifiable_type', MorphMap::getType($notifiable))
50 ->where('notifiable_id', $notifiable->getKey())
51 ->where('created_at', '<=', $this->object->post_time);
52 });
53
54 // only fetch the models that require marking as read.
55 $notifications = Notification::whereIn('id', (clone $userNotifications)->select('notification_id'))->get();
56 $notificationIdentities = $notifications->map->toIdentityJson()->all();
57
58 $count = $userNotifications->update(['is_read' => true]);
59
60 if ($count > 0) {
61 (new NotificationReadEvent($this->user->getKey(), [
62 'notifications' => $notificationIdentities,
63 'read_count' => $count,
64 'timestamp' => now(),
65 ]))->broadcast();
66 }
67 }
68}