Queries: Updated all app book static query uses
This commit is contained in:
parent
c95f4ca40f
commit
483410749b
37 changed files with 278 additions and 162 deletions
|
@ -40,7 +40,7 @@ class HomeController extends Controller
|
||||||
$recentFactor = count($draftPages) > 0 ? 0.5 : 1;
|
$recentFactor = count($draftPages) > 0 ? 0.5 : 1;
|
||||||
$recents = $this->isSignedIn() ?
|
$recents = $this->isSignedIn() ?
|
||||||
(new RecentlyViewed())->run(12 * $recentFactor, 1)
|
(new RecentlyViewed())->run(12 * $recentFactor, 1)
|
||||||
: Book::visible()->orderBy('created_at', 'desc')->take(12 * $recentFactor)->get();
|
: $this->queries->books->visibleForList()->orderBy('created_at', 'desc')->take(12 * $recentFactor)->get();
|
||||||
$favourites = (new TopFavourites())->run(6);
|
$favourites = (new TopFavourites())->run(6);
|
||||||
$recentlyUpdatedPages = $this->queries->pages->visibleForList()
|
$recentlyUpdatedPages = $this->queries->pages->visibleForList()
|
||||||
->where('draft', false)
|
->where('draft', false)
|
||||||
|
|
|
@ -6,6 +6,7 @@ use BookStack\Api\ApiEntityListFormatter;
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Models\Book;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Entity;
|
use BookStack\Entities\Models\Entity;
|
||||||
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
use BookStack\Entities\Repos\BookRepo;
|
use BookStack\Entities\Repos\BookRepo;
|
||||||
use BookStack\Entities\Tools\BookContents;
|
use BookStack\Entities\Tools\BookContents;
|
||||||
use BookStack\Http\ApiController;
|
use BookStack\Http\ApiController;
|
||||||
|
@ -15,7 +16,8 @@ use Illuminate\Validation\ValidationException;
|
||||||
class BookApiController extends ApiController
|
class BookApiController extends ApiController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected BookRepo $bookRepo
|
protected BookRepo $bookRepo,
|
||||||
|
protected BookQueries $queries,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ class BookApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function list()
|
public function list()
|
||||||
{
|
{
|
||||||
$books = Book::visible();
|
$books = $this->queries->visibleForList();
|
||||||
|
|
||||||
return $this->apiListingResponse($books, [
|
return $this->apiListingResponse($books, [
|
||||||
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
|
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
|
||||||
|
@ -56,7 +58,7 @@ class BookApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function read(string $id)
|
public function read(string $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$book = $this->forJsonDisplay($book);
|
$book = $this->forJsonDisplay($book);
|
||||||
$book->load(['createdBy', 'updatedBy', 'ownedBy']);
|
$book->load(['createdBy', 'updatedBy', 'ownedBy']);
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ class BookApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, string $id)
|
public function update(Request $request, string $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
|
|
||||||
$requestData = $this->validate($request, $this->rules()['update']);
|
$requestData = $this->validate($request, $this->rules()['update']);
|
||||||
|
@ -100,7 +102,7 @@ class BookApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function delete(string $id)
|
public function delete(string $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$this->checkOwnablePermission('book-delete', $book);
|
$this->checkOwnablePermission('book-delete', $book);
|
||||||
|
|
||||||
$this->bookRepo->destroy($book);
|
$this->bookRepo->destroy($book);
|
||||||
|
|
|
@ -2,18 +2,17 @@
|
||||||
|
|
||||||
namespace BookStack\Entities\Controllers;
|
namespace BookStack\Entities\Controllers;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
use BookStack\Entities\Tools\ExportFormatter;
|
use BookStack\Entities\Tools\ExportFormatter;
|
||||||
use BookStack\Http\ApiController;
|
use BookStack\Http\ApiController;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class BookExportApiController extends ApiController
|
class BookExportApiController extends ApiController
|
||||||
{
|
{
|
||||||
protected $exportFormatter;
|
public function __construct(
|
||||||
|
protected ExportFormatter $exportFormatter,
|
||||||
public function __construct(ExportFormatter $exportFormatter)
|
protected BookQueries $queries,
|
||||||
{
|
) {
|
||||||
$this->exportFormatter = $exportFormatter;
|
|
||||||
$this->middleware('can:content-export');
|
$this->middleware('can:content-export');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ class BookExportApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function exportPdf(int $id)
|
public function exportPdf(int $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||||
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
||||||
|
|
||||||
return $this->download()->directly($pdfContent, $book->slug . '.pdf');
|
return $this->download()->directly($pdfContent, $book->slug . '.pdf');
|
||||||
|
@ -37,7 +36,7 @@ class BookExportApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function exportHtml(int $id)
|
public function exportHtml(int $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||||
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
||||||
|
|
||||||
return $this->download()->directly($htmlContent, $book->slug . '.html');
|
return $this->download()->directly($htmlContent, $book->slug . '.html');
|
||||||
|
@ -48,7 +47,7 @@ class BookExportApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function exportPlainText(int $id)
|
public function exportPlainText(int $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||||
|
|
||||||
return $this->download()->directly($textContent, $book->slug . '.txt');
|
return $this->download()->directly($textContent, $book->slug . '.txt');
|
||||||
|
@ -59,7 +58,7 @@ class BookExportApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function exportMarkdown(int $id)
|
public function exportMarkdown(int $id)
|
||||||
{
|
{
|
||||||
$book = Book::visible()->findOrFail($id);
|
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||||
$markdown = $this->exportFormatter->bookToMarkdown($book);
|
$markdown = $this->exportFormatter->bookToMarkdown($book);
|
||||||
|
|
||||||
return $this->download()->directly($markdown, $book->slug . '.md');
|
return $this->download()->directly($markdown, $book->slug . '.md');
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace BookStack\Entities\Controllers;
|
||||||
|
|
||||||
use BookStack\Activity\ActivityQueries;
|
use BookStack\Activity\ActivityQueries;
|
||||||
use BookStack\Activity\Models\View;
|
use BookStack\Activity\Models\View;
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
use BookStack\Entities\Queries\BookshelfQueries;
|
use BookStack\Entities\Queries\BookshelfQueries;
|
||||||
use BookStack\Entities\Repos\BookshelfRepo;
|
use BookStack\Entities\Repos\BookshelfRepo;
|
||||||
use BookStack\Entities\Tools\ShelfContext;
|
use BookStack\Entities\Tools\ShelfContext;
|
||||||
|
@ -22,6 +22,7 @@ class BookshelfController extends Controller
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected BookshelfRepo $shelfRepo,
|
protected BookshelfRepo $shelfRepo,
|
||||||
protected BookshelfQueries $queries,
|
protected BookshelfQueries $queries,
|
||||||
|
protected BookQueries $bookQueries,
|
||||||
protected ShelfContext $shelfContext,
|
protected ShelfContext $shelfContext,
|
||||||
protected ReferenceFetcher $referenceFetcher,
|
protected ReferenceFetcher $referenceFetcher,
|
||||||
) {
|
) {
|
||||||
|
@ -68,7 +69,7 @@ class BookshelfController extends Controller
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission('bookshelf-create-all');
|
$this->checkPermission('bookshelf-create-all');
|
||||||
$books = Book::visible()->orderBy('name')->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
|
$books = $this->bookQueries->visibleForList()->orderBy('name')->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
|
||||||
$this->setPageTitle(trans('entities.shelves_create'));
|
$this->setPageTitle(trans('entities.shelves_create'));
|
||||||
|
|
||||||
return view('shelves.create', ['books' => $books]);
|
return view('shelves.create', ['books' => $books]);
|
||||||
|
@ -145,7 +146,10 @@ class BookshelfController extends Controller
|
||||||
$this->checkOwnablePermission('bookshelf-update', $shelf);
|
$this->checkOwnablePermission('bookshelf-update', $shelf);
|
||||||
|
|
||||||
$shelfBookIds = $shelf->books()->get(['id'])->pluck('id');
|
$shelfBookIds = $shelf->books()->get(['id'])->pluck('id');
|
||||||
$books = Book::visible()->whereNotIn('id', $shelfBookIds)->orderBy('name')->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
|
$books = $this->bookQueries->visibleForList()
|
||||||
|
->whereNotIn('id', $shelfBookIds)
|
||||||
|
->orderBy('name')
|
||||||
|
->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()]));
|
$this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()]));
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
namespace BookStack\Entities\Controllers;
|
namespace BookStack\Entities\Controllers;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
|
use BookStack\Entities\Queries\ChapterQueries;
|
||||||
use BookStack\Entities\Repos\ChapterRepo;
|
use BookStack\Entities\Repos\ChapterRepo;
|
||||||
use BookStack\Exceptions\PermissionsException;
|
use BookStack\Exceptions\PermissionsException;
|
||||||
use BookStack\Http\ApiController;
|
use BookStack\Http\ApiController;
|
||||||
|
@ -35,7 +36,9 @@ class ChapterApiController extends ApiController
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected ChapterRepo $chapterRepo
|
protected ChapterRepo $chapterRepo,
|
||||||
|
protected ChapterQueries $queries,
|
||||||
|
protected BookQueries $bookQueries,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +47,7 @@ class ChapterApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function list()
|
public function list()
|
||||||
{
|
{
|
||||||
$chapters = Chapter::visible();
|
$chapters = $this->queries->visibleForList();
|
||||||
|
|
||||||
return $this->apiListingResponse($chapters, [
|
return $this->apiListingResponse($chapters, [
|
||||||
'id', 'book_id', 'name', 'slug', 'description', 'priority',
|
'id', 'book_id', 'name', 'slug', 'description', 'priority',
|
||||||
|
@ -60,7 +63,7 @@ class ChapterApiController extends ApiController
|
||||||
$requestData = $this->validate($request, $this->rules['create']);
|
$requestData = $this->validate($request, $this->rules['create']);
|
||||||
|
|
||||||
$bookId = $request->get('book_id');
|
$bookId = $request->get('book_id');
|
||||||
$book = Book::visible()->findOrFail($bookId);
|
$book = $this->bookQueries->findVisibleByIdOrFail(intval($bookId));
|
||||||
$this->checkOwnablePermission('chapter-create', $book);
|
$this->checkOwnablePermission('chapter-create', $book);
|
||||||
|
|
||||||
$chapter = $this->chapterRepo->create($requestData, $book);
|
$chapter = $this->chapterRepo->create($requestData, $book);
|
||||||
|
@ -73,7 +76,7 @@ class ChapterApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function read(string $id)
|
public function read(string $id)
|
||||||
{
|
{
|
||||||
$chapter = Chapter::visible()->findOrFail($id);
|
$chapter = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$chapter = $this->forJsonDisplay($chapter);
|
$chapter = $this->forJsonDisplay($chapter);
|
||||||
|
|
||||||
$chapter->load([
|
$chapter->load([
|
||||||
|
@ -94,7 +97,7 @@ class ChapterApiController extends ApiController
|
||||||
public function update(Request $request, string $id)
|
public function update(Request $request, string $id)
|
||||||
{
|
{
|
||||||
$requestData = $this->validate($request, $this->rules()['update']);
|
$requestData = $this->validate($request, $this->rules()['update']);
|
||||||
$chapter = Chapter::visible()->findOrFail($id);
|
$chapter = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
|
|
||||||
if ($request->has('book_id') && $chapter->book_id !== intval($requestData['book_id'])) {
|
if ($request->has('book_id') && $chapter->book_id !== intval($requestData['book_id'])) {
|
||||||
|
@ -122,7 +125,7 @@ class ChapterApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function delete(string $id)
|
public function delete(string $id)
|
||||||
{
|
{
|
||||||
$chapter = Chapter::visible()->findOrFail($id);
|
$chapter = $this->queries->findVisibleByIdOrFail(intval($id));
|
||||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||||
|
|
||||||
$this->chapterRepo->destroy($chapter);
|
$this->chapterRepo->destroy($chapter);
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
namespace BookStack\Entities\Controllers;
|
namespace BookStack\Entities\Controllers;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Entities\Models\Chapter;
|
|
||||||
use BookStack\Entities\Models\Page;
|
|
||||||
use BookStack\Entities\Queries\PageQueries;
|
use BookStack\Entities\Queries\PageQueries;
|
||||||
use BookStack\Entities\Repos\PageRepo;
|
use BookStack\Entities\Repos\PageRepo;
|
||||||
use BookStack\Exceptions\PermissionsException;
|
use BookStack\Exceptions\PermissionsException;
|
||||||
|
@ -38,6 +36,7 @@ class PageApiController extends ApiController
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected PageRepo $pageRepo,
|
protected PageRepo $pageRepo,
|
||||||
protected PageQueries $queries,
|
protected PageQueries $queries,
|
||||||
|
protected EntityQueries $entityQueries,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ class PageApiController extends ApiController
|
||||||
*/
|
*/
|
||||||
public function list()
|
public function list()
|
||||||
{
|
{
|
||||||
$pages = Page::visible();
|
$pages = $this->queries->visibleForList();
|
||||||
|
|
||||||
return $this->apiListingResponse($pages, [
|
return $this->apiListingResponse($pages, [
|
||||||
'id', 'book_id', 'chapter_id', 'name', 'slug', 'priority',
|
'id', 'book_id', 'chapter_id', 'name', 'slug', 'priority',
|
||||||
|
@ -72,9 +71,9 @@ class PageApiController extends ApiController
|
||||||
$this->validate($request, $this->rules['create']);
|
$this->validate($request, $this->rules['create']);
|
||||||
|
|
||||||
if ($request->has('chapter_id')) {
|
if ($request->has('chapter_id')) {
|
||||||
$parent = Chapter::visible()->findOrFail($request->get('chapter_id'));
|
$parent = $this->entityQueries->chapters->findVisibleByIdOrFail(intval($request->get('chapter_id')));
|
||||||
} else {
|
} else {
|
||||||
$parent = Book::visible()->findOrFail($request->get('book_id'));
|
$parent = $this->entityQueries->books->findVisibleByIdOrFail(intval($request->get('book_id')));
|
||||||
}
|
}
|
||||||
$this->checkOwnablePermission('page-create', $parent);
|
$this->checkOwnablePermission('page-create', $parent);
|
||||||
|
|
||||||
|
@ -120,9 +119,9 @@ class PageApiController extends ApiController
|
||||||
|
|
||||||
$parent = null;
|
$parent = null;
|
||||||
if ($request->has('chapter_id')) {
|
if ($request->has('chapter_id')) {
|
||||||
$parent = Chapter::visible()->findOrFail($request->get('chapter_id'));
|
$parent = $this->entityQueries->chapters->findVisibleByIdOrFail(intval($request->get('chapter_id')));
|
||||||
} elseif ($request->has('book_id')) {
|
} elseif ($request->has('book_id')) {
|
||||||
$parent = Book::visible()->findOrFail($request->get('book_id'));
|
$parent = $this->entityQueries->books->findVisibleByIdOrFail(intval($request->get('book_id')));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($parent && !$parent->matches($page->getParent())) {
|
if ($parent && !$parent->matches($page->getParent())) {
|
||||||
|
|
|
@ -276,8 +276,8 @@ class PageController extends Controller
|
||||||
$this->checkOwnablePermission('page-delete', $page);
|
$this->checkOwnablePermission('page-delete', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()]));
|
||||||
$usedAsTemplate =
|
$usedAsTemplate =
|
||||||
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
|
$this->entityQueries->books->start()->where('default_template_id', '=', $page->id)->count() > 0 ||
|
||||||
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;
|
$this->entityQueries->chapters->start()->where('default_template_id', '=', $page->id)->count() > 0;
|
||||||
|
|
||||||
return view('pages.delete', [
|
return view('pages.delete', [
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
|
@ -298,8 +298,8 @@ class PageController extends Controller
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()]));
|
||||||
$usedAsTemplate =
|
$usedAsTemplate =
|
||||||
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
|
$this->entityQueries->books->start()->where('default_template_id', '=', $page->id)->count() > 0 ||
|
||||||
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;
|
$this->entityQueries->chapters->start()->where('default_template_id', '=', $page->id)->count() > 0;
|
||||||
|
|
||||||
return view('pages.delete', [
|
return view('pages.delete', [
|
||||||
'book' => $page->book,
|
'book' => $page->book,
|
||||||
|
|
|
@ -116,9 +116,9 @@ class RecycleBinController extends Controller
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function empty()
|
public function empty(TrashCan $trash)
|
||||||
{
|
{
|
||||||
$deleteCount = (new TrashCan())->empty();
|
$deleteCount = $trash->empty();
|
||||||
|
|
||||||
$this->logActivity(ActivityType::RECYCLE_BIN_EMPTY);
|
$this->logActivity(ActivityType::RECYCLE_BIN_EMPTY);
|
||||||
$this->showSuccessNotification(trans('settings.recycle_bin_destroy_notification', ['count' => $deleteCount]));
|
$this->showSuccessNotification(trans('settings.recycle_bin_destroy_notification', ['count' => $deleteCount]));
|
||||||
|
|
|
@ -117,20 +117,11 @@ class Book extends Entity implements HasCoverImage
|
||||||
/**
|
/**
|
||||||
* Get the direct child items within this book.
|
* Get the direct child items within this book.
|
||||||
*/
|
*/
|
||||||
public function getDirectChildren(): Collection
|
public function getDirectVisibleChildren(): Collection
|
||||||
{
|
{
|
||||||
$pages = $this->directPages()->scopes('visible')->get();
|
$pages = $this->directPages()->scopes('visible')->get();
|
||||||
$chapters = $this->chapters()->scopes('visible')->get();
|
$chapters = $this->chapters()->scopes('visible')->get();
|
||||||
|
|
||||||
return $pages->concat($chapters)->sortBy('priority')->sortByDesc('draft');
|
return $pages->concat($chapters)->sortBy('priority')->sortByDesc('draft');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a visible book by its slug.
|
|
||||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
|
||||||
*/
|
|
||||||
public static function getBySlug(string $slug): self
|
|
||||||
{
|
|
||||||
return static::visible()->where('slug', '=', $slug)->firstOrFail();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ class BookQueries implements ProvidesEntityQueries
|
||||||
return $this->start()->scopes('visible')->find($id);
|
return $this->start()->scopes('visible')->find($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findVisibleByIdOrFail(int $id): Book
|
||||||
|
{
|
||||||
|
return $this->start()->scopes('visible')->findOrFail($id);
|
||||||
|
}
|
||||||
|
|
||||||
public function findVisibleBySlugOrFail(string $slug): Book
|
public function findVisibleBySlugOrFail(string $slug): Book
|
||||||
{
|
{
|
||||||
/** @var ?Book $book */
|
/** @var ?Book $book */
|
||||||
|
|
|
@ -24,10 +24,17 @@ class ChapterQueries implements ProvidesEntityQueries
|
||||||
return $this->start()->scopes('visible')->find($id);
|
return $this->start()->scopes('visible')->find($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findVisibleByIdOrFail(int $id): Chapter
|
||||||
|
{
|
||||||
|
return $this->start()->scopes('visible')->findOrFail($id);
|
||||||
|
}
|
||||||
|
|
||||||
public function findVisibleBySlugsOrFail(string $bookSlug, string $chapterSlug): Chapter
|
public function findVisibleBySlugsOrFail(string $bookSlug, string $chapterSlug): Chapter
|
||||||
{
|
{
|
||||||
/** @var ?Chapter $chapter */
|
/** @var ?Chapter $chapter */
|
||||||
$chapter = $this->start()->with('book')
|
$chapter = $this->start()
|
||||||
|
->scopes('visible')
|
||||||
|
->with('book')
|
||||||
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
||||||
$query->where('slug', '=', $bookSlug);
|
$query->where('slug', '=', $bookSlug);
|
||||||
})
|
})
|
||||||
|
@ -41,9 +48,19 @@ class ChapterQueries implements ProvidesEntityQueries
|
||||||
return $chapter;
|
return $chapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function usingSlugs(string $bookSlug, string $chapterSlug): Builder
|
||||||
|
{
|
||||||
|
return $this->start()
|
||||||
|
->where('slug', '=', $chapterSlug)
|
||||||
|
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
||||||
|
$query->where('slug', '=', $bookSlug);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function visibleForList(): Builder
|
public function visibleForList(): Builder
|
||||||
{
|
{
|
||||||
return $this->start()
|
return $this->start()
|
||||||
|
->scopes('visible')
|
||||||
->select(array_merge(static::$listAttributes, ['book_slug' => function ($builder) {
|
->select(array_merge(static::$listAttributes, ['book_slug' => function ($builder) {
|
||||||
$builder->select('slug')
|
$builder->select('slug')
|
||||||
->from('books')
|
->from('books')
|
||||||
|
|
|
@ -33,6 +33,7 @@ class PageQueries implements ProvidesEntityQueries
|
||||||
{
|
{
|
||||||
/** @var ?Page $page */
|
/** @var ?Page $page */
|
||||||
$page = $this->start()->with('book')
|
$page = $this->start()->with('book')
|
||||||
|
->scopes('visible')
|
||||||
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
||||||
$query->where('slug', '=', $bookSlug);
|
$query->where('slug', '=', $bookSlug);
|
||||||
})
|
})
|
||||||
|
@ -46,9 +47,19 @@ class PageQueries implements ProvidesEntityQueries
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function usingSlugs(string $bookSlug, string $pageSlug): Builder
|
||||||
|
{
|
||||||
|
return $this->start()
|
||||||
|
->where('slug', '=', $pageSlug)
|
||||||
|
->whereHas('book', function (Builder $query) use ($bookSlug) {
|
||||||
|
$query->where('slug', '=', $bookSlug);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function visibleForList(): Builder
|
public function visibleForList(): Builder
|
||||||
{
|
{
|
||||||
return $this->start()
|
return $this->start()
|
||||||
|
->scopes('visible')
|
||||||
->select(array_merge(Page::$listAttributes, ['book_slug' => function ($builder) {
|
->select(array_merge(Page::$listAttributes, ['book_slug' => function ($builder) {
|
||||||
$builder->select('slug')
|
$builder->select('slug')
|
||||||
->from('books')
|
->from('books')
|
||||||
|
@ -56,6 +67,17 @@ class PageQueries implements ProvidesEntityQueries
|
||||||
}]));
|
}]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function visibleWithContents(): Builder
|
||||||
|
{
|
||||||
|
return $this->start()
|
||||||
|
->scopes('visible')
|
||||||
|
->select(array_merge(Page::$contentAttributes, ['book_slug' => function ($builder) {
|
||||||
|
$builder->select('slug')
|
||||||
|
->from('books')
|
||||||
|
->whereColumn('books.id', '=', 'pages.book_id');
|
||||||
|
}]));
|
||||||
|
}
|
||||||
|
|
||||||
public function currentUserDraftsForList(): Builder
|
public function currentUserDraftsForList(): Builder
|
||||||
{
|
{
|
||||||
return $this->visibleForList()
|
return $this->visibleForList()
|
||||||
|
|
|
@ -17,7 +17,8 @@ class BookRepo
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected BaseRepo $baseRepo,
|
protected BaseRepo $baseRepo,
|
||||||
protected TagRepo $tagRepo,
|
protected TagRepo $tagRepo,
|
||||||
protected ImageRepo $imageRepo
|
protected ImageRepo $imageRepo,
|
||||||
|
protected TrashCan $trashCan,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,10 +74,9 @@ class BookRepo
|
||||||
*/
|
*/
|
||||||
public function destroy(Book $book)
|
public function destroy(Book $book)
|
||||||
{
|
{
|
||||||
$trashCan = new TrashCan();
|
$this->trashCan->softDestroyBook($book);
|
||||||
$trashCan->softDestroyBook($book);
|
|
||||||
Activity::add(ActivityType::BOOK_DELETE, $book);
|
Activity::add(ActivityType::BOOK_DELETE, $book);
|
||||||
|
|
||||||
$trashCan->autoClearOld();
|
$this->trashCan->autoClearOld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
namespace BookStack\Entities\Repos;
|
namespace BookStack\Entities\Repos;
|
||||||
|
|
||||||
use BookStack\Activity\ActivityType;
|
use BookStack\Activity\ActivityType;
|
||||||
use BookStack\Entities\Models\Book;
|
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
use BookStack\Entities\Models\Bookshelf;
|
||||||
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
use BookStack\Entities\Tools\TrashCan;
|
use BookStack\Entities\Tools\TrashCan;
|
||||||
use BookStack\Facades\Activity;
|
use BookStack\Facades\Activity;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
@ -13,6 +13,8 @@ class BookshelfRepo
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected BaseRepo $baseRepo,
|
protected BaseRepo $baseRepo,
|
||||||
|
protected BookQueries $bookQueries,
|
||||||
|
protected TrashCan $trashCan,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ class BookshelfRepo
|
||||||
return intval($id);
|
return intval($id);
|
||||||
});
|
});
|
||||||
|
|
||||||
$syncData = Book::visible()
|
$syncData = $this->bookQueries->visibleForList()
|
||||||
->whereIn('id', $bookIds)
|
->whereIn('id', $bookIds)
|
||||||
->pluck('id')
|
->pluck('id')
|
||||||
->mapWithKeys(function ($bookId) use ($numericIDs) {
|
->mapWithKeys(function ($bookId) use ($numericIDs) {
|
||||||
|
@ -77,9 +79,8 @@ class BookshelfRepo
|
||||||
*/
|
*/
|
||||||
public function destroy(Bookshelf $shelf)
|
public function destroy(Bookshelf $shelf)
|
||||||
{
|
{
|
||||||
$trashCan = new TrashCan();
|
$this->trashCan->softDestroyShelf($shelf);
|
||||||
$trashCan->softDestroyShelf($shelf);
|
|
||||||
Activity::add(ActivityType::BOOKSHELF_DELETE, $shelf);
|
Activity::add(ActivityType::BOOKSHELF_DELETE, $shelf);
|
||||||
$trashCan->autoClearOld();
|
$this->trashCan->autoClearOld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ class ChapterRepo
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected BaseRepo $baseRepo,
|
protected BaseRepo $baseRepo,
|
||||||
protected EntityQueries $entityQueries,
|
protected EntityQueries $entityQueries,
|
||||||
|
protected TrashCan $trashCan,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,10 +60,9 @@ class ChapterRepo
|
||||||
*/
|
*/
|
||||||
public function destroy(Chapter $chapter)
|
public function destroy(Chapter $chapter)
|
||||||
{
|
{
|
||||||
$trashCan = new TrashCan();
|
$this->trashCan->softDestroyChapter($chapter);
|
||||||
$trashCan->softDestroyChapter($chapter);
|
|
||||||
Activity::add(ActivityType::CHAPTER_DELETE, $chapter);
|
Activity::add(ActivityType::CHAPTER_DELETE, $chapter);
|
||||||
$trashCan->autoClearOld();
|
$this->trashCan->autoClearOld();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,7 +27,8 @@ class PageRepo
|
||||||
protected RevisionRepo $revisionRepo,
|
protected RevisionRepo $revisionRepo,
|
||||||
protected EntityQueries $entityQueries,
|
protected EntityQueries $entityQueries,
|
||||||
protected ReferenceStore $referenceStore,
|
protected ReferenceStore $referenceStore,
|
||||||
protected ReferenceUpdater $referenceUpdater
|
protected ReferenceUpdater $referenceUpdater,
|
||||||
|
protected TrashCan $trashCan,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +185,9 @@ class PageRepo
|
||||||
*/
|
*/
|
||||||
public function destroy(Page $page)
|
public function destroy(Page $page)
|
||||||
{
|
{
|
||||||
$trashCan = new TrashCan();
|
$this->trashCan->softDestroyPage($page);
|
||||||
$trashCan->softDestroyPage($page);
|
|
||||||
Activity::add(ActivityType::PAGE_DELETE, $page);
|
Activity::add(ActivityType::PAGE_DELETE, $page);
|
||||||
$trashCan->autoClearOld();
|
$this->trashCan->autoClearOld();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,15 +7,17 @@ use BookStack\Entities\Models\BookChild;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Entity;
|
use BookStack\Entities\Models\Entity;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class BookContents
|
class BookContents
|
||||||
{
|
{
|
||||||
protected Book $book;
|
protected EntityQueries $queries;
|
||||||
|
|
||||||
public function __construct(Book $book)
|
public function __construct(
|
||||||
{
|
protected Book $book,
|
||||||
$this->book = $book;
|
) {
|
||||||
|
$this->queries = app()->make(EntityQueries::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,10 +25,12 @@ class BookContents
|
||||||
*/
|
*/
|
||||||
public function getLastPriority(): int
|
public function getLastPriority(): int
|
||||||
{
|
{
|
||||||
$maxPage = Page::visible()->where('book_id', '=', $this->book->id)
|
$maxPage = $this->book->pages()
|
||||||
->where('draft', '=', false)
|
->where('draft', '=', false)
|
||||||
->where('chapter_id', '=', 0)->max('priority');
|
->where('chapter_id', '=', 0)
|
||||||
$maxChapter = Chapter::visible()->where('book_id', '=', $this->book->id)
|
->max('priority');
|
||||||
|
|
||||||
|
$maxChapter = $this->book->chapters()
|
||||||
->max('priority');
|
->max('priority');
|
||||||
|
|
||||||
return max($maxChapter, $maxPage, 1);
|
return max($maxChapter, $maxPage, 1);
|
||||||
|
@ -38,7 +42,7 @@ class BookContents
|
||||||
public function getTree(bool $showDrafts = false, bool $renderPages = false): Collection
|
public function getTree(bool $showDrafts = false, bool $renderPages = false): Collection
|
||||||
{
|
{
|
||||||
$pages = $this->getPages($showDrafts, $renderPages);
|
$pages = $this->getPages($showDrafts, $renderPages);
|
||||||
$chapters = Chapter::visible()->where('book_id', '=', $this->book->id)->get();
|
$chapters = $this->book->chapters()->scopes('visible')->get();
|
||||||
$all = collect()->concat($pages)->concat($chapters);
|
$all = collect()->concat($pages)->concat($chapters);
|
||||||
$chapterMap = $chapters->keyBy('id');
|
$chapterMap = $chapters->keyBy('id');
|
||||||
$lonePages = collect();
|
$lonePages = collect();
|
||||||
|
@ -87,15 +91,17 @@ class BookContents
|
||||||
*/
|
*/
|
||||||
protected function getPages(bool $showDrafts = false, bool $getPageContent = false): Collection
|
protected function getPages(bool $showDrafts = false, bool $getPageContent = false): Collection
|
||||||
{
|
{
|
||||||
$query = Page::visible()
|
if ($getPageContent) {
|
||||||
->select($getPageContent ? Page::$contentAttributes : Page::$listAttributes)
|
$query = $this->queries->pages->visibleWithContents();
|
||||||
->where('book_id', '=', $this->book->id);
|
} else {
|
||||||
|
$query = $this->queries->pages->visibleForList();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$showDrafts) {
|
if (!$showDrafts) {
|
||||||
$query->where('draft', '=', false);
|
$query->where('draft', '=', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->get();
|
return $query->where('book_id', '=', $this->book->id)->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,7 +132,7 @@ class BookContents
|
||||||
|
|
||||||
/** @var Book[] $booksInvolved */
|
/** @var Book[] $booksInvolved */
|
||||||
$booksInvolved = array_values(array_filter($modelMap, function (string $key) {
|
$booksInvolved = array_values(array_filter($modelMap, function (string $key) {
|
||||||
return strpos($key, 'book:') === 0;
|
return str_starts_with($key, 'book:');
|
||||||
}, ARRAY_FILTER_USE_KEY));
|
}, ARRAY_FILTER_USE_KEY));
|
||||||
|
|
||||||
// Update permissions of books involved
|
// Update permissions of books involved
|
||||||
|
@ -279,7 +285,7 @@ class BookContents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pages = Page::visible()->whereIn('id', array_unique($ids['page']))->get(Page::$listAttributes);
|
$pages = $this->queries->pages->visibleForList()->whereIn('id', array_unique($ids['page']))->get();
|
||||||
/** @var Page $page */
|
/** @var Page $page */
|
||||||
foreach ($pages as $page) {
|
foreach ($pages as $page) {
|
||||||
$modelMap['page:' . $page->id] = $page;
|
$modelMap['page:' . $page->id] = $page;
|
||||||
|
@ -289,14 +295,14 @@ class BookContents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$chapters = Chapter::visible()->whereIn('id', array_unique($ids['chapter']))->get();
|
$chapters = $this->queries->chapters->visibleForList()->whereIn('id', array_unique($ids['chapter']))->get();
|
||||||
/** @var Chapter $chapter */
|
/** @var Chapter $chapter */
|
||||||
foreach ($chapters as $chapter) {
|
foreach ($chapters as $chapter) {
|
||||||
$modelMap['chapter:' . $chapter->id] = $chapter;
|
$modelMap['chapter:' . $chapter->id] = $chapter;
|
||||||
$ids['book'][] = $chapter->book_id;
|
$ids['book'][] = $chapter->book_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$books = Book::visible()->whereIn('id', array_unique($ids['book']))->get();
|
$books = $this->queries->books->visibleForList()->whereIn('id', array_unique($ids['book']))->get();
|
||||||
/** @var Book $book */
|
/** @var Book $book */
|
||||||
foreach ($books as $book) {
|
foreach ($books as $book) {
|
||||||
$modelMap['book:' . $book->id] = $book;
|
$modelMap['book:' . $book->id] = $book;
|
||||||
|
|
|
@ -77,7 +77,7 @@ class Cloner
|
||||||
$copyBook = $this->bookRepo->create($bookDetails);
|
$copyBook = $this->bookRepo->create($bookDetails);
|
||||||
|
|
||||||
// Clone contents
|
// Clone contents
|
||||||
$directChildren = $original->getDirectChildren();
|
$directChildren = $original->getDirectVisibleChildren();
|
||||||
foreach ($directChildren as $child) {
|
foreach ($directChildren as $child) {
|
||||||
if ($child instanceof Chapter && userCan('chapter-create', $copyBook)) {
|
if ($child instanceof Chapter && userCan('chapter-create', $copyBook)) {
|
||||||
$this->cloneChapter($child, $copyBook, $child->name);
|
$this->cloneChapter($child, $copyBook, $child->name);
|
||||||
|
|
|
@ -7,10 +7,16 @@ use BookStack\Entities\Models\Book;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
use BookStack\Entities\Models\Bookshelf;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class SiblingFetcher
|
class SiblingFetcher
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected EntityQueries $queries,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search among the siblings of the entity of given type and id.
|
* Search among the siblings of the entity of given type and id.
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +32,7 @@ class SiblingFetcher
|
||||||
|
|
||||||
// Page in book or chapter
|
// Page in book or chapter
|
||||||
if (($entity instanceof Page && !$entity->chapter) || $entity instanceof Chapter) {
|
if (($entity instanceof Page && !$entity->chapter) || $entity instanceof Chapter) {
|
||||||
$entities = $entity->book->getDirectChildren();
|
$entities = $entity->book->getDirectVisibleChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Book
|
// Book
|
||||||
|
@ -36,13 +42,13 @@ class SiblingFetcher
|
||||||
if ($contextShelf) {
|
if ($contextShelf) {
|
||||||
$entities = $contextShelf->visibleBooks()->get();
|
$entities = $contextShelf->visibleBooks()->get();
|
||||||
} else {
|
} else {
|
||||||
$entities = Book::visible()->get();
|
$entities = $this->queries->books->visibleForList()->get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shelf
|
// Shelf
|
||||||
if ($entity instanceof Bookshelf) {
|
if ($entity instanceof Bookshelf) {
|
||||||
$entities = Bookshelf::visible()->get();
|
$entities = $this->queries->shelves->visibleForList()->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entities;
|
return $entities;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use BookStack\Entities\Models\Deletion;
|
||||||
use BookStack\Entities\Models\Entity;
|
use BookStack\Entities\Models\Entity;
|
||||||
use BookStack\Entities\Models\HasCoverImage;
|
use BookStack\Entities\Models\HasCoverImage;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Exceptions\NotifyException;
|
use BookStack\Exceptions\NotifyException;
|
||||||
use BookStack\Facades\Activity;
|
use BookStack\Facades\Activity;
|
||||||
use BookStack\Uploads\AttachmentService;
|
use BookStack\Uploads\AttachmentService;
|
||||||
|
@ -20,6 +21,11 @@ use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class TrashCan
|
class TrashCan
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected EntityQueries $queries,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a shelf to the recycle bin.
|
* Send a shelf to the recycle bin.
|
||||||
*
|
*
|
||||||
|
@ -203,11 +209,13 @@ class TrashCan
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove book template usages
|
// Remove book template usages
|
||||||
Book::query()->where('default_template_id', '=', $page->id)
|
$this->queries->books->start()
|
||||||
|
->where('default_template_id', '=', $page->id)
|
||||||
->update(['default_template_id' => null]);
|
->update(['default_template_id' => null]);
|
||||||
|
|
||||||
// Remove chapter template usages
|
// Remove chapter template usages
|
||||||
Chapter::query()->where('default_template_id', '=', $page->id)
|
$this->queries->chapters->start()
|
||||||
|
->where('default_template_id', '=', $page->id)
|
||||||
->update(['default_template_id' => null]);
|
->update(['default_template_id' => null]);
|
||||||
|
|
||||||
$page->forceDelete();
|
$page->forceDelete();
|
||||||
|
|
|
@ -8,6 +8,7 @@ use BookStack\Entities\Models\Bookshelf;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Entity;
|
use BookStack\Entities\Models\Entity;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Permissions\Models\JointPermission;
|
use BookStack\Permissions\Models\JointPermission;
|
||||||
use BookStack\Users\Models\Role;
|
use BookStack\Users\Models\Role;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
@ -20,6 +21,12 @@ use Illuminate\Support\Facades\DB;
|
||||||
*/
|
*/
|
||||||
class JointPermissionBuilder
|
class JointPermissionBuilder
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected EntityQueries $queries,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-generate all entity permission from scratch.
|
* Re-generate all entity permission from scratch.
|
||||||
*/
|
*/
|
||||||
|
@ -36,7 +43,7 @@ class JointPermissionBuilder
|
||||||
});
|
});
|
||||||
|
|
||||||
// Chunk through all bookshelves
|
// Chunk through all bookshelves
|
||||||
Bookshelf::query()->withTrashed()->select(['id', 'owned_by'])
|
$this->queries->shelves->start()->withTrashed()->select(['id', 'owned_by'])
|
||||||
->chunk(50, function (EloquentCollection $shelves) use ($roles) {
|
->chunk(50, function (EloquentCollection $shelves) use ($roles) {
|
||||||
$this->createManyJointPermissions($shelves->all(), $roles);
|
$this->createManyJointPermissions($shelves->all(), $roles);
|
||||||
});
|
});
|
||||||
|
@ -88,7 +95,7 @@ class JointPermissionBuilder
|
||||||
});
|
});
|
||||||
|
|
||||||
// Chunk through all bookshelves
|
// Chunk through all bookshelves
|
||||||
Bookshelf::query()->select(['id', 'owned_by'])
|
$this->queries->shelves->start()->select(['id', 'owned_by'])
|
||||||
->chunk(100, function ($shelves) use ($roles) {
|
->chunk(100, function ($shelves) use ($roles) {
|
||||||
$this->createManyJointPermissions($shelves->all(), $roles);
|
$this->createManyJointPermissions($shelves->all(), $roles);
|
||||||
});
|
});
|
||||||
|
@ -99,7 +106,7 @@ class JointPermissionBuilder
|
||||||
*/
|
*/
|
||||||
protected function bookFetchQuery(): Builder
|
protected function bookFetchQuery(): Builder
|
||||||
{
|
{
|
||||||
return Book::query()->withTrashed()
|
return $this->queries->books->start()->withTrashed()
|
||||||
->select(['id', 'owned_by'])->with([
|
->select(['id', 'owned_by'])->with([
|
||||||
'chapters' => function ($query) {
|
'chapters' => function ($query) {
|
||||||
$query->withTrashed()->select(['id', 'owned_by', 'book_id']);
|
$query->withTrashed()->select(['id', 'owned_by', 'book_id']);
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
|
|
||||||
namespace BookStack\Permissions;
|
namespace BookStack\Permissions;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
|
||||||
use BookStack\Entities\Models\Page;
|
|
||||||
use BookStack\Entities\Tools\PermissionsUpdater;
|
use BookStack\Entities\Tools\PermissionsUpdater;
|
||||||
use BookStack\Http\Controller;
|
use BookStack\Http\Controller;
|
||||||
use BookStack\Permissions\Models\EntityPermission;
|
use BookStack\Permissions\Models\EntityPermission;
|
||||||
|
@ -14,19 +11,18 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class PermissionsController extends Controller
|
class PermissionsController extends Controller
|
||||||
{
|
{
|
||||||
protected PermissionsUpdater $permissionsUpdater;
|
public function __construct(
|
||||||
|
protected PermissionsUpdater $permissionsUpdater,
|
||||||
public function __construct(PermissionsUpdater $permissionsUpdater)
|
protected EntityQueries $queries,
|
||||||
{
|
) {
|
||||||
$this->permissionsUpdater = $permissionsUpdater;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the Permissions view for a page.
|
* Show the permissions view for a page.
|
||||||
*/
|
*/
|
||||||
public function showForPage(string $bookSlug, string $pageSlug)
|
public function showForPage(string $bookSlug, string $pageSlug)
|
||||||
{
|
{
|
||||||
$page = Page::getBySlugs($bookSlug, $pageSlug);
|
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.pages_permissions'));
|
$this->setPageTitle(trans('entities.pages_permissions'));
|
||||||
|
@ -41,7 +37,7 @@ class PermissionsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function updateForPage(Request $request, string $bookSlug, string $pageSlug)
|
public function updateForPage(Request $request, string $bookSlug, string $pageSlug)
|
||||||
{
|
{
|
||||||
$page = Page::getBySlugs($bookSlug, $pageSlug);
|
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||||
|
|
||||||
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
||||||
|
@ -52,11 +48,11 @@ class PermissionsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the Restrictions view for a chapter.
|
* Show the permissions view for a chapter.
|
||||||
*/
|
*/
|
||||||
public function showForChapter(string $bookSlug, string $chapterSlug)
|
public function showForChapter(string $bookSlug, string $chapterSlug)
|
||||||
{
|
{
|
||||||
$chapter = Chapter::getBySlugs($bookSlug, $chapterSlug);
|
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.chapters_permissions'));
|
$this->setPageTitle(trans('entities.chapters_permissions'));
|
||||||
|
@ -67,11 +63,11 @@ class PermissionsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the restrictions for a chapter.
|
* Set the permissions for a chapter.
|
||||||
*/
|
*/
|
||||||
public function updateForChapter(Request $request, string $bookSlug, string $chapterSlug)
|
public function updateForChapter(Request $request, string $bookSlug, string $chapterSlug)
|
||||||
{
|
{
|
||||||
$chapter = Chapter::getBySlugs($bookSlug, $chapterSlug);
|
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
|
|
||||||
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
||||||
|
@ -86,7 +82,7 @@ class PermissionsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function showForBook(string $slug)
|
public function showForBook(string $slug)
|
||||||
{
|
{
|
||||||
$book = Book::getBySlug($slug);
|
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.books_permissions'));
|
$this->setPageTitle(trans('entities.books_permissions'));
|
||||||
|
@ -97,11 +93,11 @@ class PermissionsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the restrictions for a book.
|
* Set the permissions for a book.
|
||||||
*/
|
*/
|
||||||
public function updateForBook(Request $request, string $slug)
|
public function updateForBook(Request $request, string $slug)
|
||||||
{
|
{
|
||||||
$book = Book::getBySlug($slug);
|
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
|
|
||||||
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
||||||
|
@ -116,7 +112,7 @@ class PermissionsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function showForShelf(string $slug)
|
public function showForShelf(string $slug)
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::getBySlug($slug);
|
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||||
|
|
||||||
$this->setPageTitle(trans('entities.shelves_permissions'));
|
$this->setPageTitle(trans('entities.shelves_permissions'));
|
||||||
|
@ -131,7 +127,7 @@ class PermissionsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function updateForShelf(Request $request, string $slug)
|
public function updateForShelf(Request $request, string $slug)
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::getBySlug($slug);
|
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||||
|
|
||||||
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
||||||
|
@ -146,7 +142,7 @@ class PermissionsController extends Controller
|
||||||
*/
|
*/
|
||||||
public function copyShelfPermissionsToBooks(string $slug)
|
public function copyShelfPermissionsToBooks(string $slug)
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::getBySlug($slug);
|
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||||
|
|
||||||
$updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
$updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace BookStack\References;
|
namespace BookStack\References;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\References\ModelResolvers\BookLinkModelResolver;
|
use BookStack\References\ModelResolvers\BookLinkModelResolver;
|
||||||
use BookStack\References\ModelResolvers\BookshelfLinkModelResolver;
|
use BookStack\References\ModelResolvers\BookshelfLinkModelResolver;
|
||||||
use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
|
use BookStack\References\ModelResolvers\ChapterLinkModelResolver;
|
||||||
|
@ -85,12 +86,14 @@ class CrossLinkParser
|
||||||
*/
|
*/
|
||||||
public static function createWithEntityResolvers(): self
|
public static function createWithEntityResolvers(): self
|
||||||
{
|
{
|
||||||
|
$queries = app()->make(EntityQueries::class);
|
||||||
|
|
||||||
return new self([
|
return new self([
|
||||||
new PagePermalinkModelResolver(),
|
new PagePermalinkModelResolver($queries->pages),
|
||||||
new PageLinkModelResolver(),
|
new PageLinkModelResolver($queries->pages),
|
||||||
new ChapterLinkModelResolver(),
|
new ChapterLinkModelResolver($queries->chapters),
|
||||||
new BookLinkModelResolver(),
|
new BookLinkModelResolver($queries->books),
|
||||||
new BookshelfLinkModelResolver(),
|
new BookshelfLinkModelResolver($queries->shelves),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,15 @@ namespace BookStack\References\ModelResolvers;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Models\Book;
|
||||||
|
use BookStack\Entities\Queries\BookQueries;
|
||||||
|
|
||||||
class BookLinkModelResolver implements CrossLinkModelResolver
|
class BookLinkModelResolver implements CrossLinkModelResolver
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected BookQueries $queries
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function resolve(string $link): ?Model
|
public function resolve(string $link): ?Model
|
||||||
{
|
{
|
||||||
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '([#?\/]|$)/';
|
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '([#?\/]|$)/';
|
||||||
|
@ -19,7 +25,7 @@ class BookLinkModelResolver implements CrossLinkModelResolver
|
||||||
$bookSlug = $matches[1];
|
$bookSlug = $matches[1];
|
||||||
|
|
||||||
/** @var ?Book $model */
|
/** @var ?Book $model */
|
||||||
$model = Book::query()->where('slug', '=', $bookSlug)->first(['id']);
|
$model = $this->queries->start()->where('slug', '=', $bookSlug)->first(['id']);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,14 @@ namespace BookStack\References\ModelResolvers;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
use BookStack\Entities\Models\Bookshelf;
|
||||||
|
use BookStack\Entities\Queries\BookshelfQueries;
|
||||||
|
|
||||||
class BookshelfLinkModelResolver implements CrossLinkModelResolver
|
class BookshelfLinkModelResolver implements CrossLinkModelResolver
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected BookshelfQueries $queries
|
||||||
|
) {
|
||||||
|
}
|
||||||
public function resolve(string $link): ?Model
|
public function resolve(string $link): ?Model
|
||||||
{
|
{
|
||||||
$pattern = '/^' . preg_quote(url('/shelves'), '/') . '\/([\w-]+)' . '([#?\/]|$)/';
|
$pattern = '/^' . preg_quote(url('/shelves'), '/') . '\/([\w-]+)' . '([#?\/]|$)/';
|
||||||
|
@ -19,7 +24,7 @@ class BookshelfLinkModelResolver implements CrossLinkModelResolver
|
||||||
$shelfSlug = $matches[1];
|
$shelfSlug = $matches[1];
|
||||||
|
|
||||||
/** @var ?Bookshelf $model */
|
/** @var ?Bookshelf $model */
|
||||||
$model = Bookshelf::query()->where('slug', '=', $shelfSlug)->first(['id']);
|
$model = $this->queries->start()->where('slug', '=', $shelfSlug)->first(['id']);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,15 @@ namespace BookStack\References\ModelResolvers;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
|
use BookStack\Entities\Queries\ChapterQueries;
|
||||||
|
|
||||||
class ChapterLinkModelResolver implements CrossLinkModelResolver
|
class ChapterLinkModelResolver implements CrossLinkModelResolver
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected ChapterQueries $queries
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function resolve(string $link): ?Model
|
public function resolve(string $link): ?Model
|
||||||
{
|
{
|
||||||
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '\/chapter\/' . '([\w-]+)' . '([#?\/]|$)/';
|
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '\/chapter\/' . '([\w-]+)' . '([#?\/]|$)/';
|
||||||
|
@ -20,7 +26,7 @@ class ChapterLinkModelResolver implements CrossLinkModelResolver
|
||||||
$chapterSlug = $matches[2];
|
$chapterSlug = $matches[2];
|
||||||
|
|
||||||
/** @var ?Chapter $model */
|
/** @var ?Chapter $model */
|
||||||
$model = Chapter::query()->whereSlugs($bookSlug, $chapterSlug)->first(['id']);
|
$model = $this->queries->usingSlugs($bookSlug, $chapterSlug)->first(['id']);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,15 @@ namespace BookStack\References\ModelResolvers;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\PageQueries;
|
||||||
|
|
||||||
class PageLinkModelResolver implements CrossLinkModelResolver
|
class PageLinkModelResolver implements CrossLinkModelResolver
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected PageQueries $queries
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function resolve(string $link): ?Model
|
public function resolve(string $link): ?Model
|
||||||
{
|
{
|
||||||
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '\/page\/' . '([\w-]+)' . '([#?\/]|$)/';
|
$pattern = '/^' . preg_quote(url('/books'), '/') . '\/([\w-]+)' . '\/page\/' . '([\w-]+)' . '([#?\/]|$)/';
|
||||||
|
@ -20,7 +26,7 @@ class PageLinkModelResolver implements CrossLinkModelResolver
|
||||||
$pageSlug = $matches[2];
|
$pageSlug = $matches[2];
|
||||||
|
|
||||||
/** @var ?Page $model */
|
/** @var ?Page $model */
|
||||||
$model = Page::query()->whereSlugs($bookSlug, $pageSlug)->first(['id']);
|
$model = $this->queries->usingSlugs($bookSlug, $pageSlug)->first(['id']);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,15 @@ namespace BookStack\References\ModelResolvers;
|
||||||
|
|
||||||
use BookStack\App\Model;
|
use BookStack\App\Model;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\PageQueries;
|
||||||
|
|
||||||
class PagePermalinkModelResolver implements CrossLinkModelResolver
|
class PagePermalinkModelResolver implements CrossLinkModelResolver
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected PageQueries $queries
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function resolve(string $link): ?Model
|
public function resolve(string $link): ?Model
|
||||||
{
|
{
|
||||||
$pattern = '/^' . preg_quote(url('/link'), '/') . '\/(\d+)/';
|
$pattern = '/^' . preg_quote(url('/link'), '/') . '\/(\d+)/';
|
||||||
|
@ -18,7 +24,7 @@ class PagePermalinkModelResolver implements CrossLinkModelResolver
|
||||||
|
|
||||||
$id = intval($matches[1]);
|
$id = intval($matches[1]);
|
||||||
/** @var ?Page $model */
|
/** @var ?Page $model */
|
||||||
$model = Page::query()->find($id, ['id']);
|
$model = $this->queries->start()->find($id, ['id']);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,14 @@ use BookStack\Entities\Models\Book;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
use BookStack\Entities\Models\Bookshelf;
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Http\Controller;
|
use BookStack\Http\Controller;
|
||||||
|
|
||||||
class ReferenceController extends Controller
|
class ReferenceController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected ReferenceFetcher $referenceFetcher
|
protected ReferenceFetcher $referenceFetcher,
|
||||||
|
protected EntityQueries $queries,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ class ReferenceController extends Controller
|
||||||
*/
|
*/
|
||||||
public function page(string $bookSlug, string $pageSlug)
|
public function page(string $bookSlug, string $pageSlug)
|
||||||
{
|
{
|
||||||
$page = Page::getBySlugs($bookSlug, $pageSlug);
|
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||||
$references = $this->referenceFetcher->getReferencesToEntity($page);
|
$references = $this->referenceFetcher->getReferencesToEntity($page);
|
||||||
|
|
||||||
return view('pages.references', [
|
return view('pages.references', [
|
||||||
|
@ -34,7 +36,7 @@ class ReferenceController extends Controller
|
||||||
*/
|
*/
|
||||||
public function chapter(string $bookSlug, string $chapterSlug)
|
public function chapter(string $bookSlug, string $chapterSlug)
|
||||||
{
|
{
|
||||||
$chapter = Chapter::getBySlugs($bookSlug, $chapterSlug);
|
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||||
$references = $this->referenceFetcher->getReferencesToEntity($chapter);
|
$references = $this->referenceFetcher->getReferencesToEntity($chapter);
|
||||||
|
|
||||||
return view('chapters.references', [
|
return view('chapters.references', [
|
||||||
|
@ -48,7 +50,7 @@ class ReferenceController extends Controller
|
||||||
*/
|
*/
|
||||||
public function book(string $slug)
|
public function book(string $slug)
|
||||||
{
|
{
|
||||||
$book = Book::getBySlug($slug);
|
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
|
||||||
$references = $this->referenceFetcher->getReferencesToEntity($book);
|
$references = $this->referenceFetcher->getReferencesToEntity($book);
|
||||||
|
|
||||||
return view('books.references', [
|
return view('books.references', [
|
||||||
|
@ -62,7 +64,7 @@ class ReferenceController extends Controller
|
||||||
*/
|
*/
|
||||||
public function shelf(string $slug)
|
public function shelf(string $slug)
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::getBySlug($slug);
|
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||||
$references = $this->referenceFetcher->getReferencesToEntity($shelf);
|
$references = $this->referenceFetcher->getReferencesToEntity($shelf);
|
||||||
|
|
||||||
return view('shelves.references', [
|
return view('shelves.references', [
|
||||||
|
|
|
@ -130,12 +130,12 @@ class SearchController extends Controller
|
||||||
/**
|
/**
|
||||||
* Search siblings items in the system.
|
* Search siblings items in the system.
|
||||||
*/
|
*/
|
||||||
public function searchSiblings(Request $request)
|
public function searchSiblings(Request $request, SiblingFetcher $siblingFetcher)
|
||||||
{
|
{
|
||||||
$type = $request->get('entity_type', null);
|
$type = $request->get('entity_type', null);
|
||||||
$id = $request->get('entity_id', null);
|
$id = $request->get('entity_id', null);
|
||||||
|
|
||||||
$entities = (new SiblingFetcher())->fetch($type, $id);
|
$entities = $siblingFetcher->fetch($type, $id);
|
||||||
|
|
||||||
return view('entities.list-basic', ['entities' => $entities, 'style' => 'compact']);
|
return view('entities.list-basic', ['entities' => $entities, 'style' => 'compact']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class MaintenanceController extends Controller
|
||||||
/**
|
/**
|
||||||
* Show the page for application maintenance.
|
* Show the page for application maintenance.
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index(TrashCan $trashCan)
|
||||||
{
|
{
|
||||||
$this->checkPermission('settings-manage');
|
$this->checkPermission('settings-manage');
|
||||||
$this->setPageTitle(trans('settings.maint'));
|
$this->setPageTitle(trans('settings.maint'));
|
||||||
|
@ -23,7 +23,7 @@ class MaintenanceController extends Controller
|
||||||
$version = trim(file_get_contents(base_path('version')));
|
$version = trim(file_get_contents(base_path('version')));
|
||||||
|
|
||||||
// Recycle bin details
|
// Recycle bin details
|
||||||
$recycleStats = (new TrashCan())->getTrashedCounts();
|
$recycleStats = $trashCan->getTrashedCounts();
|
||||||
|
|
||||||
return view('settings.maintenance', [
|
return view('settings.maintenance', [
|
||||||
'version' => $version,
|
'version' => $version,
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace BookStack\Uploads;
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Models\Book;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
use BookStack\Entities\Models\Bookshelf;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Exceptions\ImageUploadException;
|
use BookStack\Exceptions\ImageUploadException;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
@ -20,6 +21,7 @@ class ImageService
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected ImageStorage $storage,
|
protected ImageStorage $storage,
|
||||||
protected ImageResizer $resizer,
|
protected ImageResizer $resizer,
|
||||||
|
protected EntityQueries $queries,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,15 +280,15 @@ class ImageService
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($imageType === 'gallery' || $imageType === 'drawio') {
|
if ($imageType === 'gallery' || $imageType === 'drawio') {
|
||||||
return Page::visible()->where('id', '=', $image->uploaded_to)->exists();
|
return $this->queries->pages->visibleForList()->where('id', '=', $image->uploaded_to)->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($imageType === 'cover_book') {
|
if ($imageType === 'cover_book') {
|
||||||
return Book::visible()->where('id', '=', $image->uploaded_to)->exists();
|
return $this->queries->books->visibleForList()->where('id', '=', $image->uploaded_to)->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($imageType === 'cover_bookshelf') {
|
if ($imageType === 'cover_bookshelf') {
|
||||||
return Bookshelf::visible()->where('id', '=', $image->uploaded_to)->exists();
|
return $this->queries->shelves->visibleForList()->where('id', '=', $image->uploaded_to)->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -10,16 +10,25 @@ use BookStack\Users\UserRepo;
|
||||||
|
|
||||||
class UserProfileController extends Controller
|
class UserProfileController extends Controller
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected UserRepo $userRepo,
|
||||||
|
protected ActivityQueries $activityQueries,
|
||||||
|
protected UserContentCounts $contentCounts,
|
||||||
|
protected UserRecentlyCreatedContent $recentlyCreatedContent
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the user profile page.
|
* Show the user profile page.
|
||||||
*/
|
*/
|
||||||
public function show(UserRepo $repo, ActivityQueries $activities, string $slug)
|
public function show(string $slug)
|
||||||
{
|
{
|
||||||
$user = $repo->getBySlug($slug);
|
$user = $this->userRepo->getBySlug($slug);
|
||||||
|
|
||||||
$userActivity = $activities->userActivity($user);
|
$userActivity = $this->activityQueries->userActivity($user);
|
||||||
$recentlyCreated = (new UserRecentlyCreatedContent())->run($user, 5);
|
$recentlyCreated = $this->recentlyCreatedContent->run($user, 5);
|
||||||
$assetCounts = (new UserContentCounts())->run($user);
|
$assetCounts = $this->contentCounts->run($user);
|
||||||
|
|
||||||
$this->setPageTitle($user->name);
|
$this->setPageTitle($user->name);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
|
|
||||||
namespace BookStack\Users\Queries;
|
namespace BookStack\Users\Queries;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
|
||||||
use BookStack\Entities\Models\Page;
|
|
||||||
use BookStack\Users\Models\User;
|
use BookStack\Users\Models\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +10,12 @@ use BookStack\Users\Models\User;
|
||||||
*/
|
*/
|
||||||
class UserContentCounts
|
class UserContentCounts
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected EntityQueries $queries,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{pages: int, chapters: int, books: int, shelves: int}
|
* @return array{pages: int, chapters: int, books: int, shelves: int}
|
||||||
*/
|
*/
|
||||||
|
@ -21,10 +24,10 @@ class UserContentCounts
|
||||||
$createdBy = ['created_by' => $user->id];
|
$createdBy = ['created_by' => $user->id];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'pages' => Page::visible()->where($createdBy)->count(),
|
'pages' => $this->queries->pages->visibleForList()->where($createdBy)->count(),
|
||||||
'chapters' => Chapter::visible()->where($createdBy)->count(),
|
'chapters' => $this->queries->chapters->visibleForList()->where($createdBy)->count(),
|
||||||
'books' => Book::visible()->where($createdBy)->count(),
|
'books' => $this->queries->books->visibleForList()->where($createdBy)->count(),
|
||||||
'shelves' => Bookshelf::visible()->where($createdBy)->count(),
|
'shelves' => $this->queries->shelves->visibleForList()->where($createdBy)->count(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
|
|
||||||
namespace BookStack\Users\Queries;
|
namespace BookStack\Users\Queries;
|
||||||
|
|
||||||
use BookStack\Entities\Models\Book;
|
use BookStack\Entities\Queries\EntityQueries;
|
||||||
use BookStack\Entities\Models\Bookshelf;
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
|
||||||
use BookStack\Entities\Models\Page;
|
|
||||||
use BookStack\Users\Models\User;
|
use BookStack\Users\Models\User;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
@ -15,6 +12,11 @@ use Illuminate\Database\Eloquent\Collection;
|
||||||
*/
|
*/
|
||||||
class UserRecentlyCreatedContent
|
class UserRecentlyCreatedContent
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected EntityQueries $queries,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{pages: Collection, chapters: Collection, books: Collection, shelves: Collection}
|
* @return array{pages: Collection, chapters: Collection, books: Collection, shelves: Collection}
|
||||||
*/
|
*/
|
||||||
|
@ -28,10 +30,10 @@ class UserRecentlyCreatedContent
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'pages' => $query(Page::visible()->where('draft', '=', false)),
|
'pages' => $query($this->queries->pages->visibleForList()->where('draft', '=', false)),
|
||||||
'chapters' => $query(Chapter::visible()),
|
'chapters' => $query($this->queries->chapters->visibleForList()),
|
||||||
'books' => $query(Book::visible()),
|
'books' => $query($this->queries->books->visibleForList()),
|
||||||
'shelves' => $query(Bookshelf::visible()),
|
'shelves' => $query($this->queries->shelves->visibleForList()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,7 +317,7 @@ class BookTest extends TestCase
|
||||||
$copy = Book::query()->where('name', '=', 'My copy book')->first();
|
$copy = Book::query()->where('name', '=', 'My copy book')->first();
|
||||||
|
|
||||||
$resp->assertRedirect($copy->getUrl());
|
$resp->assertRedirect($copy->getUrl());
|
||||||
$this->assertEquals($book->getDirectChildren()->count(), $copy->getDirectChildren()->count());
|
$this->assertEquals($book->getDirectVisibleChildren()->count(), $copy->getDirectVisibleChildren()->count());
|
||||||
|
|
||||||
$this->get($copy->getUrl())->assertSee($book->description_html, false);
|
$this->get($copy->getUrl())->assertSee($book->description_html, false);
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ class BookTest extends TestCase
|
||||||
|
|
||||||
// Hide child content
|
// Hide child content
|
||||||
/** @var BookChild $page */
|
/** @var BookChild $page */
|
||||||
foreach ($book->getDirectChildren() as $child) {
|
foreach ($book->getDirectVisibleChildren() as $child) {
|
||||||
$this->permissions->setEntityPermissions($child, [], []);
|
$this->permissions->setEntityPermissions($child, [], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ class BookTest extends TestCase
|
||||||
/** @var Book $copy */
|
/** @var Book $copy */
|
||||||
$copy = Book::query()->where('name', '=', 'My copy book')->first();
|
$copy = Book::query()->where('name', '=', 'My copy book')->first();
|
||||||
|
|
||||||
$this->assertEquals(0, $copy->getDirectChildren()->count());
|
$this->assertEquals(0, $copy->getDirectVisibleChildren()->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_copy_does_not_copy_pages_or_chapters_if_user_cant_create()
|
public function test_copy_does_not_copy_pages_or_chapters_if_user_cant_create()
|
||||||
|
|
|
@ -303,7 +303,7 @@ class EntitySearchTest extends TestCase
|
||||||
public function test_sibling_search_for_pages_without_chapter()
|
public function test_sibling_search_for_pages_without_chapter()
|
||||||
{
|
{
|
||||||
$page = $this->entities->pageNotWithinChapter();
|
$page = $this->entities->pageNotWithinChapter();
|
||||||
$bookChildren = $page->book->getDirectChildren();
|
$bookChildren = $page->book->getDirectVisibleChildren();
|
||||||
$this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling');
|
$this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling');
|
||||||
|
|
||||||
$search = $this->actingAs($this->users->viewer())->get("/search/entity/siblings?entity_id={$page->id}&entity_type=page");
|
$search = $this->actingAs($this->users->viewer())->get("/search/entity/siblings?entity_id={$page->id}&entity_type=page");
|
||||||
|
@ -318,7 +318,7 @@ class EntitySearchTest extends TestCase
|
||||||
public function test_sibling_search_for_chapters()
|
public function test_sibling_search_for_chapters()
|
||||||
{
|
{
|
||||||
$chapter = $this->entities->chapter();
|
$chapter = $this->entities->chapter();
|
||||||
$bookChildren = $chapter->book->getDirectChildren();
|
$bookChildren = $chapter->book->getDirectVisibleChildren();
|
||||||
$this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling');
|
$this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling');
|
||||||
|
|
||||||
$search = $this->actingAs($this->users->viewer())->get("/search/entity/siblings?entity_id={$chapter->id}&entity_type=chapter");
|
$search = $this->actingAs($this->users->viewer())->get("/search/entity/siblings?entity_id={$chapter->id}&entity_type=chapter");
|
||||||
|
|
Loading…
Reference in a new issue