]> BookStack Code Mirror - bookstack/blob - app/Activity/Tools/UserEntityWatchOptions.php
Images: Added testing to cover animated avif handling
[bookstack] / app / Activity / Tools / UserEntityWatchOptions.php
1 <?php
2
3 namespace BookStack\Activity\Tools;
4
5 use BookStack\Activity\Models\Watch;
6 use BookStack\Activity\WatchLevels;
7 use BookStack\Entities\Models\BookChild;
8 use BookStack\Entities\Models\Entity;
9 use BookStack\Entities\Models\Page;
10 use BookStack\Users\Models\User;
11 use Illuminate\Database\Eloquent\Builder;
12
13 class UserEntityWatchOptions
14 {
15     protected ?array $watchMap = null;
16
17     public function __construct(
18         protected User $user,
19         protected Entity $entity,
20     ) {
21     }
22
23     public function canWatch(): bool
24     {
25         return $this->user->can('receive-notifications') && !$this->user->isGuest();
26     }
27
28     public function getWatchLevel(): string
29     {
30         return WatchLevels::levelValueToName($this->getWatchLevelValue());
31     }
32
33     public function isWatching(): bool
34     {
35         return $this->getWatchLevelValue() !== WatchLevels::DEFAULT;
36     }
37
38     public function getWatchedParent(): ?WatchedParentDetails
39     {
40         $watchMap = $this->getWatchMap();
41         unset($watchMap[$this->entity->getMorphClass()]);
42
43         if (isset($watchMap['chapter'])) {
44             return new WatchedParentDetails('chapter', $watchMap['chapter']);
45         }
46
47         if (isset($watchMap['book'])) {
48             return new WatchedParentDetails('book', $watchMap['book']);
49         }
50
51         return null;
52     }
53
54     public function updateLevelByName(string $level): void
55     {
56         $levelValue = WatchLevels::levelNameToValue($level);
57         $this->updateLevelByValue($levelValue);
58     }
59
60     public function updateLevelByValue(int $level): void
61     {
62         if ($level < 0) {
63             $this->remove();
64             return;
65         }
66
67         $this->updateLevel($level);
68     }
69
70     public function getWatchMap(): array
71     {
72         if (!is_null($this->watchMap)) {
73             return $this->watchMap;
74         }
75
76         $entities = [$this->entity];
77         if ($this->entity instanceof BookChild) {
78             $entities[] = $this->entity->book;
79         }
80         if ($this->entity instanceof Page && $this->entity->chapter) {
81             $entities[] = $this->entity->chapter;
82         }
83
84         $query = Watch::query()
85             ->where('user_id', '=', $this->user->id)
86             ->where(function (Builder $subQuery) use ($entities) {
87                 foreach ($entities as $entity) {
88                     $subQuery->orWhere(function (Builder $whereQuery) use ($entity) {
89                         $whereQuery->where('watchable_type', '=', $entity->getMorphClass())
90                         ->where('watchable_id', '=', $entity->id);
91                     });
92                 }
93             });
94
95         $this->watchMap = $query->get(['watchable_type', 'level'])
96             ->pluck('level', 'watchable_type')
97             ->toArray();
98
99         return $this->watchMap;
100     }
101
102     protected function getWatchLevelValue()
103     {
104         return $this->getWatchMap()[$this->entity->getMorphClass()] ?? WatchLevels::DEFAULT;
105     }
106
107     protected function updateLevel(int $levelValue): void
108     {
109         Watch::query()->updateOrCreate([
110             'watchable_id' => $this->entity->id,
111             'watchable_type' => $this->entity->getMorphClass(),
112             'user_id' => $this->user->id,
113         ], [
114             'level' => $levelValue,
115         ]);
116         $this->watchMap = null;
117     }
118
119     protected function remove(): void
120     {
121         $this->entityQuery()->delete();
122         $this->watchMap = null;
123     }
124
125     protected function entityQuery(): Builder
126     {
127         return Watch::query()->where('watchable_id', '=', $this->entity->id)
128             ->where('watchable_type', '=', $this->entity->getMorphClass())
129             ->where('user_id', '=', $this->user->id);
130     }
131 }