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