]> BookStack Code Mirror - bookstack/blob - app/Activity/ActivityQueries.php
Testing: Added more deprecation output
[bookstack] / app / Activity / ActivityQueries.php
1 <?php
2
3 namespace BookStack\Activity;
4
5 use BookStack\Activity\Models\Activity;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Chapter;
8 use BookStack\Entities\Models\Entity;
9 use BookStack\Entities\Models\Page;
10 use BookStack\Entities\Tools\MixedEntityListLoader;
11 use BookStack\Permissions\PermissionApplicator;
12 use BookStack\Users\Models\User;
13 use Illuminate\Database\Eloquent\Builder;
14 use Illuminate\Database\Eloquent\Relations\MorphTo;
15 use Illuminate\Database\Eloquent\Relations\Relation;
16
17 class ActivityQueries
18 {
19     public function __construct(
20         protected PermissionApplicator $permissions,
21         protected MixedEntityListLoader $listLoader,
22     ) {
23     }
24
25     /**
26      * Gets the latest activity.
27      */
28     public function latest(int $count = 20, int $page = 0): array
29     {
30         $activityList = $this->permissions
31             ->restrictEntityRelationQuery(Activity::query(), 'activities', 'loggable_id', 'loggable_type')
32             ->orderBy('created_at', 'desc')
33             ->with(['user'])
34             ->skip($count * $page)
35             ->take($count)
36             ->get();
37
38         $this->listLoader->loadIntoRelations($activityList->all(), 'loggable', false);
39
40         return $this->filterSimilar($activityList);
41     }
42
43     /**
44      * Gets the latest activity for an entity, Filtering out similar
45      * items to prevent a message activity list.
46      */
47     public function entityActivity(Entity $entity, int $count = 20, int $page = 1): array
48     {
49         /** @var array<string, int[]> $queryIds */
50         $queryIds = [$entity->getMorphClass() => [$entity->id]];
51
52         if ($entity instanceof Book) {
53             $queryIds[(new Chapter())->getMorphClass()] = $entity->chapters()->scopes('visible')->pluck('id');
54         }
55         if ($entity instanceof Book || $entity instanceof Chapter) {
56             $queryIds[(new Page())->getMorphClass()] = $entity->pages()->scopes('visible')->pluck('id');
57         }
58
59         $query = Activity::query();
60         $query->where(function (Builder $query) use ($queryIds) {
61             foreach ($queryIds as $morphClass => $idArr) {
62                 $query->orWhere(function (Builder $innerQuery) use ($morphClass, $idArr) {
63                     $innerQuery->where('loggable_type', '=', $morphClass)
64                         ->whereIn('loggable_id', $idArr);
65                 });
66             }
67         });
68
69         $activity = $query->orderBy('created_at', 'desc')
70             ->with(['loggable' => function (Relation $query) {
71                 /** @var MorphTo<Entity, Activity> $query */
72                 $query->withTrashed();
73             }, 'user.avatar'])
74             ->skip($count * ($page - 1))
75             ->take($count)
76             ->get();
77
78         return $this->filterSimilar($activity);
79     }
80
81     /**
82      * Get the latest activity for a user, Filtering out similar items.
83      */
84     public function userActivity(User $user, int $count = 20, int $page = 0): array
85     {
86         $activityList = $this->permissions
87             ->restrictEntityRelationQuery(Activity::query(), 'activities', 'loggable_id', 'loggable_type')
88             ->orderBy('created_at', 'desc')
89             ->where('user_id', '=', $user->id)
90             ->skip($count * $page)
91             ->take($count)
92             ->get();
93
94         return $this->filterSimilar($activityList);
95     }
96
97     /**
98      * Filters out similar activity.
99      *
100      * @param Activity[] $activities
101      */
102     protected function filterSimilar(iterable $activities): array
103     {
104         $newActivity = [];
105         $previousItem = null;
106
107         foreach ($activities as $activityItem) {
108             if (!$previousItem || !$activityItem->isSimilarTo($previousItem)) {
109                 $newActivity[] = $activityItem;
110             }
111
112             $previousItem = $activityItem;
113         }
114
115         return $newActivity;
116     }
117 }