2023-08-04 07:27:29 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace BookStack\Activity\Tools;
|
|
|
|
|
|
|
|
use BookStack\Activity\Models\Watch;
|
|
|
|
use BookStack\Entities\Models\BookChild;
|
|
|
|
use BookStack\Entities\Models\Entity;
|
|
|
|
use BookStack\Entities\Models\Page;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
|
|
|
|
class EntityWatchers
|
|
|
|
{
|
2023-08-04 11:51:29 -04:00
|
|
|
/**
|
|
|
|
* @var int[]
|
|
|
|
*/
|
2023-08-04 07:27:29 -04:00
|
|
|
protected array $watchers = [];
|
2023-08-04 11:51:29 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var int[]
|
|
|
|
*/
|
2023-08-04 07:27:29 -04:00
|
|
|
protected array $ignorers = [];
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
protected Entity $entity,
|
|
|
|
protected int $watchLevel,
|
|
|
|
) {
|
|
|
|
$this->build();
|
|
|
|
}
|
|
|
|
|
2023-08-04 11:51:29 -04:00
|
|
|
public function getWatcherUserIds(): array
|
|
|
|
{
|
|
|
|
return $this->watchers;
|
|
|
|
}
|
|
|
|
|
2023-08-05 09:19:23 -04:00
|
|
|
public function isUserIgnoring(int $userId): bool
|
|
|
|
{
|
|
|
|
return in_array($userId, $this->ignorers);
|
|
|
|
}
|
|
|
|
|
2023-08-04 07:27:29 -04:00
|
|
|
protected function build(): void
|
|
|
|
{
|
|
|
|
$watches = $this->getRelevantWatches();
|
|
|
|
|
2023-08-04 11:51:29 -04:00
|
|
|
// Sort before de-duping, so that the order looped below follows book -> chapter -> page ordering
|
|
|
|
usort($watches, function (Watch $watchA, Watch $watchB) {
|
|
|
|
$entityTypeDiff = $watchA->watchable_type <=> $watchB->watchable_type;
|
|
|
|
return $entityTypeDiff === 0 ? ($watchA->user_id <=> $watchB->user_id) : $entityTypeDiff;
|
|
|
|
});
|
|
|
|
|
|
|
|
// De-dupe by user id to get their most relevant level
|
|
|
|
$levelByUserId = [];
|
|
|
|
foreach ($watches as $watch) {
|
|
|
|
$levelByUserId[$watch->user_id] = $watch->level;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the class arrays
|
|
|
|
$this->watchers = array_keys(array_filter($levelByUserId, fn(int $level) => $level >= $this->watchLevel));
|
|
|
|
$this->ignorers = array_keys(array_filter($levelByUserId, fn(int $level) => $level === 0));
|
2023-08-04 07:27:29 -04:00
|
|
|
}
|
|
|
|
|
2023-08-04 11:51:29 -04:00
|
|
|
/**
|
|
|
|
* @return Watch[]
|
|
|
|
*/
|
2023-08-04 07:27:29 -04:00
|
|
|
protected function getRelevantWatches(): array
|
|
|
|
{
|
|
|
|
/** @var Entity[] $entitiesInvolved */
|
|
|
|
$entitiesInvolved = array_filter([
|
|
|
|
$this->entity,
|
|
|
|
$this->entity instanceof BookChild ? $this->entity->book : null,
|
|
|
|
$this->entity instanceof Page ? $this->entity->chapter : null,
|
|
|
|
]);
|
|
|
|
|
|
|
|
$query = Watch::query()->where(function (Builder $query) use ($entitiesInvolved) {
|
|
|
|
foreach ($entitiesInvolved as $entity) {
|
|
|
|
$query->orWhere(function (Builder $query) use ($entity) {
|
|
|
|
$query->where('watchable_type', '=', $entity->getMorphClass())
|
|
|
|
->where('watchable_id', '=', $entity->id);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return $query->get([
|
2023-08-04 11:51:29 -04:00
|
|
|
'level', 'watchable_id', 'watchable_type', 'user_id'
|
2023-08-04 07:27:29 -04:00
|
|
|
])->all();
|
|
|
|
}
|
|
|
|
}
|