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:
Dan Brown
2019-10-05 12:55:01 +01:00
committed by GitHub
parent 7cd956b24b
commit 31f5786e01
72 changed files with 2705 additions and 2751 deletions

View File

@ -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);

View File

@ -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');
}
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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');
}

View File

@ -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();
}
}
}

View File

@ -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)
{

View 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());
}
}

View File

@ -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();
}
}
}

View File

@ -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());
}
}

View File

@ -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');
}

View File

@ -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')]);
}

View File

@ -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';
}
}

View File

@ -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]));
}

View File

@ -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);
}
/**

View File

@ -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());
}
}

View File

@ -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');
}

View 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'));
}
}

View File

@ -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();

View File

@ -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');
}
}

View File

@ -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']);

View File

@ -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();

View File

@ -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', [

View File

@ -24,5 +24,4 @@ class GlobalViewData
return $next($request);
}
}
}