mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-03 08:13:14 +08:00
Entity Repo & Controller Refactor (#1690)
* Started mass-refactoring of the current entity repos * Rewrote book tree logic - Now does two simple queries instead of one really complex one. - Extracted logic into its own class. - Remove model-level akward union field listing. - Logic now more readable than being large separate query and compilation functions. * Extracted and split book sort logic * Finished up Book controller/repo organisation * Refactored bookshelves controllers and repo parts * Fixed issues found via phpunit * Refactored Chapter controller * Updated Chapter export controller * Started Page controller/repo refactor * Refactored another chunk of PageController * Completed initial pagecontroller refactor pass * Fixed tests and continued reduction of old repos * Removed old page remove and further reduced entity repo * Removed old entity repo, split out page controller * Ran phpcbf and split out some page content methods * Tidied up some EntityProvider elements * Fixed issued caused by viewservice change
This commit is contained in:
@ -1,37 +1,37 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Exceptions\FileUploadException;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Uploads\Attachment;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AttachmentController extends Controller
|
||||
{
|
||||
protected $attachmentService;
|
||||
protected $attachment;
|
||||
protected $entityRepo;
|
||||
protected $pageRepo;
|
||||
|
||||
/**
|
||||
* AttachmentController constructor.
|
||||
* @param \BookStack\Uploads\AttachmentService $attachmentService
|
||||
* @param Attachment $attachment
|
||||
* @param EntityRepo $entityRepo
|
||||
*/
|
||||
public function __construct(AttachmentService $attachmentService, Attachment $attachment, EntityRepo $entityRepo)
|
||||
public function __construct(AttachmentService $attachmentService, Attachment $attachment, PageRepo $pageRepo)
|
||||
{
|
||||
$this->attachmentService = $attachmentService;
|
||||
$this->attachment = $attachment;
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->pageRepo = $pageRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Endpoint at which attachments are uploaded to.
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
{
|
||||
@ -41,7 +41,7 @@ class AttachmentController extends Controller
|
||||
]);
|
||||
|
||||
$pageId = $request->get('uploaded_to');
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
|
||||
$this->checkPermission('attachment-create-all');
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
@ -59,10 +59,8 @@ class AttachmentController extends Controller
|
||||
|
||||
/**
|
||||
* Update an uploaded attachment.
|
||||
* @param Request $request
|
||||
* @param int $attachmentId
|
||||
* @return mixed
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function uploadUpdate(Request $request, $attachmentId)
|
||||
{
|
||||
@ -72,7 +70,7 @@ class AttachmentController extends Controller
|
||||
]);
|
||||
|
||||
$pageId = $request->get('uploaded_to');
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
@ -95,10 +93,8 @@ class AttachmentController extends Controller
|
||||
|
||||
/**
|
||||
* Update the details of an existing file.
|
||||
* @param Request $request
|
||||
* @param $attachmentId
|
||||
* @return Attachment|mixed
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function update(Request $request, $attachmentId)
|
||||
{
|
||||
@ -109,7 +105,7 @@ class AttachmentController extends Controller
|
||||
]);
|
||||
|
||||
$pageId = $request->get('uploaded_to');
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
@ -125,8 +121,8 @@ class AttachmentController extends Controller
|
||||
|
||||
/**
|
||||
* Attach a link to a page.
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function attachLink(Request $request)
|
||||
{
|
||||
@ -137,7 +133,7 @@ class AttachmentController extends Controller
|
||||
]);
|
||||
|
||||
$pageId = $request->get('uploaded_to');
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
|
||||
$this->checkPermission('attachment-create-all');
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
@ -151,30 +147,26 @@ class AttachmentController extends Controller
|
||||
|
||||
/**
|
||||
* Get the attachments for a specific page.
|
||||
* @param $pageId
|
||||
* @return mixed
|
||||
*/
|
||||
public function listForPage($pageId)
|
||||
public function listForPage(int $pageId)
|
||||
{
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-view', $page);
|
||||
return response()->json($page->attachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the attachment sorting.
|
||||
* @param Request $request
|
||||
* @param $pageId
|
||||
* @return mixed
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function sortForPage(Request $request, $pageId)
|
||||
public function sortForPage(Request $request, int $pageId)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'files' => 'required|array',
|
||||
'files.*.id' => 'required|integer',
|
||||
]);
|
||||
$page = $this->entityRepo->getById('page', $pageId);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
|
||||
$attachments = $request->get('files');
|
||||
@ -184,16 +176,15 @@ class AttachmentController extends Controller
|
||||
|
||||
/**
|
||||
* Get an attachment from storage.
|
||||
* @param $attachmentId
|
||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Symfony\Component\HttpFoundation\Response
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function get($attachmentId)
|
||||
public function get(int $attachmentId)
|
||||
{
|
||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||
$page = $this->entityRepo->getById('page', $attachment->uploaded_to);
|
||||
if ($page === null) {
|
||||
try {
|
||||
$page = $this->pageRepo->getById($attachment->uploaded_to);
|
||||
} catch (NotFoundException $exception) {
|
||||
throw new NotFoundException(trans('errors.attachment_not_found'));
|
||||
}
|
||||
|
||||
@ -211,9 +202,9 @@ class AttachmentController extends Controller
|
||||
* Delete a specific attachment in the system.
|
||||
* @param $attachmentId
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete($attachmentId)
|
||||
public function delete(int $attachmentId)
|
||||
{
|
||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||
$this->checkOwnablePermission('attachment-delete', $attachment);
|
||||
|
@ -65,14 +65,14 @@ class ConfirmEmailController extends Controller
|
||||
$userId = $this->emailConfirmationService->checkTokenAndGetUserId($token);
|
||||
} catch (Exception $exception) {
|
||||
if ($exception instanceof UserTokenNotFoundException) {
|
||||
$this->showErrorNotification( trans('errors.email_confirmation_invalid'));
|
||||
$this->showErrorNotification(trans('errors.email_confirmation_invalid'));
|
||||
return redirect('/register');
|
||||
}
|
||||
|
||||
if ($exception instanceof UserTokenExpiredException) {
|
||||
$user = $this->userRepo->getById($exception->userId);
|
||||
$this->emailConfirmationService->sendConfirmation($user);
|
||||
$this->showErrorNotification( trans('errors.email_confirmation_expired'));
|
||||
$this->showErrorNotification(trans('errors.email_confirmation_expired'));
|
||||
return redirect('/register/confirm');
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ class ConfirmEmailController extends Controller
|
||||
$user->save();
|
||||
|
||||
auth()->login($user);
|
||||
$this->showSuccessNotification( trans('auth.email_confirm_success'));
|
||||
$this->showSuccessNotification(trans('auth.email_confirm_success'));
|
||||
$this->emailConfirmationService->deleteByUser($user);
|
||||
|
||||
return redirect('/');
|
||||
@ -106,11 +106,11 @@ class ConfirmEmailController extends Controller
|
||||
try {
|
||||
$this->emailConfirmationService->sendConfirmation($user);
|
||||
} catch (Exception $e) {
|
||||
$this->showErrorNotification( trans('auth.email_confirm_send_error'));
|
||||
$this->showErrorNotification(trans('auth.email_confirm_send_error'));
|
||||
return redirect('/register/confirm');
|
||||
}
|
||||
|
||||
$this->showSuccessNotification( trans('auth.email_confirm_resent'));
|
||||
$this->showSuccessNotification(trans('auth.email_confirm_resent'));
|
||||
return redirect('/register/confirm');
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class ForgotPasswordController extends Controller
|
||||
|
||||
if ($response === Password::RESET_LINK_SENT) {
|
||||
$message = trans('auth.reset_password_sent_success', ['email' => $request->get('email')]);
|
||||
$this->showSuccessNotification( $message);
|
||||
$this->showSuccessNotification($message);
|
||||
return back()->with('status', trans($response));
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ class ResetPasswordController extends Controller
|
||||
protected function sendResetResponse(Request $request, $response)
|
||||
{
|
||||
$message = trans('auth.reset_password_success');
|
||||
$this->showSuccessNotification( $message);
|
||||
$this->showSuccessNotification($message);
|
||||
return redirect($this->redirectPath())
|
||||
->with('status', trans($response));
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class UserInviteController extends Controller
|
||||
$user->save();
|
||||
|
||||
auth()->login($user);
|
||||
$this->showSuccessNotification( trans('auth.user_invite_success', ['appName' => setting('app-name')]));
|
||||
$this->showSuccessNotification(trans('auth.user_invite_success', ['appName' => setting('app-name')]));
|
||||
$this->inviteService->deleteByUser($user);
|
||||
|
||||
return redirect('/');
|
||||
@ -96,7 +96,7 @@ class UserInviteController extends Controller
|
||||
}
|
||||
|
||||
if ($exception instanceof UserTokenExpiredException) {
|
||||
$this->showErrorNotification( trans('errors.invite_token_expired'));
|
||||
$this->showErrorNotification(trans('errors.invite_token_expired'));
|
||||
return redirect('/password/email');
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,14 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Auth\UserRepo;
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Managers\BookContents;
|
||||
use BookStack\Entities\Bookshelf;
|
||||
use BookStack\Entities\EntityContextManager;
|
||||
use BookStack\Entities\Managers\EntityContext;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Exceptions\NotifyException;
|
||||
use BookStack\Uploads\ImageRepo;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
use Throwable;
|
||||
use Views;
|
||||
|
||||
@ -24,33 +16,20 @@ class BookController extends Controller
|
||||
{
|
||||
|
||||
protected $bookRepo;
|
||||
protected $userRepo;
|
||||
protected $entityContextManager;
|
||||
protected $imageRepo;
|
||||
|
||||
/**
|
||||
* BookController constructor.
|
||||
* @param BookRepo $bookRepo
|
||||
* @param UserRepo $userRepo
|
||||
* @param EntityContextManager $entityContextManager
|
||||
* @param ImageRepo $imageRepo
|
||||
*/
|
||||
public function __construct(
|
||||
BookRepo $bookRepo,
|
||||
UserRepo $userRepo,
|
||||
EntityContextManager $entityContextManager,
|
||||
ImageRepo $imageRepo
|
||||
) {
|
||||
public function __construct(EntityContext $entityContextManager, BookRepo $bookRepo)
|
||||
{
|
||||
$this->bookRepo = $bookRepo;
|
||||
$this->userRepo = $userRepo;
|
||||
$this->entityContextManager = $entityContextManager;
|
||||
$this->imageRepo = $imageRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the book.
|
||||
* @return Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
@ -58,10 +37,10 @@ class BookController extends Controller
|
||||
$sort = setting()->getForCurrentUser('books_sort', 'name');
|
||||
$order = setting()->getForCurrentUser('books_sort_order', 'asc');
|
||||
|
||||
$books = $this->bookRepo->getAllPaginated('book', 18, $sort, $order);
|
||||
$recents = $this->isSignedIn() ? $this->bookRepo->getRecentlyViewed('book', 4, 0) : false;
|
||||
$popular = $this->bookRepo->getPopular('book', 4, 0);
|
||||
$new = $this->bookRepo->getRecentlyCreated('book', 4, 0);
|
||||
$books = $this->bookRepo->getAllPaginated(18, $sort, $order);
|
||||
$recents = $this->isSignedIn() ? $this->bookRepo->getRecentlyViewed(4) : false;
|
||||
$popular = $this->bookRepo->getPopular(4);
|
||||
$new = $this->bookRepo->getRecentlyCreated(4);
|
||||
|
||||
$this->entityContextManager->clearShelfContext();
|
||||
|
||||
@ -79,19 +58,17 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for creating a new book.
|
||||
* @param string $shelfSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function create(string $shelfSlug = null)
|
||||
{
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$bookshelf = null;
|
||||
if ($shelfSlug !== null) {
|
||||
$bookshelf = $this->bookRepo->getEntityBySlug('bookshelf', $shelfSlug);
|
||||
$bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail();
|
||||
$this->checkOwnablePermission('bookshelf-update', $bookshelf);
|
||||
}
|
||||
|
||||
$this->checkPermission('book-create-all');
|
||||
$this->setPageTitle(trans('entities.books_create'));
|
||||
return view('books.create', [
|
||||
'bookshelf' => $bookshelf
|
||||
@ -100,11 +77,6 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* Store a newly created book in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $shelfSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws ImageUploadException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@ -114,19 +86,17 @@ class BookController extends Controller
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'string|max:1000',
|
||||
'image' => $this->imageRepo->getImageValidationRules(),
|
||||
'image' => $this->getImageValidationRules(),
|
||||
]);
|
||||
|
||||
$bookshelf = null;
|
||||
if ($shelfSlug !== null) {
|
||||
/** @var Bookshelf $bookshelf */
|
||||
$bookshelf = $this->bookRepo->getEntityBySlug('bookshelf', $shelfSlug);
|
||||
$bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail();
|
||||
$this->checkOwnablePermission('bookshelf-update', $bookshelf);
|
||||
}
|
||||
|
||||
/** @var Book $book */
|
||||
$book = $this->bookRepo->createFromInput('book', $request->all());
|
||||
$this->bookUpdateActions($book, $request);
|
||||
$book = $this->bookRepo->create($request->all());
|
||||
$this->bookRepo->updateCoverImage($book, $request->file('image', null));
|
||||
Activity::add($book, 'book_create', $book->id);
|
||||
|
||||
if ($bookshelf) {
|
||||
@ -139,17 +109,11 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* Display the specified book.
|
||||
* @param Request $request
|
||||
* @param string $slug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function show(Request $request, string $slug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('book-view', $book);
|
||||
|
||||
$bookChildren = $this->bookRepo->getBookChildren($book);
|
||||
$bookChildren = (new BookContents($book))->getTree(true);
|
||||
|
||||
Views::add($book);
|
||||
if ($request->has('shelf')) {
|
||||
@ -167,9 +131,6 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified book.
|
||||
* @param string $slug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function edit(string $slug)
|
||||
{
|
||||
@ -181,11 +142,7 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* Update the specified book in storage.
|
||||
* @param Request $request
|
||||
* @param string $slug
|
||||
* @return Response
|
||||
* @throws ImageUploadException
|
||||
* @throws NotFoundException
|
||||
* @throws ValidationException
|
||||
* @throws Throwable
|
||||
*/
|
||||
@ -196,22 +153,20 @@ class BookController extends Controller
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'string|max:1000',
|
||||
'image' => $this->imageRepo->getImageValidationRules(),
|
||||
'image' => $this->getImageValidationRules(),
|
||||
]);
|
||||
|
||||
$book = $this->bookRepo->updateFromInput($book, $request->all());
|
||||
$this->bookUpdateActions($book, $request);
|
||||
$book = $this->bookRepo->update($book, $request->all());
|
||||
$resetCover = $request->has('image_reset');
|
||||
$this->bookRepo->updateCoverImage($book, $request->file('image', null), $resetCover);
|
||||
|
||||
Activity::add($book, 'book_update', $book->id);
|
||||
Activity::add($book, 'book_update', $book->id);
|
||||
|
||||
return redirect($book->getUrl());
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the page to confirm deletion
|
||||
* @param string $bookSlug
|
||||
* @return View
|
||||
* @throws NotFoundException
|
||||
* Shows the page to confirm deletion.
|
||||
*/
|
||||
public function showDelete(string $bookSlug)
|
||||
{
|
||||
@ -222,115 +177,7 @@ class BookController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the view which allows pages to be re-ordered and sorted.
|
||||
* @param string $bookSlug
|
||||
* @return View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function sort(string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
|
||||
$bookChildren = $this->bookRepo->getBookChildren($book, true);
|
||||
|
||||
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
|
||||
return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the sort box for a single book.
|
||||
* Used via AJAX when loading in extra books to a sort.
|
||||
* @param string $bookSlug
|
||||
* @return Factory|View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function sortItem(string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$bookChildren = $this->bookRepo->getBookChildren($book);
|
||||
return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an array of sort mapping to pages and chapters.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @return RedirectResponse|Redirector
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function saveSort(Request $request, string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
|
||||
// Return if no map sent
|
||||
if (!$request->filled('sort-tree')) {
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
// Sort pages and chapters
|
||||
$sortMap = collect(json_decode($request->get('sort-tree')));
|
||||
$bookIdsInvolved = collect([$book->id]);
|
||||
|
||||
// Load models into map
|
||||
$sortMap->each(function ($mapItem) use ($bookIdsInvolved) {
|
||||
$mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter');
|
||||
$mapItem->model = $this->bookRepo->getById($mapItem->type, $mapItem->id);
|
||||
// Store source and target books
|
||||
$bookIdsInvolved->push(intval($mapItem->model->book_id));
|
||||
$bookIdsInvolved->push(intval($mapItem->book));
|
||||
});
|
||||
|
||||
// Get the books involved in the sort
|
||||
$bookIdsInvolved = $bookIdsInvolved->unique()->toArray();
|
||||
$booksInvolved = $this->bookRepo->getManyById('book', $bookIdsInvolved, false, true);
|
||||
|
||||
// Throw permission error if invalid ids or inaccessible books given.
|
||||
if (count($bookIdsInvolved) !== count($booksInvolved)) {
|
||||
$this->showPermissionError();
|
||||
}
|
||||
|
||||
// Check permissions of involved books
|
||||
$booksInvolved->each(function (Book $book) {
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
});
|
||||
|
||||
// Perform the sort
|
||||
$sortMap->each(function ($mapItem) {
|
||||
$model = $mapItem->model;
|
||||
|
||||
$priorityChanged = intval($model->priority) !== intval($mapItem->sort);
|
||||
$bookChanged = intval($model->book_id) !== intval($mapItem->book);
|
||||
$chapterChanged = ($mapItem->type === 'page') && intval($model->chapter_id) !== $mapItem->parentChapter;
|
||||
|
||||
if ($bookChanged) {
|
||||
$this->bookRepo->changeBook($model, $mapItem->book);
|
||||
}
|
||||
if ($chapterChanged) {
|
||||
$model->chapter_id = intval($mapItem->parentChapter);
|
||||
$model->save();
|
||||
}
|
||||
if ($priorityChanged) {
|
||||
$model->priority = intval($mapItem->sort);
|
||||
$model->save();
|
||||
}
|
||||
});
|
||||
|
||||
// Rebuild permissions and add activity for involved books.
|
||||
$booksInvolved->each(function (Book $book) {
|
||||
$book->rebuildPermissions();
|
||||
Activity::add($book, 'book_sort', $book->id);
|
||||
});
|
||||
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified book from storage.
|
||||
* @param string $bookSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* Remove the specified book from the system.
|
||||
* @throws Throwable
|
||||
* @throws NotifyException
|
||||
*/
|
||||
@ -338,72 +185,40 @@ class BookController extends Controller
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-delete', $book);
|
||||
Activity::addMessage('book_delete', $book->name);
|
||||
|
||||
if ($book->cover) {
|
||||
$this->imageRepo->destroyImage($book->cover);
|
||||
}
|
||||
$this->bookRepo->destroyBook($book);
|
||||
Activity::addMessage('book_delete', $book->name);
|
||||
$this->bookRepo->destroy($book);
|
||||
|
||||
return redirect('/books');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Restrictions view.
|
||||
* @param string $bookSlug
|
||||
* @return Factory|View
|
||||
* @throws NotFoundException
|
||||
* Show the permissions view.
|
||||
*/
|
||||
public function showPermissions(string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||
$roles = $this->userRepo->getRestrictableRoles();
|
||||
|
||||
return view('books.permissions', [
|
||||
'book' => $book,
|
||||
'roles' => $roles
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restrictions for this book.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @return RedirectResponse|Redirector
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function permissions(Request $request, string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||
$this->bookRepo->updateEntityPermissionsFromRequest($request, $book);
|
||||
|
||||
$restricted = $request->get('restricted') === 'true';
|
||||
$permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null;
|
||||
$this->bookRepo->updatePermissions($book, $restricted, $permissions);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.books_permissions_updated'));
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Common actions to run on book update.
|
||||
* Handles updating the cover image.
|
||||
* @param Book $book
|
||||
* @param Request $request
|
||||
* @throws ImageUploadException
|
||||
*/
|
||||
protected function bookUpdateActions(Book $book, Request $request)
|
||||
{
|
||||
// Update the cover image if in request
|
||||
if ($request->has('image')) {
|
||||
$this->imageRepo->destroyImage($book->cover);
|
||||
$newImage = $request->file('image');
|
||||
$image = $this->imageRepo->saveNew($newImage, 'cover_book', $book->id, 512, 512, true);
|
||||
$book->image_id = $image->id;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
if ($request->has('image_reset')) {
|
||||
$this->imageRepo->destroyImage($book->cover);
|
||||
$book->image_id = 0;
|
||||
$book->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,25 +4,16 @@ namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\ExportService;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Throwable;
|
||||
|
||||
class BookExportController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var BookRepo
|
||||
*/
|
||||
protected $bookRepo;
|
||||
|
||||
/**
|
||||
* @var ExportService
|
||||
*/
|
||||
protected $bookRepo;
|
||||
protected $exportService;
|
||||
|
||||
/**
|
||||
* BookExportController constructor.
|
||||
* @param BookRepo $bookRepo
|
||||
* @param ExportService $exportService
|
||||
*/
|
||||
public function __construct(BookRepo $bookRepo, ExportService $exportService)
|
||||
{
|
||||
@ -33,9 +24,6 @@ class BookExportController extends Controller
|
||||
|
||||
/**
|
||||
* Export a book as a PDF file.
|
||||
* @param string $bookSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function pdf(string $bookSlug)
|
||||
@ -47,9 +35,6 @@ class BookExportController extends Controller
|
||||
|
||||
/**
|
||||
* Export a book as a contained HTML file.
|
||||
* @param string $bookSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function html(string $bookSlug)
|
||||
@ -61,9 +46,6 @@ class BookExportController extends Controller
|
||||
|
||||
/**
|
||||
* Export a book as a plain text file.
|
||||
* @param $bookSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function plainText(string $bookSlug)
|
||||
{
|
||||
|
82
app/Http/Controllers/BookSortController.php
Normal file
82
app/Http/Controllers/BookSortController.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Managers\BookContents;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Exceptions\SortOperationException;
|
||||
use BookStack\Facades\Activity;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BookSortController extends Controller
|
||||
{
|
||||
|
||||
protected $bookRepo;
|
||||
|
||||
/**
|
||||
* BookSortController constructor.
|
||||
* @param $bookRepo
|
||||
*/
|
||||
public function __construct(BookRepo $bookRepo)
|
||||
{
|
||||
$this->bookRepo = $bookRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the view which allows pages to be re-ordered and sorted.
|
||||
*/
|
||||
public function show(string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
|
||||
$bookChildren = (new BookContents($book))->getTree(false);
|
||||
|
||||
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
|
||||
return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the sort box for a single book.
|
||||
* Used via AJAX when loading in extra books to a sort.
|
||||
*/
|
||||
public function showItem(string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$bookChildren = (new BookContents($book))->getTree();
|
||||
return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a book using a given mapping array.
|
||||
*/
|
||||
public function update(Request $request, string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
|
||||
// Return if no map sent
|
||||
if (!$request->filled('sort-tree')) {
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
$sortMap = collect(json_decode($request->get('sort-tree')));
|
||||
$bookContents = new BookContents($book);
|
||||
$booksInvolved = collect();
|
||||
|
||||
try {
|
||||
$booksInvolved = $bookContents->sortUsingMap($sortMap);
|
||||
} catch (SortOperationException $exception) {
|
||||
$this->showPermissionError();
|
||||
}
|
||||
|
||||
// Rebuild permissions and add activity for involved books.
|
||||
$booksInvolved->each(function (Book $book) {
|
||||
Activity::add($book, 'book_sort', $book->id);
|
||||
});
|
||||
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
}
|
@ -1,34 +1,30 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Auth\UserRepo;
|
||||
use BookStack\Entities\Bookshelf;
|
||||
use BookStack\Entities\EntityContextManager;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Managers\EntityContext;
|
||||
use BookStack\Entities\Repos\BookshelfRepo;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Uploads\ImageRepo;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Views;
|
||||
|
||||
class BookshelfController extends Controller
|
||||
{
|
||||
|
||||
protected $entityRepo;
|
||||
protected $userRepo;
|
||||
protected $bookshelfRepo;
|
||||
protected $entityContextManager;
|
||||
protected $imageRepo;
|
||||
|
||||
/**
|
||||
* BookController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
* @param UserRepo $userRepo
|
||||
* @param EntityContextManager $entityContextManager
|
||||
* @param ImageRepo $imageRepo
|
||||
*/
|
||||
public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, EntityContextManager $entityContextManager, ImageRepo $imageRepo)
|
||||
public function __construct(BookshelfRepo $bookshelfRepo, EntityContext $entityContextManager, ImageRepo $imageRepo)
|
||||
{
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->userRepo = $userRepo;
|
||||
$this->bookshelfRepo = $bookshelfRepo;
|
||||
$this->entityContextManager = $entityContextManager;
|
||||
$this->imageRepo = $imageRepo;
|
||||
parent::__construct();
|
||||
@ -36,7 +32,6 @@ class BookshelfController extends Controller
|
||||
|
||||
/**
|
||||
* Display a listing of the book.
|
||||
* @return Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
@ -49,14 +44,10 @@ class BookshelfController extends Controller
|
||||
'updated_at' => trans('common.sort_updated_at'),
|
||||
];
|
||||
|
||||
$shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $sort, $order);
|
||||
foreach ($shelves as $shelf) {
|
||||
$shelf->books = $this->entityRepo->getBookshelfChildren($shelf);
|
||||
}
|
||||
|
||||
$recents = $this->isSignedIn() ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false;
|
||||
$popular = $this->entityRepo->getPopular('bookshelf', 4, 0);
|
||||
$new = $this->entityRepo->getRecentlyCreated('bookshelf', 4, 0);
|
||||
$shelves = $this->bookshelfRepo->getAllPaginated(18, $sort, $order);
|
||||
$recents = $this->isSignedIn() ? $this->bookshelfRepo->getRecentlyViewed(4) : false;
|
||||
$popular = $this->bookshelfRepo->getPopular(4);
|
||||
$new = $this->bookshelfRepo->getRecentlyCreated(4);
|
||||
|
||||
$this->entityContextManager->clearShelfContext();
|
||||
$this->setPageTitle(trans('entities.shelves'));
|
||||
@ -74,21 +65,19 @@ class BookshelfController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for creating a new bookshelf.
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->checkPermission('bookshelf-create-all');
|
||||
$books = $this->entityRepo->getAll('book', false, 'update');
|
||||
$books = Book::hasPermission('update')->get();
|
||||
$this->setPageTitle(trans('entities.shelves_create'));
|
||||
return view('shelves.create', ['books' => $books]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created bookshelf in storage.
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\ImageUploadException
|
||||
* @throws ValidationException
|
||||
* @throws ImageUploadException
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
@ -96,80 +85,63 @@ class BookshelfController extends Controller
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'string|max:1000',
|
||||
'image' => $this->imageRepo->getImageValidationRules(),
|
||||
'image' => $this->getImageValidationRules(),
|
||||
]);
|
||||
|
||||
$shelf = $this->entityRepo->createFromInput('bookshelf', $request->all());
|
||||
$this->shelfUpdateActions($shelf, $request);
|
||||
$bookIds = explode(',', $request->get('books', ''));
|
||||
$shelf = $this->bookshelfRepo->create($request->all(), $bookIds);
|
||||
$this->bookshelfRepo->updateCoverImage($shelf);
|
||||
|
||||
Activity::add($shelf, 'bookshelf_create');
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the specified bookshelf.
|
||||
* @param String $slug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* Display the bookshelf of the given slug.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function show(string $slug)
|
||||
{
|
||||
/** @var Bookshelf $shelf */
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug);
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('book-view', $shelf);
|
||||
|
||||
$books = $this->entityRepo->getBookshelfChildren($shelf);
|
||||
Views::add($shelf);
|
||||
$this->entityContextManager->setShelfContext($shelf->id);
|
||||
|
||||
$this->setPageTitle($shelf->getShortName());
|
||||
|
||||
return view('shelves.show', [
|
||||
'shelf' => $shelf,
|
||||
'books' => $books,
|
||||
'activity' => Activity::entityActivity($shelf, 20, 1)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified bookshelf.
|
||||
* @param $slug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
*/
|
||||
public function edit(string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('bookshelf-update', $shelf);
|
||||
|
||||
$shelfBooks = $this->entityRepo->getBookshelfChildren($shelf);
|
||||
$shelfBookIds = $shelfBooks->pluck('id');
|
||||
$books = $this->entityRepo->getAll('book', false, 'update');
|
||||
$books = $books->filter(function ($book) use ($shelfBookIds) {
|
||||
return !$shelfBookIds->contains($book->id);
|
||||
});
|
||||
$shelfBookIds = $shelf->books()->get(['id'])->pluck('id');
|
||||
$books = Book::hasPermission('update')->whereNotIn('id', $shelfBookIds)->get();
|
||||
|
||||
$this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()]));
|
||||
return view('shelves.edit', [
|
||||
'shelf' => $shelf,
|
||||
'books' => $books,
|
||||
'shelfBooks' => $shelfBooks,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the specified bookshelf in storage.
|
||||
* @param Request $request
|
||||
* @param string $slug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws \BookStack\Exceptions\ImageUploadException
|
||||
* @throws ValidationException
|
||||
* @throws ImageUploadException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function update(Request $request, string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('bookshelf-update', $shelf);
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255',
|
||||
@ -177,24 +149,22 @@ class BookshelfController extends Controller
|
||||
'image' => $this->imageRepo->getImageValidationRules(),
|
||||
]);
|
||||
|
||||
$shelf = $this->entityRepo->updateFromInput($shelf, $request->all());
|
||||
$this->shelfUpdateActions($shelf, $request);
|
||||
|
||||
Activity::add($shelf, 'bookshelf_update');
|
||||
$bookIds = explode(',', $request->get('books', ''));
|
||||
$shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds);
|
||||
$resetCover = $request->has('image_reset');
|
||||
$this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover);
|
||||
Activity::add($shelf, 'bookshelf_update');
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the page to confirm deletion
|
||||
* @param $slug
|
||||
* @return \Illuminate\View\View
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
*/
|
||||
public function showDelete(string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('bookshelf-delete', $shelf);
|
||||
|
||||
$this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $shelf->getShortName()]));
|
||||
@ -203,101 +173,58 @@ class BookshelfController extends Controller
|
||||
|
||||
/**
|
||||
* Remove the specified bookshelf from storage.
|
||||
* @param string $slug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws \Throwable
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroy(string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('bookshelf-delete', $shelf);
|
||||
Activity::addMessage('bookshelf_delete', $shelf->name);
|
||||
|
||||
if ($shelf->cover) {
|
||||
$this->imageRepo->destroyImage($shelf->cover);
|
||||
}
|
||||
$this->entityRepo->destroyBookshelf($shelf);
|
||||
Activity::addMessage('bookshelf_delete', $shelf->name);
|
||||
$this->bookshelfRepo->destroy($shelf);
|
||||
|
||||
return redirect('/shelves');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the permissions view.
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
*/
|
||||
public function showPermissions(string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug);
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$roles = $this->userRepo->getRestrictableRoles();
|
||||
return view('shelves.permissions', [
|
||||
'shelf' => $shelf,
|
||||
'roles' => $roles
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permissions for this bookshelf.
|
||||
* @param Request $request
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function permissions(Request $request, string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug);
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$this->entityRepo->updateEntityPermissionsFromRequest($request, $shelf);
|
||||
$this->showSuccessNotification( trans('entities.shelves_permissions_updated'));
|
||||
$restricted = $request->get('restricted') === 'true';
|
||||
$permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null;
|
||||
$this->bookshelfRepo->updatePermissions($shelf, $restricted, $permissions);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.shelves_permissions_updated'));
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the permissions of a bookshelf to the child books.
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
*/
|
||||
public function copyPermissions(string $slug)
|
||||
{
|
||||
$shelf = $this->entityRepo->getEntityBySlug('bookshelf', $slug);
|
||||
$shelf = $this->bookshelfRepo->getBySlug($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$updateCount = $this->entityRepo->copyBookshelfPermissions($shelf);
|
||||
$this->showSuccessNotification( trans('entities.shelves_copy_permission_success', ['count' => $updateCount]));
|
||||
$updateCount = $this->bookshelfRepo->copyDownPermissions($shelf);
|
||||
$this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount]));
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Common actions to run on bookshelf update.
|
||||
* @param Bookshelf $shelf
|
||||
* @param Request $request
|
||||
* @throws \BookStack\Exceptions\ImageUploadException
|
||||
*/
|
||||
protected function shelfUpdateActions(Bookshelf $shelf, Request $request)
|
||||
{
|
||||
// Update the books that the shelf references
|
||||
$this->entityRepo->updateShelfBooks($shelf, $request->get('books', ''));
|
||||
|
||||
// Update the cover image if in request
|
||||
if ($request->has('image')) {
|
||||
$newImage = $request->file('image');
|
||||
$this->imageRepo->destroyImage($shelf->cover);
|
||||
$image = $this->imageRepo->saveNew($newImage, 'cover_shelf', $shelf->id, 512, 512, true);
|
||||
$shelf->image_id = $image->id;
|
||||
$shelf->save();
|
||||
}
|
||||
|
||||
if ($request->has('image_reset')) {
|
||||
$this->imageRepo->destroyImage($shelf->cover);
|
||||
$shelf->image_id = 0;
|
||||
$shelf->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,45 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Auth\UserRepo;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Managers\BookContents;
|
||||
use BookStack\Entities\Repos\ChapterRepo;
|
||||
use BookStack\Exceptions\MoveOperationException;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Throwable;
|
||||
use Views;
|
||||
|
||||
class ChapterController extends Controller
|
||||
{
|
||||
|
||||
protected $userRepo;
|
||||
protected $entityRepo;
|
||||
protected $chapterRepo;
|
||||
|
||||
/**
|
||||
* ChapterController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
* @param UserRepo $userRepo
|
||||
*/
|
||||
public function __construct(EntityRepo $entityRepo, UserRepo $userRepo)
|
||||
public function __construct(ChapterRepo $chapterRepo)
|
||||
{
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->userRepo = $userRepo;
|
||||
$this->chapterRepo = $chapterRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new chapter.
|
||||
* @param $bookSlug
|
||||
* @return Response
|
||||
*/
|
||||
public function create($bookSlug)
|
||||
public function create(string $bookSlug)
|
||||
{
|
||||
$book = $this->entityRepo->getEntityBySlug('book', $bookSlug);
|
||||
$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
|
||||
$this->checkOwnablePermission('chapter-create', $book);
|
||||
|
||||
$this->setPageTitle(trans('entities.chapters_create'));
|
||||
return view('chapters.create', ['book' => $book, 'current' => $book]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created chapter in storage.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request, string $bookSlug)
|
||||
{
|
||||
@ -52,30 +47,28 @@ class ChapterController extends Controller
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
|
||||
$book = $this->entityRepo->getEntityBySlug('book', $bookSlug);
|
||||
$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
|
||||
$this->checkOwnablePermission('chapter-create', $book);
|
||||
|
||||
$input = $request->all();
|
||||
$input['priority'] = $this->entityRepo->getNewBookPriority($book);
|
||||
$chapter = $this->entityRepo->createFromInput('chapter', $input, $book);
|
||||
$chapter = $this->chapterRepo->create($request->all(), $book);
|
||||
Activity::add($chapter, 'chapter_create', $book->id);
|
||||
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified chapter.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
*/
|
||||
public function show($bookSlug, $chapterSlug)
|
||||
public function show(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-view', $chapter);
|
||||
$sidebarTree = $this->entityRepo->getBookChildren($chapter->book);
|
||||
|
||||
$sidebarTree = (new BookContents($chapter->book))->getTree();
|
||||
$pages = $chapter->getVisiblePages();
|
||||
Views::add($chapter);
|
||||
|
||||
$this->setPageTitle($chapter->getShortName());
|
||||
$pages = $this->entityRepo->getChapterChildren($chapter);
|
||||
return view('chapters.show', [
|
||||
'book' => $chapter->book,
|
||||
'chapter' => $chapter,
|
||||
@ -87,79 +80,71 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified chapter.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
*/
|
||||
public function edit($bookSlug, $chapterSlug)
|
||||
public function edit(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||
|
||||
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
|
||||
return view('chapters.edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified chapter in storage.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function update(Request $request, string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||
|
||||
$this->entityRepo->updateFromInput($chapter, $request->all());
|
||||
$this->chapterRepo->update($chapter, $request->all());
|
||||
Activity::add($chapter, 'chapter_update', $chapter->book->id);
|
||||
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the page to confirm deletion of this chapter.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return \Illuminate\View\View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showDelete($bookSlug, $chapterSlug)
|
||||
public function showDelete(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
|
||||
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
|
||||
return view('chapters.delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified chapter from storage.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function destroy($bookSlug, $chapterSlug)
|
||||
public function destroy(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$book = $chapter->book;
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
Activity::addMessage('chapter_delete', $chapter->name, $book->id);
|
||||
$this->entityRepo->destroyChapter($chapter);
|
||||
return redirect($book->getUrl());
|
||||
|
||||
Activity::addMessage('chapter_delete', $chapter->name, $chapter->book->id);
|
||||
$this->chapterRepo->destroy($chapter);
|
||||
|
||||
return redirect($chapter->book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the page for moving a chapter.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return mixed
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showMove($bookSlug, $chapterSlug)
|
||||
public function showMove(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
|
||||
return view('chapters.move', [
|
||||
'chapter' => $chapter,
|
||||
'book' => $chapter->book
|
||||
@ -168,15 +153,11 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Perform the move action for a chapter.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return mixed
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function move(Request $request, string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
|
||||
@ -185,63 +166,47 @@ class ChapterController extends Controller
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
|
||||
$stringExploded = explode(':', $entitySelection);
|
||||
$entityType = $stringExploded[0];
|
||||
$entityId = intval($stringExploded[1]);
|
||||
|
||||
$parent = false;
|
||||
|
||||
if ($entityType == 'book') {
|
||||
$parent = $this->entityRepo->getById('book', $entityId);
|
||||
}
|
||||
|
||||
if ($parent === false || $parent === null) {
|
||||
$this->showErrorNotification( trans('errors.selected_book_not_found'));
|
||||
try {
|
||||
$newBook = $this->chapterRepo->move($chapter, $entitySelection);
|
||||
} catch (MoveOperationException $exception) {
|
||||
$this->showErrorNotification(trans('errors.selected_book_not_found'));
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
$this->entityRepo->changeBook($chapter, $parent->id);
|
||||
$chapter->rebuildPermissions();
|
||||
|
||||
Activity::add($chapter, 'chapter_move', $chapter->book->id);
|
||||
$this->showSuccessNotification( trans('entities.chapter_move_success', ['bookName' => $parent->name]));
|
||||
Activity::add($chapter, 'chapter_move', $newBook->id);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.chapter_move_success', ['bookName' => $newBook->name]));
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Restrictions view.
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showPermissions($bookSlug, $chapterSlug)
|
||||
public function showPermissions(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||
$roles = $this->userRepo->getRestrictableRoles();
|
||||
|
||||
return view('chapters.permissions', [
|
||||
'chapter' => $chapter,
|
||||
'roles' => $roles
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restrictions for this chapter.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws \Throwable
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function permissions(Request $request, string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||
$this->entityRepo->updateEntityPermissionsFromRequest($request, $chapter);
|
||||
$this->showSuccessNotification( trans('entities.chapters_permissions_success'));
|
||||
|
||||
$restricted = $request->get('restricted') === 'true';
|
||||
$permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null;
|
||||
$this->chapterRepo->updatePermissions($chapter, $restricted, $permissions);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.chapters_permissions_success'));
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
}
|
||||
|
@ -1,77 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Http\Controllers;
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\ExportService;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Repos\ChapterRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Illuminate\Http\Response;
|
||||
use Throwable;
|
||||
|
||||
class ChapterExportController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var EntityRepo
|
||||
*/
|
||||
protected $entityRepo;
|
||||
|
||||
/**
|
||||
* @var ExportService
|
||||
*/
|
||||
protected $chapterRepo;
|
||||
protected $exportService;
|
||||
|
||||
/**
|
||||
* ChapterExportController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
* @param ExportService $exportService
|
||||
*/
|
||||
public function __construct(EntityRepo $entityRepo, ExportService $exportService)
|
||||
public function __construct(ChapterRepo $chapterRepo, ExportService $exportService)
|
||||
{
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->chapterRepo = $chapterRepo;
|
||||
$this->exportService = $exportService;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a chapter to pdf .
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* Exports a chapter to pdf.
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function pdf(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$pdfContent = $this->exportService->chapterToPdf($chapter);
|
||||
return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a chapter to a self-contained HTML file.
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function html(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$containedHtml = $this->exportService->chapterToContainedHtml($chapter);
|
||||
return $this->downloadResponse($containedHtml, $chapterSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a chapter to a simple plaintext .txt file.
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function plainText(string $bookSlug, string $chapterSlug)
|
||||
{
|
||||
$chapter = $this->entityRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
|
||||
$chapterText = $this->exportService->chapterToPlainText($chapter);
|
||||
return $this->downloadResponse($chapterText, $chapterSlug . '.txt');
|
||||
}
|
||||
|
@ -2,44 +2,36 @@
|
||||
|
||||
use Activity;
|
||||
use BookStack\Actions\CommentRepo;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use BookStack\Entities\Page;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
protected $entityRepo;
|
||||
protected $commentRepo;
|
||||
|
||||
/**
|
||||
* CommentController constructor.
|
||||
* @param \BookStack\Entities\Repos\EntityRepo $entityRepo
|
||||
* @param \BookStack\Actions\CommentRepo $commentRepo
|
||||
*/
|
||||
public function __construct(EntityRepo $entityRepo, CommentRepo $commentRepo)
|
||||
public function __construct(CommentRepo $commentRepo)
|
||||
{
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->commentRepo = $commentRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a new comment for a Page
|
||||
* @param Request $request
|
||||
* @param integer $pageId
|
||||
* @param null|integer $commentId
|
||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function savePageComment(Request $request, $pageId, $commentId = null)
|
||||
public function savePageComment(Request $request, int $pageId, int $commentId = null)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'text' => 'required|string',
|
||||
'html' => 'required|string',
|
||||
]);
|
||||
|
||||
try {
|
||||
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
$page = Page::visible()->find($pageId);
|
||||
if ($page === null) {
|
||||
return response('Not found', 404);
|
||||
}
|
||||
|
||||
@ -59,11 +51,9 @@ class CommentController extends Controller
|
||||
|
||||
/**
|
||||
* Update an existing comment.
|
||||
* @param Request $request
|
||||
* @param integer $commentId
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function update(Request $request, $commentId)
|
||||
public function update(Request $request, int $commentId)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'text' => 'required|string',
|
||||
@ -80,13 +70,12 @@ class CommentController extends Controller
|
||||
|
||||
/**
|
||||
* Delete a comment from the system.
|
||||
* @param integer $id
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy($id)
|
||||
public function destroy(int $id)
|
||||
{
|
||||
$comment = $this->commentRepo->getById($id);
|
||||
$this->checkOwnablePermission('comment-delete', $comment);
|
||||
|
||||
$this->commentRepo->delete($comment);
|
||||
return response()->json(['message' => trans('entities.comment_deleted')]);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ abstract class Controller extends BaseController
|
||||
$response = response()->json(['error' => trans('errors.permissionJson')], 403);
|
||||
} else {
|
||||
$response = redirect('/');
|
||||
$this->showErrorNotification( trans('errors.permission'));
|
||||
$this->showErrorNotification(trans('errors.permission'));
|
||||
}
|
||||
|
||||
throw new HttpResponseException($response);
|
||||
@ -129,7 +129,7 @@ abstract class Controller extends BaseController
|
||||
*/
|
||||
protected function jsonError($messageText = "", $statusCode = 500)
|
||||
{
|
||||
return response()->json(['message' => $messageText], $statusCode);
|
||||
return response()->json(['message' => $messageText, 'status' => 'error'], $statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,4 +189,12 @@ abstract class Controller extends BaseController
|
||||
{
|
||||
session()->flash('error', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for image files.
|
||||
*/
|
||||
protected function getImageValidationRules(): string
|
||||
{
|
||||
return 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff';
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,16 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Managers\PageContent;
|
||||
use BookStack\Entities\Page;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Entities\Repos\BookshelfRepo;
|
||||
use Illuminate\Http\Response;
|
||||
use Views;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
protected $entityRepo;
|
||||
|
||||
/**
|
||||
* HomeController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
*/
|
||||
public function __construct(EntityRepo $entityRepo)
|
||||
{
|
||||
$this->entityRepo = $entityRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the homepage.
|
||||
@ -26,10 +19,20 @@ class HomeController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$activity = Activity::latest(10);
|
||||
$draftPages = $this->isSignedIn() ? $this->entityRepo->getUserDraftPages(6) : [];
|
||||
$draftPages = [];
|
||||
|
||||
if ($this->isSignedIn()) {
|
||||
$draftPages = Page::visible()->where('draft', '=', true)
|
||||
->where('created_by', '=', user()->id)
|
||||
->orderBy('updated_at', 'desc')->take(6)->get();
|
||||
}
|
||||
|
||||
$recentFactor = count($draftPages) > 0 ? 0.5 : 1;
|
||||
$recents = $this->isSignedIn() ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 12*$recentFactor);
|
||||
$recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 12);
|
||||
$recents = $this->isSignedIn() ?
|
||||
Views::getUserRecentlyViewed(12*$recentFactor, 0)
|
||||
: Book::visible()->orderBy('created_at', 'desc')->take(12 * $recentFactor)->get();
|
||||
$recentlyUpdatedPages = Page::visible()->where('draft', false)
|
||||
->orderBy('updated_at', 'desc')->take(12)->get();
|
||||
|
||||
$homepageOptions = ['default', 'books', 'bookshelves', 'page'];
|
||||
$homepageOption = setting('app-homepage-type', 'default');
|
||||
@ -66,16 +69,18 @@ class HomeController extends Controller
|
||||
}
|
||||
|
||||
if ($homepageOption === 'bookshelves') {
|
||||
$shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $commonData['sort'], $commonData['order']);
|
||||
$shelfRepo = app(BookshelfRepo::class);
|
||||
$shelves = app(BookshelfRepo::class)->getAllPaginated(18, $commonData['sort'], $commonData['order']);
|
||||
foreach ($shelves as $shelf) {
|
||||
$shelf->books = $this->entityRepo->getBookshelfChildren($shelf);
|
||||
$shelf->books = $shelf->visibleBooks;
|
||||
}
|
||||
$data = array_merge($commonData, ['shelves' => $shelves]);
|
||||
return view('common.home-shelves', $data);
|
||||
}
|
||||
|
||||
if ($homepageOption === 'books') {
|
||||
$books = $this->entityRepo->getAllPaginated('book', 18, $commonData['sort'], $commonData['order']);
|
||||
$bookRepo = app(BookRepo::class);
|
||||
$books = $bookRepo->getAllPaginated(18, $commonData['sort'], $commonData['order']);
|
||||
$data = array_merge($commonData, ['books' => $books]);
|
||||
return view('common.home-book', $data);
|
||||
}
|
||||
@ -83,8 +88,9 @@ class HomeController extends Controller
|
||||
if ($homepageOption === 'page') {
|
||||
$homepageSetting = setting('app-homepage', '0:');
|
||||
$id = intval(explode(':', $homepageSetting)[0]);
|
||||
$customHomepage = $this->entityRepo->getById('page', $id, false, true);
|
||||
$this->entityRepo->renderPage($customHomepage, true);
|
||||
$customHomepage = Page::query()->where('draft', '=', false)->findOrFail($id);
|
||||
$pageContent = new PageContent($customHomepage);
|
||||
$customHomepage->html = $pageContent->render(true);
|
||||
return view('common.home-custom', array_merge($commonData, ['customHomepage' => $customHomepage]));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php namespace BookStack\Http\Controllers\Images;
|
||||
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Page;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Http\Controllers\Controller;
|
||||
use BookStack\Repos\PageRepo;
|
||||
@ -69,16 +69,21 @@ class ImageController extends Controller
|
||||
|
||||
/**
|
||||
* Show the usage of an image on pages.
|
||||
* @param \BookStack\Entities\Repos\EntityRepo $entityRepo
|
||||
* @param $id
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function usage(EntityRepo $entityRepo, $id)
|
||||
public function usage(int $id)
|
||||
{
|
||||
$image = $this->imageRepo->getById($id);
|
||||
$this->checkImagePermission($image);
|
||||
$pageSearch = $entityRepo->searchForImage($image->url);
|
||||
return response()->json($pageSearch);
|
||||
|
||||
$pages = Page::visible()->where('html', 'like', '%' . $image->url . '%')->get(['id', 'name', 'slug', 'book_id']);
|
||||
foreach ($pages as $page) {
|
||||
$page->url = $page->getUrl();
|
||||
$page->html = '';
|
||||
$page->text = '';
|
||||
}
|
||||
$result = count($pages) > 0 ? $pages : false;
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,18 +1,17 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use Activity;
|
||||
use BookStack\Auth\UserRepo;
|
||||
use BookStack\Entities\Managers\BookContents;
|
||||
use BookStack\Entities\Managers\PageContent;
|
||||
use BookStack\Entities\Managers\PageEditActivity;
|
||||
use BookStack\Entities\Page;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Exceptions\NotifyException;
|
||||
use BookStack\Exceptions\PermissionsException;
|
||||
use Exception;
|
||||
use GatherContent\Htmldiff\Htmldiff;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Throwable;
|
||||
use Views;
|
||||
|
||||
@ -20,44 +19,28 @@ class PageController extends Controller
|
||||
{
|
||||
|
||||
protected $pageRepo;
|
||||
protected $userRepo;
|
||||
|
||||
/**
|
||||
* PageController constructor.
|
||||
* @param PageRepo $pageRepo
|
||||
* @param UserRepo $userRepo
|
||||
*/
|
||||
public function __construct(PageRepo $pageRepo, UserRepo $userRepo)
|
||||
public function __construct(PageRepo $pageRepo)
|
||||
{
|
||||
$this->pageRepo = $pageRepo;
|
||||
$this->userRepo = $userRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new page.
|
||||
* @param string $bookSlug
|
||||
* @param string $chapterSlug
|
||||
* @return Response
|
||||
* @internal param bool $pageSlug
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function create($bookSlug, $chapterSlug = null)
|
||||
public function create(string $bookSlug, string $chapterSlug = null)
|
||||
{
|
||||
if ($chapterSlug !== null) {
|
||||
$chapter = $this->pageRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$book = $chapter->book;
|
||||
} else {
|
||||
$chapter = null;
|
||||
$book = $this->pageRepo->getEntityBySlug('book', $bookSlug);
|
||||
}
|
||||
|
||||
$parent = $chapter ? $chapter : $book;
|
||||
$parent = $this->pageRepo->getParentFromSlugs($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
// Redirect to draft edit screen if signed in
|
||||
if ($this->isSignedIn()) {
|
||||
$draft = $this->pageRepo->getDraftPage($book, $chapter);
|
||||
$draft = $this->pageRepo->getNewDraftPage($parent);
|
||||
return redirect($draft->getUrl());
|
||||
}
|
||||
|
||||
@ -68,51 +51,38 @@ class PageController extends Controller
|
||||
|
||||
/**
|
||||
* Create a new page as a guest user.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string|null $chapterSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function createAsGuest(Request $request, $bookSlug, $chapterSlug = null)
|
||||
public function createAsGuest(Request $request, string $bookSlug, string $chapterSlug = null)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
|
||||
if ($chapterSlug !== null) {
|
||||
$chapter = $this->pageRepo->getEntityBySlug('chapter', $chapterSlug, $bookSlug);
|
||||
$book = $chapter->book;
|
||||
} else {
|
||||
$chapter = null;
|
||||
$book = $this->pageRepo->getEntityBySlug('book', $bookSlug);
|
||||
}
|
||||
|
||||
$parent = $chapter ? $chapter : $book;
|
||||
$parent = $this->pageRepo->getParentFromSlugs($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
$page = $this->pageRepo->getDraftPage($book, $chapter);
|
||||
$this->pageRepo->publishPageDraft($page, [
|
||||
$page = $this->pageRepo->getNewDraftPage($parent);
|
||||
$this->pageRepo->publishDraft($page, [
|
||||
'name' => $request->get('name'),
|
||||
'html' => ''
|
||||
]);
|
||||
|
||||
return redirect($page->getUrl('/edit'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show form to continue editing a draft page.
|
||||
* @param string $bookSlug
|
||||
* @param int $pageId
|
||||
* @return Factory|View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function editDraft($bookSlug, $pageId)
|
||||
public function editDraft(string $bookSlug, int $pageId)
|
||||
{
|
||||
$draft = $this->pageRepo->getById('page', $pageId, true);
|
||||
$this->checkOwnablePermission('page-create', $draft->parent);
|
||||
$draft = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-create', $draft->parent());
|
||||
$this->setPageTitle(trans('entities.pages_edit_draft'));
|
||||
|
||||
$draftsEnabled = $this->isSignedIn();
|
||||
$templates = $this->pageRepo->getPageTemplates(10);
|
||||
$templates = $this->pageRepo->getTemplates(10);
|
||||
|
||||
return view('pages.edit', [
|
||||
'page' => $draft,
|
||||
@ -125,63 +95,50 @@ class PageController extends Controller
|
||||
|
||||
/**
|
||||
* Store a new page by changing a draft into a page.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param int $pageId
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request, $bookSlug, $pageId)
|
||||
public function store(Request $request, string $bookSlug, int $pageId)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
$draftPage = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-create', $draftPage->parent());
|
||||
|
||||
$input = $request->all();
|
||||
$draftPage = $this->pageRepo->getById('page', $pageId, true);
|
||||
$book = $draftPage->book;
|
||||
$page = $this->pageRepo->publishDraft($draftPage, $request->all());
|
||||
Activity::add($page, 'page_create', $draftPage->book->id);
|
||||
|
||||
$parent = $draftPage->parent;
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
if ($parent->isA('chapter')) {
|
||||
$input['priority'] = $this->pageRepo->getNewChapterPriority($parent);
|
||||
} else {
|
||||
$input['priority'] = $this->pageRepo->getNewBookPriority($parent);
|
||||
}
|
||||
|
||||
$page = $this->pageRepo->publishPageDraft($draftPage, $input);
|
||||
|
||||
Activity::add($page, 'page_create', $book->id);
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified page.
|
||||
* If the page is not found via the slug the revisions are searched for a match.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function show($bookSlug, $pageSlug)
|
||||
public function show(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
try {
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
} catch (NotFoundException $e) {
|
||||
$page = $this->pageRepo->getPageByOldSlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getByOldSlug($bookSlug, $pageSlug);
|
||||
|
||||
if ($page === null) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
$this->checkOwnablePermission('page-view', $page);
|
||||
|
||||
$page->html = $this->pageRepo->renderPage($page);
|
||||
$sidebarTree = $this->pageRepo->getBookChildren($page->book);
|
||||
$pageNav = $this->pageRepo->getPageNav($page->html);
|
||||
$pageContent = (new PageContent($page));
|
||||
$page->html = $pageContent->render();
|
||||
$sidebarTree = (new BookContents($page->book))->getTree();
|
||||
$pageNav = $pageContent->getNavigation($page->html);
|
||||
|
||||
// check if the comment's are enabled
|
||||
// Check if page comments are enabled
|
||||
$commentsEnabled = !setting('app-disable-comments');
|
||||
if ($commentsEnabled) {
|
||||
$page->load(['comments.createdBy']);
|
||||
@ -190,7 +147,8 @@ class PageController extends Controller
|
||||
Views::add($page);
|
||||
$this->setPageTitle($page->getShortName());
|
||||
return view('pages.show', [
|
||||
'page' => $page,'book' => $page->book,
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
'current' => $page,
|
||||
'sidebarTree' => $sidebarTree,
|
||||
'commentsEnabled' => $commentsEnabled,
|
||||
@ -200,52 +158,47 @@ class PageController extends Controller
|
||||
|
||||
/**
|
||||
* Get page from an ajax request.
|
||||
* @param int $pageId
|
||||
* @return JsonResponse
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function getPageAjax($pageId)
|
||||
public function getPageAjax(int $pageId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $pageId);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
return response()->json($page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified page.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function edit($bookSlug, $pageSlug)
|
||||
public function edit(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()]));
|
||||
|
||||
$page->isDraft = false;
|
||||
$editActivity = new PageEditActivity($page);
|
||||
|
||||
// Check for active editing
|
||||
$warnings = [];
|
||||
if ($this->pageRepo->isPageEditingActive($page, 60)) {
|
||||
$warnings[] = $this->pageRepo->getPageEditingActiveMessage($page, 60);
|
||||
if ($editActivity->hasActiveEditing()) {
|
||||
$warnings[] = $editActivity->activeEditingMessage();
|
||||
}
|
||||
|
||||
// Check for a current draft version for this user
|
||||
$userPageDraft = $this->pageRepo->getUserPageDraft($page, user()->id);
|
||||
if ($userPageDraft !== null) {
|
||||
$page->name = $userPageDraft->name;
|
||||
$page->html = $userPageDraft->html;
|
||||
$page->markdown = $userPageDraft->markdown;
|
||||
$userDraft = $this->pageRepo->getUserDraft($page);
|
||||
if ($userDraft !== null) {
|
||||
$page->forceFill($userDraft->only(['name', 'html', 'markdown']));
|
||||
$page->isDraft = true;
|
||||
$warnings [] = $this->pageRepo->getUserPageDraftMessage($userPageDraft);
|
||||
$warnings[] = $editActivity->getEditingActiveDraftMessage($userDraft);
|
||||
}
|
||||
|
||||
if (count($warnings) > 0) {
|
||||
$this->showWarningNotification( implode("\n", $warnings));
|
||||
$this->showWarningNotification(implode("\n", $warnings));
|
||||
}
|
||||
|
||||
$templates = $this->pageRepo->getTemplates(10);
|
||||
$draftsEnabled = $this->isSignedIn();
|
||||
$templates = $this->pageRepo->getPageTemplates(10);
|
||||
|
||||
$this->setPageTitle(trans('entities.pages_editing_named', ['pageName' => $page->getShortName()]));
|
||||
return view('pages.edit', [
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
@ -257,39 +210,34 @@ class PageController extends Controller
|
||||
|
||||
/**
|
||||
* Update the specified page in storage.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws ValidationException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function update(Request $request, $bookSlug, $pageSlug)
|
||||
public function update(Request $request, string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->pageRepo->updatePage($page, $page->book->id, $request->all());
|
||||
|
||||
$this->pageRepo->update($page, $request->all());
|
||||
Activity::add($page, 'page_update', $page->book->id);
|
||||
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a draft update as a revision.
|
||||
* @param Request $request
|
||||
* @param int $pageId
|
||||
* @return JsonResponse
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function saveDraft(Request $request, $pageId)
|
||||
public function saveDraft(Request $request, int $pageId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
|
||||
if (!$this->isSignedIn()) {
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => trans('errors.guests_cannot_save_drafts'),
|
||||
], 500);
|
||||
return $this->jsonError(trans('errors.guests_cannot_save_drafts'), 500);
|
||||
}
|
||||
|
||||
$draft = $this->pageRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown']));
|
||||
@ -303,211 +251,98 @@ class PageController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect from a special link url which
|
||||
* uses the page id rather than the name.
|
||||
* @param int $pageId
|
||||
* @return RedirectResponse|Redirector
|
||||
* Redirect from a special link url which uses the page id rather than the name.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function redirectFromLink($pageId)
|
||||
public function redirectFromLink(int $pageId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $pageId);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the deletion page for the specified page.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showDelete($bookSlug, $pageSlug)
|
||||
public function showDelete(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
|
||||
return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
|
||||
return view('pages.delete', [
|
||||
'book' => $page->book,
|
||||
'page' => $page,
|
||||
'current' => $page
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the deletion page for the specified page.
|
||||
* @param string $bookSlug
|
||||
* @param int $pageId
|
||||
* @return View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showDeleteDraft($bookSlug, $pageId)
|
||||
public function showDeleteDraft(string $bookSlug, int $pageId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
|
||||
return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
|
||||
return view('pages.delete', [
|
||||
'book' => $page->book,
|
||||
'page' => $page,
|
||||
'current' => $page
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified page from storage.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @internal param int $id
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
* @throws NotifyException
|
||||
*/
|
||||
public function destroy($bookSlug, $pageSlug)
|
||||
public function destroy(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$book = $page->book;
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
$this->pageRepo->destroyPage($page);
|
||||
|
||||
$book = $page->book;
|
||||
$this->pageRepo->destroy($page);
|
||||
Activity::addMessage('page_delete', $page->name, $book->id);
|
||||
$this->showSuccessNotification( trans('entities.pages_delete_success'));
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_delete_success'));
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified draft page from storage.
|
||||
* @param string $bookSlug
|
||||
* @param int $pageId
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws NotifyException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function destroyDraft($bookSlug, $pageId)
|
||||
public function destroyDraft(string $bookSlug, int $pageId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $pageId, true);
|
||||
$page = $this->pageRepo->getById($pageId);
|
||||
$book = $page->book;
|
||||
$chapter = $page->chapter;
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->showSuccessNotification( trans('entities.pages_delete_draft_success'));
|
||||
$this->pageRepo->destroyPage($page);
|
||||
|
||||
$this->pageRepo->destroy($page);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_delete_draft_success'));
|
||||
|
||||
if ($chapter && userCan('view', $chapter)) {
|
||||
return redirect($chapter->getUrl());
|
||||
}
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the last revisions for this page.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showRevisions($bookSlug, $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
||||
return view('pages.revisions', ['page' => $page, 'current' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a preview of a single revision
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param int $revisionId
|
||||
* @return View
|
||||
*/
|
||||
public function showRevision($bookSlug, $pageSlug, $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
||||
if ($revision === null) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$page->fill($revision->toArray());
|
||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
|
||||
|
||||
return view('pages.revision', [
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
'diff' => null,
|
||||
'revision' => $revision
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the changes of a single revision
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param int $revisionId
|
||||
* @return View
|
||||
*/
|
||||
public function showRevisionChanges($bookSlug, $pageSlug, $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
||||
if ($revision === null) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$prev = $revision->getPrevious();
|
||||
$prevContent = ($prev === null) ? '' : $prev->html;
|
||||
$diff = (new Htmldiff)->diff($prevContent, $revision->html);
|
||||
|
||||
$page->fill($revision->toArray());
|
||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
||||
|
||||
return view('pages.revision', [
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
'diff' => $diff,
|
||||
'revision' => $revision
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a page using the content of the specified revision.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param int $revisionId
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$page = $this->pageRepo->restorePageRevision($page, $page->book, $revisionId);
|
||||
Activity::add($page, 'page_restore', $page->book->id);
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a revision using the id of the specified revision.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param int $revId
|
||||
* @return RedirectResponse|Redirector
|
||||
*@throws BadRequestException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function destroyRevision($bookSlug, $pageSlug, $revId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
|
||||
$revision = $page->revisions()->where('id', '=', $revId)->first();
|
||||
if ($revision === null) {
|
||||
throw new NotFoundException("Revision #{$revId} not found");
|
||||
}
|
||||
|
||||
// Get the current revision for the page
|
||||
$currentRevision = $page->getCurrentRevision();
|
||||
|
||||
// Check if its the latest revision, cannot delete latest revision.
|
||||
if (intval($currentRevision->id) === intval($revId)) {
|
||||
$this->showErrorNotification( trans('entities.revision_cannot_delete_latest'));
|
||||
return response()->view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
|
||||
}
|
||||
|
||||
$revision->delete();
|
||||
$this->showSuccessNotification( trans('entities.revision_delete_success'));
|
||||
return redirect($page->getUrl('/revisions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a listing of recently created pages
|
||||
* @return Factory|View
|
||||
* Show a listing of recently created pages.
|
||||
*/
|
||||
public function showRecentlyUpdated()
|
||||
{
|
||||
// TODO - Still exist?
|
||||
$pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(url('/pages/recently-updated'));
|
||||
$pages = Page::visible()->orderBy('updated_at', 'desc')
|
||||
->paginate(20)
|
||||
->setPath(url('/pages/recently-updated'));
|
||||
|
||||
return view('pages.detailed-listing', [
|
||||
'title' => trans('entities.recently_updated_pages'),
|
||||
'pages' => $pages
|
||||
@ -516,14 +351,11 @@ class PageController extends Controller
|
||||
|
||||
/**
|
||||
* Show the view to choose a new parent to move a page into.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showMove($bookSlug, $pageSlug)
|
||||
public function showMove(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
return view('pages.move', [
|
||||
@ -533,17 +365,13 @@ class PageController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the action of moving the location of a page
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return mixed
|
||||
* Does the action of moving the location of a page.
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function move(Request $request, string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
|
||||
@ -552,37 +380,29 @@ class PageController extends Controller
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
$stringExploded = explode(':', $entitySelection);
|
||||
$entityType = $stringExploded[0];
|
||||
$entityId = intval($stringExploded[1]);
|
||||
|
||||
|
||||
try {
|
||||
$parent = $this->pageRepo->getById($entityType, $entityId);
|
||||
} catch (Exception $e) {
|
||||
session()->flash(trans('entities.selected_book_chapter_not_found'));
|
||||
$parent = $this->pageRepo->move($page, $entitySelection);
|
||||
} catch (Exception $exception) {
|
||||
if ($exception instanceof PermissionsException) {
|
||||
$this->showPermissionError();
|
||||
}
|
||||
|
||||
$this->showErrorNotification(trans('errors.selected_book_chapter_not_found'));
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
$this->pageRepo->changePageParent($page, $parent);
|
||||
Activity::add($page, 'page_move', $page->book->id);
|
||||
$this->showSuccessNotification( trans('entities.pages_move_success', ['parentName' => $parent->name]));
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_move_success', ['parentName' => $parent->name]));
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the view to copy a page.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showCopy($bookSlug, $pageSlug)
|
||||
public function showCopy(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-view', $page);
|
||||
session()->flashInput(['name' => $page->name]);
|
||||
return view('pages.copy', [
|
||||
@ -591,79 +411,65 @@ class PageController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a copy of a page within the requested target destination.
|
||||
* @param Request $request
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function copy(Request $request, string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-view', $page);
|
||||
|
||||
$entitySelection = $request->get('entity_selection', null);
|
||||
if ($entitySelection === null || $entitySelection === '') {
|
||||
$parent = $page->chapter ? $page->chapter : $page->book;
|
||||
} else {
|
||||
$stringExploded = explode(':', $entitySelection);
|
||||
$entityType = $stringExploded[0];
|
||||
$entityId = intval($stringExploded[1]);
|
||||
$entitySelection = $request->get('entity_selection', null) ?? null;
|
||||
$newName = $request->get('name', null);
|
||||
|
||||
try {
|
||||
$parent = $this->pageRepo->getById($entityType, $entityId);
|
||||
} catch (Exception $e) {
|
||||
$this->showErrorNotification(trans('entities.selected_book_chapter_not_found'));
|
||||
return redirect()->back();
|
||||
try {
|
||||
$pageCopy = $this->pageRepo->copy($page, $entitySelection, $newName);
|
||||
} catch (Exception $exception) {
|
||||
if ($exception instanceof PermissionsException) {
|
||||
$this->showPermissionError();
|
||||
}
|
||||
|
||||
$this->showErrorNotification(trans('errors.selected_book_chapter_not_found'));
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
$this->checkOwnablePermission('page-create', $parent);
|
||||
|
||||
$pageCopy = $this->pageRepo->copyPage($page, $parent, $request->get('name', ''));
|
||||
|
||||
Activity::add($pageCopy, 'page_create', $pageCopy->book->id);
|
||||
$this->showSuccessNotification( trans('entities.pages_copy_success'));
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_copy_success'));
|
||||
return redirect($pageCopy->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Permissions view.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Factory|View
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showPermissions($bookSlug, $pageSlug)
|
||||
public function showPermissions(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||
$roles = $this->userRepo->getRestrictableRoles();
|
||||
return view('pages.permissions', [
|
||||
'page' => $page,
|
||||
'roles' => $roles
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permissions for this page.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @param Request $request
|
||||
* @return RedirectResponse|Redirector
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function permissions(Request $request, string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||
$this->pageRepo->updateEntityPermissionsFromRequest($request, $page);
|
||||
$this->showSuccessNotification( trans('entities.pages_permissions_success'));
|
||||
|
||||
$restricted = $request->get('restricted') === 'true';
|
||||
$permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null;
|
||||
$this->pageRepo->updatePermissions($page, $restricted, $permissions);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_permissions_success'));
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
}
|
||||
|
@ -3,21 +3,15 @@
|
||||
namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\ExportService;
|
||||
use BookStack\Entities\Managers\PageContent;
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Illuminate\Http\Response;
|
||||
use Throwable;
|
||||
|
||||
class PageExportController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var PageRepo
|
||||
*/
|
||||
protected $pageRepo;
|
||||
|
||||
/**
|
||||
* @var ExportService
|
||||
*/
|
||||
protected $pageRepo;
|
||||
protected $exportService;
|
||||
|
||||
/**
|
||||
@ -35,46 +29,37 @@ class PageExportController extends Controller
|
||||
/**
|
||||
* Exports a page to a PDF.
|
||||
* https://github.com/barryvdh/laravel-dompdf
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function pdf(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page->html = $this->pageRepo->renderPage($page);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$pdfContent = $this->exportService->pageToPdf($page);
|
||||
return $this->downloadResponse($pdfContent, $pageSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a page to a self-contained HTML file.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function html(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page->html = $this->pageRepo->renderPage($page);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$containedHtml = $this->exportService->pageToContainedHtml($page);
|
||||
return $this->downloadResponse($containedHtml, $pageSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a page to a simple plaintext .txt file.
|
||||
* @param string $bookSlug
|
||||
* @param string $pageSlug
|
||||
* @return Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function plainText(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($pageSlug, $bookSlug);
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$pageText = $this->exportService->pageToPlainText($page);
|
||||
return $this->downloadResponse($pageText, $pageSlug . '.txt');
|
||||
}
|
||||
|
128
app/Http/Controllers/PageRevisionController.php
Normal file
128
app/Http/Controllers/PageRevisionController.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Entities\Repos\PageRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Facades\Activity;
|
||||
use GatherContent\Htmldiff\Htmldiff;
|
||||
|
||||
class PageRevisionController extends Controller
|
||||
{
|
||||
|
||||
protected $pageRepo;
|
||||
|
||||
/**
|
||||
* PageRevisionController constructor.
|
||||
*/
|
||||
public function __construct(PageRepo $pageRepo)
|
||||
{
|
||||
$this->pageRepo = $pageRepo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the last revisions for this page.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function index(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
||||
return view('pages.revisions', [
|
||||
'page' => $page,
|
||||
'current' => $page
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a preview of a single revision.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function show(string $bookSlug, string $pageSlug, int $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
||||
if ($revision === null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$page->fill($revision->toArray());
|
||||
|
||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
|
||||
return view('pages.revision', [
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
'diff' => null,
|
||||
'revision' => $revision
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the changes of a single revision.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function changes(string $bookSlug, string $pageSlug, int $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$revision = $page->revisions()->where('id', '=', $revisionId)->first();
|
||||
if ($revision === null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$prev = $revision->getPrevious();
|
||||
$prevContent = $prev->html ?? '';
|
||||
$diff = (new Htmldiff)->diff($prevContent, $revision->html);
|
||||
|
||||
$page->fill($revision->toArray());
|
||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
||||
|
||||
return view('pages.revision', [
|
||||
'page' => $page,
|
||||
'book' => $page->book,
|
||||
'diff' => $diff,
|
||||
'revision' => $revision
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a page using the content of the specified revision.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function restore(string $bookSlug, string $pageSlug, int $revisionId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-update', $page);
|
||||
|
||||
$page = $this->pageRepo->restoreRevision($page, $revisionId);
|
||||
|
||||
Activity::add($page, 'page_restore', $page->book->id);
|
||||
return redirect($page->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a revision using the id of the specified revision.
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function destroy(string $bookSlug, string $pageSlug, int $revId)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('page-delete', $page);
|
||||
|
||||
$revision = $page->revisions()->where('id', '=', $revId)->first();
|
||||
if ($revision === null) {
|
||||
throw new NotFoundException("Revision #{$revId} not found");
|
||||
}
|
||||
|
||||
// Get the current revision for the page
|
||||
$currentRevision = $page->getCurrentRevision();
|
||||
|
||||
// Check if its the latest revision, cannot delete latest revision.
|
||||
if (intval($currentRevision->id) === intval($revId)) {
|
||||
$this->showErrorNotification(trans('entities.revision_cannot_delete_latest'));
|
||||
return redirect($page->getUrl('/revisions'));
|
||||
}
|
||||
|
||||
$revision->delete();
|
||||
$this->showSuccessNotification(trans('entities.revision_delete_success'));
|
||||
return redirect($page->getUrl('/revisions'));
|
||||
}
|
||||
}
|
@ -11,8 +11,7 @@ class PageTemplateController extends Controller
|
||||
protected $pageRepo;
|
||||
|
||||
/**
|
||||
* PageTemplateController constructor.
|
||||
* @param $pageRepo
|
||||
* PageTemplateController constructor
|
||||
*/
|
||||
public function __construct(PageRepo $pageRepo)
|
||||
{
|
||||
@ -22,14 +21,12 @@ class PageTemplateController extends Controller
|
||||
|
||||
/**
|
||||
* Fetch a list of templates from the system.
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
$page = $request->get('page', 1);
|
||||
$search = $request->get('search', '');
|
||||
$templates = $this->pageRepo->getPageTemplates(10, $page, $search);
|
||||
$templates = $this->pageRepo->getTemplates(10, $page, $search);
|
||||
|
||||
if ($search) {
|
||||
$templates->appends(['search' => $search]);
|
||||
@ -42,13 +39,11 @@ class PageTemplateController extends Controller
|
||||
|
||||
/**
|
||||
* Get the content of a template.
|
||||
* @param $templateId
|
||||
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function get($templateId)
|
||||
public function get(int $templateId)
|
||||
{
|
||||
$page = $this->pageRepo->getById('page', $templateId);
|
||||
$page = $this->pageRepo->getById($templateId);
|
||||
|
||||
if (!$page->template) {
|
||||
throw new NotFoundException();
|
||||
|
@ -53,7 +53,7 @@ class PermissionController extends Controller
|
||||
]);
|
||||
|
||||
$this->permissionsRepo->saveNewRole($request->all());
|
||||
$this->showSuccessNotification( trans('settings.role_create_success'));
|
||||
$this->showSuccessNotification(trans('settings.role_create_success'));
|
||||
return redirect('/settings/roles');
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ class PermissionController extends Controller
|
||||
]);
|
||||
|
||||
$this->permissionsRepo->updateRole($id, $request->all());
|
||||
$this->showSuccessNotification( trans('settings.role_update_success'));
|
||||
$this->showSuccessNotification(trans('settings.role_update_success'));
|
||||
return redirect('/settings/roles');
|
||||
}
|
||||
|
||||
@ -124,11 +124,11 @@ class PermissionController extends Controller
|
||||
try {
|
||||
$this->permissionsRepo->deleteRole($id, $request->get('migrate_role_id'));
|
||||
} catch (PermissionsException $e) {
|
||||
$this->showErrorNotification( $e->getMessage());
|
||||
$this->showErrorNotification($e->getMessage());
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
$this->showSuccessNotification( trans('settings.role_delete_success'));
|
||||
$this->showSuccessNotification(trans('settings.role_delete_success'));
|
||||
return redirect('/settings/roles');
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,27 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Actions\ViewService;
|
||||
use BookStack\Entities\EntityContextManager;
|
||||
use BookStack\Entities\Repos\EntityRepo;
|
||||
use BookStack\Entities\Book;
|
||||
use BookStack\Entities\Bookshelf;
|
||||
use BookStack\Entities\Entity;
|
||||
use BookStack\Entities\Managers\EntityContext;
|
||||
use BookStack\Entities\SearchService;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
protected $entityRepo;
|
||||
protected $viewService;
|
||||
protected $searchService;
|
||||
protected $entityContextManager;
|
||||
|
||||
/**
|
||||
* SearchController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
* @param ViewService $viewService
|
||||
* @param SearchService $searchService
|
||||
* @param EntityContextManager $entityContextManager
|
||||
*/
|
||||
public function __construct(
|
||||
EntityRepo $entityRepo,
|
||||
ViewService $viewService,
|
||||
SearchService $searchService,
|
||||
EntityContextManager $entityContextManager
|
||||
EntityContext $entityContextManager
|
||||
) {
|
||||
$this->entityRepo = $entityRepo;
|
||||
$this->viewService = $viewService;
|
||||
$this->searchService = $searchService;
|
||||
$this->entityContextManager = $entityContextManager;
|
||||
@ -38,9 +30,6 @@ class SearchController extends Controller
|
||||
|
||||
/**
|
||||
* Searches all entities.
|
||||
* @param Request $request
|
||||
* @return View
|
||||
* @internal param string $searchTerm
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
@ -64,12 +53,8 @@ class SearchController extends Controller
|
||||
|
||||
/**
|
||||
* Searches all entities within a book.
|
||||
* @param Request $request
|
||||
* @param integer $bookId
|
||||
* @return View
|
||||
* @internal param string $searchTerm
|
||||
*/
|
||||
public function searchBook(Request $request, $bookId)
|
||||
public function searchBook(Request $request, int $bookId)
|
||||
{
|
||||
$term = $request->get('term', '');
|
||||
$results = $this->searchService->searchBook($bookId, $term);
|
||||
@ -78,12 +63,8 @@ class SearchController extends Controller
|
||||
|
||||
/**
|
||||
* Searches all entities within a chapter.
|
||||
* @param Request $request
|
||||
* @param integer $chapterId
|
||||
* @return View
|
||||
* @internal param string $searchTerm
|
||||
*/
|
||||
public function searchChapter(Request $request, $chapterId)
|
||||
public function searchChapter(Request $request, int $chapterId)
|
||||
{
|
||||
$term = $request->get('term', '');
|
||||
$results = $this->searchService->searchChapter($chapterId, $term);
|
||||
@ -93,8 +74,6 @@ class SearchController extends Controller
|
||||
/**
|
||||
* Search for a list of entities and return a partial HTML response of matching entities.
|
||||
* Returns the most popular entities if no search is provided.
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function searchEntitiesAjax(Request $request)
|
||||
{
|
||||
@ -115,15 +94,13 @@ class SearchController extends Controller
|
||||
|
||||
/**
|
||||
* Search siblings items in the system.
|
||||
* @param Request $request
|
||||
* @return Factory|View|mixed
|
||||
*/
|
||||
public function searchSiblings(Request $request)
|
||||
{
|
||||
$type = $request->get('entity_type', null);
|
||||
$id = $request->get('entity_id', null);
|
||||
|
||||
$entity = $this->entityRepo->getById($type, $id);
|
||||
$entity = Entity::getEntityInstance($type)->newQuery()->visible()->find($id);
|
||||
if (!$entity) {
|
||||
return $this->jsonError(trans('errors.entity_not_found'), 404);
|
||||
}
|
||||
@ -132,12 +109,12 @@ class SearchController extends Controller
|
||||
|
||||
// Page in chapter
|
||||
if ($entity->isA('page') && $entity->chapter) {
|
||||
$entities = $this->entityRepo->getChapterChildren($entity->chapter);
|
||||
$entities = $entity->chapter->visiblePages();
|
||||
}
|
||||
|
||||
// Page in book or chapter
|
||||
if (($entity->isA('page') && !$entity->chapter) || $entity->isA('chapter')) {
|
||||
$entities = $this->entityRepo->getBookDirectChildren($entity->book);
|
||||
$entities = $entity->book->getDirectChildren();
|
||||
}
|
||||
|
||||
// Book
|
||||
@ -145,15 +122,15 @@ class SearchController extends Controller
|
||||
if ($entity->isA('book')) {
|
||||
$contextShelf = $this->entityContextManager->getContextualShelfForBook($entity);
|
||||
if ($contextShelf) {
|
||||
$entities = $this->entityRepo->getBookshelfChildren($contextShelf);
|
||||
$entities = $contextShelf->visibleBooks()->get();
|
||||
} else {
|
||||
$entities = $this->entityRepo->getAll('book');
|
||||
$entities = Book::visible()->get();
|
||||
}
|
||||
}
|
||||
|
||||
// Shelve
|
||||
if ($entity->isA('bookshelf')) {
|
||||
$entities = $this->entityRepo->getAll('bookshelf');
|
||||
$entities = Bookshelf::visible()->get();
|
||||
}
|
||||
|
||||
return view('partials.entity-list-basic', ['entities' => $entities, 'style' => 'compact']);
|
||||
|
@ -76,7 +76,7 @@ class SettingController extends Controller
|
||||
setting()->remove('app-logo');
|
||||
}
|
||||
|
||||
$this->showSuccessNotification( trans('settings.settings_save_success'));
|
||||
$this->showSuccessNotification(trans('settings.settings_save_success'));
|
||||
return redirect('/settings');
|
||||
}
|
||||
|
||||
@ -111,14 +111,14 @@ class SettingController extends Controller
|
||||
$imagesToDelete = $imageService->deleteUnusedImages($checkRevisions, $dryRun);
|
||||
$deleteCount = count($imagesToDelete);
|
||||
if ($deleteCount === 0) {
|
||||
$this->showWarningNotification( trans('settings.maint_image_cleanup_nothing_found'));
|
||||
$this->showWarningNotification(trans('settings.maint_image_cleanup_nothing_found'));
|
||||
return redirect('/settings/maintenance')->withInput();
|
||||
}
|
||||
|
||||
if ($dryRun) {
|
||||
session()->flash('cleanup-images-warning', trans('settings.maint_image_cleanup_warning', ['count' => $deleteCount]));
|
||||
} else {
|
||||
$this->showSuccessNotification( trans('settings.maint_image_cleanup_success', ['count' => $deleteCount]));
|
||||
$this->showSuccessNotification(trans('settings.maint_image_cleanup_success', ['count' => $deleteCount]));
|
||||
}
|
||||
|
||||
return redirect('/settings/maintenance#image-cleanup')->withInput();
|
||||
|
@ -202,7 +202,7 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
$user->save();
|
||||
$this->showSuccessNotification( trans('settings.users_edit_success'));
|
||||
$this->showSuccessNotification(trans('settings.users_edit_success'));
|
||||
|
||||
$redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id);
|
||||
return redirect($redirectUrl);
|
||||
@ -236,17 +236,17 @@ class UserController extends Controller
|
||||
$user = $this->userRepo->getById($id);
|
||||
|
||||
if ($this->userRepo->isOnlyAdmin($user)) {
|
||||
$this->showErrorNotification( trans('errors.users_cannot_delete_only_admin'));
|
||||
$this->showErrorNotification(trans('errors.users_cannot_delete_only_admin'));
|
||||
return redirect($user->getEditUrl());
|
||||
}
|
||||
|
||||
if ($user->system_name === 'public') {
|
||||
$this->showErrorNotification( trans('errors.users_cannot_delete_guest'));
|
||||
$this->showErrorNotification(trans('errors.users_cannot_delete_guest'));
|
||||
return redirect($user->getEditUrl());
|
||||
}
|
||||
|
||||
$this->userRepo->destroy($user);
|
||||
$this->showSuccessNotification( trans('settings.users_delete_success'));
|
||||
$this->showSuccessNotification(trans('settings.users_delete_success'));
|
||||
|
||||
return redirect('/settings/users');
|
||||
}
|
||||
@ -261,7 +261,7 @@ class UserController extends Controller
|
||||
$user = $this->userRepo->getById($id);
|
||||
|
||||
$userActivity = $this->userRepo->getActivity($user);
|
||||
$recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
|
||||
$recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5);
|
||||
$assetCounts = $this->userRepo->getAssetCounts($user);
|
||||
|
||||
return view('users.profile', [
|
||||
|
@ -24,5 +24,4 @@ class GlobalViewData
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user