]> BookStack Code Mirror - bookstack/blob - app/Entities/Repos/BookshelfRepo.php
Added tests to cover convert functionality
[bookstack] / app / Entities / Repos / BookshelfRepo.php
1 <?php
2
3 namespace BookStack\Entities\Repos;
4
5 use BookStack\Actions\ActivityType;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Bookshelf;
8 use BookStack\Entities\Tools\TrashCan;
9 use BookStack\Exceptions\ImageUploadException;
10 use BookStack\Exceptions\NotFoundException;
11 use BookStack\Facades\Activity;
12 use Exception;
13 use Illuminate\Contracts\Pagination\LengthAwarePaginator;
14 use Illuminate\Http\UploadedFile;
15 use Illuminate\Support\Collection;
16
17 class BookshelfRepo
18 {
19     protected $baseRepo;
20
21     /**
22      * BookshelfRepo constructor.
23      */
24     public function __construct(BaseRepo $baseRepo)
25     {
26         $this->baseRepo = $baseRepo;
27     }
28
29     /**
30      * Get all bookshelves in a paginated format.
31      */
32     public function getAllPaginated(int $count = 20, string $sort = 'name', string $order = 'asc'): LengthAwarePaginator
33     {
34         return Bookshelf::visible()
35             ->with(['visibleBooks', 'cover'])
36             ->orderBy($sort, $order)
37             ->paginate($count);
38     }
39
40     /**
41      * Get the bookshelves that were most recently viewed by this user.
42      */
43     public function getRecentlyViewed(int $count = 20): Collection
44     {
45         return Bookshelf::visible()->withLastView()
46             ->having('last_viewed_at', '>', 0)
47             ->orderBy('last_viewed_at', 'desc')
48             ->take($count)->get();
49     }
50
51     /**
52      * Get the most popular bookshelves in the system.
53      */
54     public function getPopular(int $count = 20): Collection
55     {
56         return Bookshelf::visible()->withViewCount()
57             ->having('view_count', '>', 0)
58             ->orderBy('view_count', 'desc')
59             ->take($count)->get();
60     }
61
62     /**
63      * Get the most recently created bookshelves from the system.
64      */
65     public function getRecentlyCreated(int $count = 20): Collection
66     {
67         return Bookshelf::visible()->orderBy('created_at', 'desc')
68             ->take($count)->get();
69     }
70
71     /**
72      * Get a shelf by its slug.
73      */
74     public function getBySlug(string $slug): Bookshelf
75     {
76         $shelf = Bookshelf::visible()->where('slug', '=', $slug)->first();
77
78         if ($shelf === null) {
79             throw new NotFoundException(trans('errors.bookshelf_not_found'));
80         }
81
82         return $shelf;
83     }
84
85     /**
86      * Create a new shelf in the system.
87      */
88     public function create(array $input, array $bookIds): Bookshelf
89     {
90         $shelf = new Bookshelf();
91         $this->baseRepo->create($shelf, $input);
92         $this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
93         $this->updateBooks($shelf, $bookIds);
94         Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
95
96         return $shelf;
97     }
98
99     /**
100      * Update an existing shelf in the system using the given input.
101      */
102     public function update(Bookshelf $shelf, array $input, ?array $bookIds): Bookshelf
103     {
104         $this->baseRepo->update($shelf, $input);
105
106         if (!is_null($bookIds)) {
107             $this->updateBooks($shelf, $bookIds);
108         }
109
110         if (array_key_exists('image', $input)) {
111             $this->baseRepo->updateCoverImage($shelf, $input['image'], $input['image'] === null);
112         }
113
114         Activity::add(ActivityType::BOOKSHELF_UPDATE, $shelf);
115
116         return $shelf;
117     }
118
119     /**
120      * Update which books are assigned to this shelf by syncing the given book ids.
121      * Function ensures the books are visible to the current user and existing.
122      */
123     protected function updateBooks(Bookshelf $shelf, array $bookIds)
124     {
125         $numericIDs = collect($bookIds)->map(function ($id) {
126             return intval($id);
127         });
128
129         $syncData = Book::visible()
130             ->whereIn('id', $bookIds)
131             ->pluck('id')
132             ->mapWithKeys(function ($bookId) use ($numericIDs) {
133                 return [$bookId => ['order' => $numericIDs->search($bookId)]];
134             });
135
136         $shelf->books()->sync($syncData);
137     }
138
139     /**
140      * Copy down the permissions of the given shelf to all child books.
141      */
142     public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int
143     {
144         $shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray();
145         $shelfBooks = $shelf->books()->get(['id', 'restricted']);
146         $updatedBookCount = 0;
147
148         /** @var Book $book */
149         foreach ($shelfBooks as $book) {
150             if ($checkUserPermissions && !userCan('restrictions-manage', $book)) {
151                 continue;
152             }
153             $book->permissions()->delete();
154             $book->restricted = $shelf->restricted;
155             $book->permissions()->createMany($shelfPermissions);
156             $book->save();
157             $book->rebuildPermissions();
158             $updatedBookCount++;
159         }
160
161         return $updatedBookCount;
162     }
163
164     /**
165      * Remove a bookshelf from the system.
166      *
167      * @throws Exception
168      */
169     public function destroy(Bookshelf $shelf)
170     {
171         $trashCan = new TrashCan();
172         $trashCan->softDestroyShelf($shelf);
173         Activity::add(ActivityType::BOOKSHELF_DELETE, $shelf);
174         $trashCan->autoClearOld();
175     }
176 }