| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Activity\Tools; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use BookStack\Activity\Models\Watch; | 
					
						
							|  |  |  | use BookStack\Activity\WatchLevels; | 
					
						
							|  |  |  | use BookStack\Entities\Models\BookChild; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Entity; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Page; | 
					
						
							|  |  |  | use BookStack\Users\Models\User; | 
					
						
							|  |  |  | use Illuminate\Database\Eloquent\Builder; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UserEntityWatchOptions | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     protected ?array $watchMap = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct( | 
					
						
							|  |  |  |         protected User $user, | 
					
						
							|  |  |  |         protected Entity $entity, | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function canWatch(): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-09-16 20:18:35 +08:00
										 |  |  |         return $this->user->can('receive-notifications') && !$this->user->isGuest(); | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getWatchLevel(): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return WatchLevels::levelValueToName($this->getWatchLevelValue()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function isWatching(): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->getWatchLevelValue() !== WatchLevels::DEFAULT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getWatchedParent(): ?WatchedParentDetails | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $watchMap = $this->getWatchMap(); | 
					
						
							|  |  |  |         unset($watchMap[$this->entity->getMorphClass()]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (isset($watchMap['chapter'])) { | 
					
						
							|  |  |  |             return new WatchedParentDetails('chapter', $watchMap['chapter']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (isset($watchMap['book'])) { | 
					
						
							|  |  |  |             return new WatchedParentDetails('book', $watchMap['book']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-18 01:10:34 +08:00
										 |  |  |     public function updateLevelByName(string $level): void | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $levelValue = WatchLevels::levelNameToValue($level); | 
					
						
							| 
									
										
										
										
											2023-08-18 01:10:34 +08:00
										 |  |  |         $this->updateLevelByValue($levelValue); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function updateLevelByValue(int $level): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ($level < 0) { | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  |             $this->remove(); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-18 01:10:34 +08:00
										 |  |  |         $this->updateLevel($level); | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getWatchMap(): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!is_null($this->watchMap)) { | 
					
						
							|  |  |  |             return $this->watchMap; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $entities = [$this->entity]; | 
					
						
							|  |  |  |         if ($this->entity instanceof BookChild) { | 
					
						
							|  |  |  |             $entities[] = $this->entity->book; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if ($this->entity instanceof Page && $this->entity->chapter) { | 
					
						
							|  |  |  |             $entities[] = $this->entity->chapter; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-15 21:39:39 +08:00
										 |  |  |         $query = Watch::query() | 
					
						
							|  |  |  |             ->where('user_id', '=', $this->user->id) | 
					
						
							|  |  |  |             ->where(function (Builder $subQuery) use ($entities) { | 
					
						
							|  |  |  |                 foreach ($entities as $entity) { | 
					
						
							|  |  |  |                     $subQuery->orWhere(function (Builder $whereQuery) use ($entity) { | 
					
						
							|  |  |  |                         $whereQuery->where('watchable_type', '=', $entity->getMorphClass()) | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  |                         ->where('watchable_id', '=', $entity->id); | 
					
						
							| 
									
										
										
										
											2023-08-15 21:39:39 +08:00
										 |  |  |                     }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2023-08-09 21:53:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $this->watchMap = $query->get(['watchable_type', 'level']) | 
					
						
							|  |  |  |             ->pluck('level', 'watchable_type') | 
					
						
							|  |  |  |             ->toArray(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this->watchMap; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function getWatchLevelValue() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->getWatchMap()[$this->entity->getMorphClass()] ?? WatchLevels::DEFAULT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function updateLevel(int $levelValue): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Watch::query()->updateOrCreate([ | 
					
						
							|  |  |  |             'watchable_id' => $this->entity->id, | 
					
						
							|  |  |  |             'watchable_type' => $this->entity->getMorphClass(), | 
					
						
							|  |  |  |             'user_id' => $this->user->id, | 
					
						
							|  |  |  |         ], [ | 
					
						
							|  |  |  |             'level' => $levelValue, | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |         $this->watchMap = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function remove(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->entityQuery()->delete(); | 
					
						
							|  |  |  |         $this->watchMap = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function entityQuery(): Builder | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return Watch::query()->where('watchable_id', '=', $this->entity->id) | 
					
						
							|  |  |  |             ->where('watchable_type', '=', $this->entity->getMorphClass()) | 
					
						
							|  |  |  |             ->where('user_id', '=', $this->user->id); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |