diff --git a/app/Actions/ActivityService.php b/app/Actions/ActivityService.php index e1046db88..be9f656c3 100644 --- a/app/Actions/ActivityService.php +++ b/app/Actions/ActivityService.php @@ -2,9 +2,11 @@ use BookStack\Auth\Permissions\PermissionService; use BookStack\Auth\User; +use BookStack\Entities\Chapter; use BookStack\Entities\Entity; +use BookStack\Entities\Page; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\Relation; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; class ActivityService @@ -21,11 +23,11 @@ class ActivityService } /** - * Add activity data to database. + * Add activity data to database for an entity. */ - public function add(Entity $entity, string $type, ?int $bookId = null) + public function addForEntity(Entity $entity, string $type) { - $activity = $this->newActivityForUser($type, $bookId); + $activity = $this->newActivityForUser($type); $entity->activity()->save($activity); $this->setNotification($type); } @@ -33,12 +35,11 @@ class ActivityService /** * Get a new activity instance for the current user. */ - protected function newActivityForUser(string $key, ?int $bookId = null): Activity + protected function newActivityForUser(string $type): Activity { return $this->activity->newInstance()->forceFill([ - 'key' => strtolower($key), + 'key' => strtolower($type), 'user_id' => $this->user->id, - 'book_id' => $bookId ?? 0, ]); } @@ -47,15 +48,13 @@ class ActivityService * and instead uses the 'extra' field with the entities name. * Used when an entity is deleted. */ - public function removeEntity(Entity $entity): Collection + public function removeEntity(Entity $entity) { - $activities = $entity->activity()->get(); $entity->activity()->update([ 'extra' => $entity->name, 'entity_id' => 0, 'entity_type' => '', ]); - return $activities; } /** @@ -80,16 +79,27 @@ class ActivityService */ public function entityActivity(Entity $entity, int $count = 20, int $page = 1): array { + /** @var [string => int[]] $queryIds */ + $queryIds = [$entity->getMorphClass() => [$entity->id]]; + if ($entity->isA('book')) { - $query = $this->activity->newQuery()->where('book_id', '=', $entity->id); - } else { - $query = $this->activity->newQuery()->where('entity_type', '=', $entity->getMorphClass()) - ->where('entity_id', '=', $entity->id); + $queryIds[(new Chapter)->getMorphClass()] = $entity->chapters()->visible()->pluck('id'); + } + if ($entity->isA('book') || $entity->isA('chapter')) { + $queryIds[(new Page)->getMorphClass()] = $entity->pages()->visible()->pluck('id'); } - $activity = $this->permissionService - ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') - ->orderBy('created_at', 'desc') + $query = $this->activity->newQuery(); + $query->where(function (Builder $query) use ($queryIds) { + foreach ($queryIds as $morphClass => $idArr) { + $query->orWhere(function (Builder $innerQuery) use ($morphClass, $idArr) { + $innerQuery->where('entity_type', '=', $morphClass) + ->whereIn('entity_id', $idArr); + }); + } + }); + + $activity = $query->orderBy('created_at', 'desc') ->with(['entity' => function (Relation $query) { $query->withTrashed(); }, 'user.avatar']) diff --git a/app/Actions/CommentRepo.php b/app/Actions/CommentRepo.php index c0f008137..1d46e781c 100644 --- a/app/Actions/CommentRepo.php +++ b/app/Actions/CommentRepo.php @@ -2,6 +2,7 @@ use BookStack\Entities\Entity; use League\CommonMark\CommonMarkConverter; +use BookStack\Facades\Activity as ActivityService; /** * Class CommentRepo @@ -44,7 +45,7 @@ class CommentRepo $comment->parent_id = $parent_id; $entity->comments()->save($comment); - Activity::add($entity, ActivityType::COMMENTED_ON, $entity->book->id); + ActivityService::addForEntity($entity, ActivityType::COMMENTED_ON); return $comment; } diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php index c2a613f71..008a9080c 100644 --- a/app/Entities/Repos/BookRepo.php +++ b/app/Entities/Repos/BookRepo.php @@ -93,7 +93,7 @@ class BookRepo { $book = new Book(); $this->baseRepo->create($book, $input); - Activity::add($book, ActivityType::BOOK_CREATE, $book->id); + Activity::addForEntity($book, ActivityType::BOOK_CREATE); return $book; } @@ -103,7 +103,7 @@ class BookRepo public function update(Book $book, array $input): Book { $this->baseRepo->update($book, $input); - Activity::add($book, ActivityType::BOOK_UPDATE, $book->id); + Activity::addForEntity($book, ActivityType::BOOK_UPDATE); return $book; } @@ -133,7 +133,7 @@ class BookRepo { $trashCan = new TrashCan(); $trashCan->softDestroyBook($book); - Activity::add($book, ActivityType::BOOK_DELETE, $book->id); + Activity::addForEntity($book, ActivityType::BOOK_DELETE); $trashCan->autoClearOld(); } diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php index 2c80b2a7d..7cd333ff3 100644 --- a/app/Entities/Repos/BookshelfRepo.php +++ b/app/Entities/Repos/BookshelfRepo.php @@ -89,7 +89,7 @@ class BookshelfRepo $shelf = new Bookshelf(); $this->baseRepo->create($shelf, $input); $this->updateBooks($shelf, $bookIds); - Activity::add($shelf, ActivityType::BOOKSHELF_CREATE); + Activity::addForEntity($shelf, ActivityType::BOOKSHELF_CREATE); return $shelf; } @@ -104,7 +104,7 @@ class BookshelfRepo $this->updateBooks($shelf, $bookIds); } - Activity::add($shelf, ActivityType::BOOKSHELF_UPDATE); + Activity::addForEntity($shelf, ActivityType::BOOKSHELF_UPDATE); return $shelf; } @@ -179,7 +179,7 @@ class BookshelfRepo { $trashCan = new TrashCan(); $trashCan->softDestroyShelf($shelf); - Activity::add($shelf, ActivityType::BOOKSHELF_DELETE); + Activity::addForEntity($shelf, ActivityType::BOOKSHELF_DELETE); $trashCan->autoClearOld(); } } diff --git a/app/Entities/Repos/ChapterRepo.php b/app/Entities/Repos/ChapterRepo.php index 581da1fa3..312cb69e5 100644 --- a/app/Entities/Repos/ChapterRepo.php +++ b/app/Entities/Repos/ChapterRepo.php @@ -48,7 +48,7 @@ class ChapterRepo $chapter->book_id = $parentBook->id; $chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1; $this->baseRepo->create($chapter, $input); - Activity::add($chapter, ActivityType::CHAPTER_CREATE, $parentBook->id); + Activity::addForEntity($chapter, ActivityType::CHAPTER_CREATE); return $chapter; } @@ -58,7 +58,7 @@ class ChapterRepo public function update(Chapter $chapter, array $input): Chapter { $this->baseRepo->update($chapter, $input); - Activity::add($chapter, ActivityType::CHAPTER_UPDATE, $chapter->book->id); + Activity::addForEntity($chapter, ActivityType::CHAPTER_UPDATE); return $chapter; } @@ -78,7 +78,7 @@ class ChapterRepo { $trashCan = new TrashCan(); $trashCan->softDestroyChapter($chapter); - Activity::add($chapter, ActivityType::CHAPTER_DELETE, $chapter->book->id); + Activity::addForEntity($chapter, ActivityType::CHAPTER_DELETE); $trashCan->autoClearOld(); } @@ -106,7 +106,7 @@ class ChapterRepo $chapter->changeBook($parent->id); $chapter->rebuildPermissions(); - Activity::add($chapter, ActivityType::CHAPTER_MOVE, $parent->id); + Activity::addForEntity($chapter, ActivityType::CHAPTER_MOVE); return $parent; } diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index 065f1606f..6b593d85e 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -169,7 +169,7 @@ class PageRepo $draft->indexForSearch(); $draft->refresh(); - Activity::add($draft, ActivityType::PAGE_CREATE, $draft->book->id); + Activity::addForEntity($draft, ActivityType::PAGE_CREATE); return $draft; } @@ -208,7 +208,7 @@ class PageRepo $this->savePageRevision($page, $summary); } - Activity::add($page, ActivityType::PAGE_UPDATE, $page->book->id); + Activity::addForEntity($page, ActivityType::PAGE_UPDATE); return $page; } @@ -272,7 +272,7 @@ class PageRepo { $trashCan = new TrashCan(); $trashCan->softDestroyPage($page); - Activity::add($page, ActivityType::PAGE_DELETE, $page->book_id); + Activity::addForEntity($page, ActivityType::PAGE_DELETE); $trashCan->autoClearOld(); } @@ -293,7 +293,7 @@ class PageRepo $page->save(); $page->indexForSearch(); - Activity::add($page, ActivityType::PAGE_RESTORE, $page->book->id); + Activity::addForEntity($page, ActivityType::PAGE_RESTORE); return $page; } @@ -319,7 +319,7 @@ class PageRepo $page->changeBook($parent instanceof Book ? $parent->id : $parent->book->id); $page->rebuildPermissions(); - Activity::add($page, ActivityType::PAGE_MOVE, $page->book->id); + Activity::addForEntity($page, ActivityType::PAGE_MOVE); return $parent; } diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 5a42daddb..74f9586aa 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -97,7 +97,7 @@ class BookController extends Controller if ($bookshelf) { $bookshelf->appendBook($book); - Activity::add($bookshelf, ActivityType::BOOKSHELF_UPDATE); + Activity::addForEntity($bookshelf, ActivityType::BOOKSHELF_UPDATE); } return redirect($book->getUrl()); diff --git a/app/Http/Controllers/BookSortController.php b/app/Http/Controllers/BookSortController.php index e94e4ecce..fb9308b46 100644 --- a/app/Http/Controllers/BookSortController.php +++ b/app/Http/Controllers/BookSortController.php @@ -75,7 +75,7 @@ class BookSortController extends Controller // Rebuild permissions and add activity for involved books. $booksInvolved->each(function (Book $book) { - Activity::add($book, ActivityType::BOOK_SORT, $book->id); + Activity::addForEntity($book, ActivityType::BOOK_SORT); }); return redirect($book->getUrl()); diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 7e931ee96..69233e287 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -38,7 +38,7 @@ class CommandsTest extends TestCase { $this->asEditor(); $page = Page::first(); - \Activity::add($page, ActivityType::PAGE_UPDATE, $page->book->id); + \Activity::addForEntity($page, ActivityType::PAGE_UPDATE); $this->assertDatabaseHas('activities', [ 'key' => 'page_update', diff --git a/tests/User/UserProfileTest.php b/tests/User/UserProfileTest.php index cc39c0d8e..f0c36454e 100644 --- a/tests/User/UserProfileTest.php +++ b/tests/User/UserProfileTest.php @@ -61,8 +61,8 @@ class UserProfileTest extends BrowserKitTest $newUser = $this->getNewBlankUser(); $this->actingAs($newUser); $entities = $this->createEntityChainBelongingToUser($newUser, $newUser); - Activity::add($entities['book'], ActivityType::BOOK_UPDATE, $entities['book']->id); - Activity::add($entities['page'], ActivityType::PAGE_CREATE, $entities['book']->id); + Activity::addForEntity($entities['book'], ActivityType::BOOK_UPDATE); + Activity::addForEntity($entities['page'], ActivityType::PAGE_CREATE); $this->asAdmin()->visit('/user/' . $newUser->id) ->seeInElement('#recent-user-activity', 'updated book') @@ -75,8 +75,8 @@ class UserProfileTest extends BrowserKitTest $newUser = $this->getNewBlankUser(); $this->actingAs($newUser); $entities = $this->createEntityChainBelongingToUser($newUser, $newUser); - Activity::add($entities['book'], ActivityType::BOOK_UPDATE, $entities['book']->id); - Activity::add($entities['page'], ActivityType::PAGE_CREATE, $entities['book']->id); + Activity::addForEntity($entities['book'], ActivityType::BOOK_UPDATE); + Activity::addForEntity($entities['page'], ActivityType::PAGE_CREATE); $this->asAdmin()->visit('/')->clickInElement('#recent-activity', $newUser->name) ->seePageIs('/user/' . $newUser->id)