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