mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-17 09:52:27 +08:00
Merge pull request #262 from BookStackApp/entity_repo_refactor
Entity repo refactor
This commit is contained in:
@ -5,6 +5,8 @@ class Chapter extends Entity
|
|||||||
{
|
{
|
||||||
protected $fillable = ['name', 'description', 'priority', 'book_id'];
|
protected $fillable = ['name', 'description', 'priority', 'book_id'];
|
||||||
|
|
||||||
|
protected $with = ['book'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the book this chapter is within.
|
* Get the book this chapter is within.
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
@ -16,11 +18,12 @@ class Chapter extends Entity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the pages that this chapter contains.
|
* Get the pages that this chapter contains.
|
||||||
|
* @param string $dir
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function pages()
|
public function pages($dir = 'ASC')
|
||||||
{
|
{
|
||||||
return $this->hasMany(Page::class)->orderBy('priority', 'ASC');
|
return $this->hasMany(Page::class)->orderBy('priority', $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
class Entity extends Ownable
|
class Entity extends Ownable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected $fieldsToSearch = ['name', 'description'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares this entity to another given entity.
|
* Compares this entity to another given entity.
|
||||||
* Matches by comparing class and id.
|
* Matches by comparing class and id.
|
||||||
@ -157,7 +159,7 @@ class Entity extends Ownable
|
|||||||
* @param string[] array $wheres
|
* @param string[] array $wheres
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = [])
|
public function fullTextSearchQuery($terms, $wheres = [])
|
||||||
{
|
{
|
||||||
$exactTerms = [];
|
$exactTerms = [];
|
||||||
$fuzzyTerms = [];
|
$fuzzyTerms = [];
|
||||||
@ -181,16 +183,16 @@ class Entity extends Ownable
|
|||||||
// Perform fulltext search if relevant terms exist.
|
// Perform fulltext search if relevant terms exist.
|
||||||
if ($isFuzzy) {
|
if ($isFuzzy) {
|
||||||
$termString = implode(' ', $fuzzyTerms);
|
$termString = implode(' ', $fuzzyTerms);
|
||||||
$fields = implode(',', $fieldsToSearch);
|
$fields = implode(',', $this->fieldsToSearch);
|
||||||
$search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]);
|
$search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]);
|
||||||
$search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
|
$search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure at least one exact term matches if in search
|
// Ensure at least one exact term matches if in search
|
||||||
if (count($exactTerms) > 0) {
|
if (count($exactTerms) > 0) {
|
||||||
$search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) {
|
$search = $search->where(function ($query) use ($exactTerms) {
|
||||||
foreach ($exactTerms as $exactTerm) {
|
foreach ($exactTerms as $exactTerm) {
|
||||||
foreach ($fieldsToSearch as $field) {
|
foreach ($this->fieldsToSearch as $field) {
|
||||||
$query->orWhere($field, 'like', $exactTerm);
|
$query->orWhere($field, 'like', $exactTerm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use BookStack\Exceptions\FileUploadException;
|
use BookStack\Exceptions\FileUploadException;
|
||||||
use BookStack\Attachment;
|
use BookStack\Attachment;
|
||||||
use BookStack\Repos\PageRepo;
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Services\AttachmentService;
|
use BookStack\Services\AttachmentService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@ -10,19 +10,19 @@ class AttachmentController extends Controller
|
|||||||
{
|
{
|
||||||
protected $attachmentService;
|
protected $attachmentService;
|
||||||
protected $attachment;
|
protected $attachment;
|
||||||
protected $pageRepo;
|
protected $entityRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AttachmentController constructor.
|
* AttachmentController constructor.
|
||||||
* @param AttachmentService $attachmentService
|
* @param AttachmentService $attachmentService
|
||||||
* @param Attachment $attachment
|
* @param Attachment $attachment
|
||||||
* @param PageRepo $pageRepo
|
* @param EntityRepo $entityRepo
|
||||||
*/
|
*/
|
||||||
public function __construct(AttachmentService $attachmentService, Attachment $attachment, PageRepo $pageRepo)
|
public function __construct(AttachmentService $attachmentService, Attachment $attachment, EntityRepo $entityRepo)
|
||||||
{
|
{
|
||||||
$this->attachmentService = $attachmentService;
|
$this->attachmentService = $attachmentService;
|
||||||
$this->attachment = $attachment;
|
$this->attachment = $attachment;
|
||||||
$this->pageRepo = $pageRepo;
|
$this->entityRepo = $entityRepo;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class AttachmentController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$pageId = $request->get('uploaded_to');
|
$pageId = $request->get('uploaded_to');
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
|
|
||||||
$this->checkPermission('attachment-create-all');
|
$this->checkPermission('attachment-create-all');
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
@ -70,7 +70,7 @@ class AttachmentController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$pageId = $request->get('uploaded_to');
|
$pageId = $request->get('uploaded_to');
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||||
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
@ -106,7 +106,7 @@ class AttachmentController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$pageId = $request->get('uploaded_to');
|
$pageId = $request->get('uploaded_to');
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||||
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
@ -134,7 +134,7 @@ class AttachmentController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$pageId = $request->get('uploaded_to');
|
$pageId = $request->get('uploaded_to');
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
|
|
||||||
$this->checkPermission('attachment-create-all');
|
$this->checkPermission('attachment-create-all');
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
@ -153,7 +153,7 @@ class AttachmentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function listForPage($pageId)
|
public function listForPage($pageId)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$this->checkOwnablePermission('page-view', $page);
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
return response()->json($page->attachments);
|
return response()->json($page->attachments);
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ class AttachmentController extends Controller
|
|||||||
'files' => 'required|array',
|
'files' => 'required|array',
|
||||||
'files.*.id' => 'required|integer',
|
'files.*.id' => 'required|integer',
|
||||||
]);
|
]);
|
||||||
$page = $this->pageRepo->getById($pageId);
|
$page = $this->entityRepo->getById('page', $pageId);
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
|
|
||||||
$attachments = $request->get('files');
|
$attachments = $request->get('files');
|
||||||
@ -186,7 +186,7 @@ class AttachmentController extends Controller
|
|||||||
public function get($attachmentId)
|
public function get($attachmentId)
|
||||||
{
|
{
|
||||||
$attachment = $this->attachment->findOrFail($attachmentId);
|
$attachment = $this->attachment->findOrFail($attachmentId);
|
||||||
$page = $this->pageRepo->getById($attachment->uploaded_to);
|
$page = $this->entityRepo->getById('page', $attachment->uploaded_to);
|
||||||
$this->checkOwnablePermission('page-view', $page);
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
|
|
||||||
if ($attachment->external) {
|
if ($attachment->external) {
|
||||||
|
@ -1,35 +1,26 @@
|
|||||||
<?php namespace BookStack\Http\Controllers;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
use Activity;
|
use Activity;
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Repos\UserRepo;
|
use BookStack\Repos\UserRepo;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use BookStack\Http\Requests;
|
|
||||||
use BookStack\Repos\BookRepo;
|
|
||||||
use BookStack\Repos\ChapterRepo;
|
|
||||||
use BookStack\Repos\PageRepo;
|
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Views;
|
use Views;
|
||||||
|
|
||||||
class BookController extends Controller
|
class BookController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $bookRepo;
|
protected $entityRepo;
|
||||||
protected $pageRepo;
|
|
||||||
protected $chapterRepo;
|
|
||||||
protected $userRepo;
|
protected $userRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BookController constructor.
|
* BookController constructor.
|
||||||
* @param BookRepo $bookRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param PageRepo $pageRepo
|
|
||||||
* @param ChapterRepo $chapterRepo
|
|
||||||
* @param UserRepo $userRepo
|
* @param UserRepo $userRepo
|
||||||
*/
|
*/
|
||||||
public function __construct(BookRepo $bookRepo, PageRepo $pageRepo, ChapterRepo $chapterRepo, UserRepo $userRepo)
|
public function __construct(EntityRepo $entityRepo, UserRepo $userRepo)
|
||||||
{
|
{
|
||||||
$this->bookRepo = $bookRepo;
|
$this->entityRepo = $entityRepo;
|
||||||
$this->pageRepo = $pageRepo;
|
|
||||||
$this->chapterRepo = $chapterRepo;
|
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
@ -40,9 +31,9 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$books = $this->bookRepo->getAllPaginated(10);
|
$books = $this->entityRepo->getAllPaginated('book', 10);
|
||||||
$recents = $this->signedIn ? $this->bookRepo->getRecentlyViewed(4, 0) : false;
|
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
|
||||||
$popular = $this->bookRepo->getPopular(4, 0);
|
$popular = $this->entityRepo->getPopular('book', 4, 0);
|
||||||
$this->setPageTitle('Books');
|
$this->setPageTitle('Books');
|
||||||
return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular]);
|
return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular]);
|
||||||
}
|
}
|
||||||
@ -71,7 +62,7 @@ class BookController extends Controller
|
|||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'description' => 'string|max:1000'
|
'description' => 'string|max:1000'
|
||||||
]);
|
]);
|
||||||
$book = $this->bookRepo->createFromInput($request->all());
|
$book = $this->entityRepo->createFromInput('book', $request->all());
|
||||||
Activity::add($book, 'book_create', $book->id);
|
Activity::add($book, 'book_create', $book->id);
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
@ -83,9 +74,9 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show($slug)
|
public function show($slug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($slug);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-view', $book);
|
$this->checkOwnablePermission('book-view', $book);
|
||||||
$bookChildren = $this->bookRepo->getChildren($book);
|
$bookChildren = $this->entityRepo->getBookChildren($book);
|
||||||
Views::add($book);
|
Views::add($book);
|
||||||
$this->setPageTitle($book->getShortName());
|
$this->setPageTitle($book->getShortName());
|
||||||
return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
|
return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
|
||||||
@ -98,7 +89,7 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit($slug)
|
public function edit($slug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($slug);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
$this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()]));
|
$this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()]));
|
||||||
return view('books/edit', ['book' => $book, 'current' => $book]);
|
return view('books/edit', ['book' => $book, 'current' => $book]);
|
||||||
@ -112,13 +103,13 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Request $request, $slug)
|
public function update(Request $request, $slug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($slug);
|
$book = $this->entityRepo->getBySlug('book', $slug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'description' => 'string|max:1000'
|
'description' => 'string|max:1000'
|
||||||
]);
|
]);
|
||||||
$book = $this->bookRepo->updateFromInput($book, $request->all());
|
$book = $this->entityRepo->updateFromInput('book', $book, $request->all());
|
||||||
Activity::add($book, 'book_update', $book->id);
|
Activity::add($book, 'book_update', $book->id);
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
@ -130,7 +121,7 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showDelete($bookSlug)
|
public function showDelete($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-delete', $book);
|
$this->checkOwnablePermission('book-delete', $book);
|
||||||
$this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
|
$this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
|
||||||
return view('books/delete', ['book' => $book, 'current' => $book]);
|
return view('books/delete', ['book' => $book, 'current' => $book]);
|
||||||
@ -143,10 +134,10 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function sort($bookSlug)
|
public function sort($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
$bookChildren = $this->bookRepo->getChildren($book, true);
|
$bookChildren = $this->entityRepo->getBookChildren($book, true);
|
||||||
$books = $this->bookRepo->getAll(false);
|
$books = $this->entityRepo->getAll('book', false);
|
||||||
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
|
$this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
|
||||||
return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
|
return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
|
||||||
}
|
}
|
||||||
@ -159,8 +150,8 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function getSortItem($bookSlug)
|
public function getSortItem($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$bookChildren = $this->bookRepo->getChildren($book);
|
$bookChildren = $this->entityRepo->getBookChildren($book);
|
||||||
return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
|
return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +163,7 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function saveSort($bookSlug, Request $request)
|
public function saveSort($bookSlug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-update', $book);
|
$this->checkOwnablePermission('book-update', $book);
|
||||||
|
|
||||||
// Return if no map sent
|
// Return if no map sent
|
||||||
@ -191,13 +182,13 @@ class BookController extends Controller
|
|||||||
$priority = $bookChild->sort;
|
$priority = $bookChild->sort;
|
||||||
$id = intval($bookChild->id);
|
$id = intval($bookChild->id);
|
||||||
$isPage = $bookChild->type == 'page';
|
$isPage = $bookChild->type == 'page';
|
||||||
$bookId = $this->bookRepo->exists($bookChild->book) ? intval($bookChild->book) : $defaultBookId;
|
$bookId = $this->entityRepo->exists('book', $bookChild->book) ? intval($bookChild->book) : $defaultBookId;
|
||||||
$chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter);
|
$chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter);
|
||||||
$model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id);
|
$model = $this->entityRepo->getById($isPage?'page':'chapter', $id);
|
||||||
|
|
||||||
// Update models only if there's a change in parent chain or ordering.
|
// Update models only if there's a change in parent chain or ordering.
|
||||||
if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) {
|
if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) {
|
||||||
$isPage ? $this->pageRepo->changeBook($bookId, $model) : $this->chapterRepo->changeBook($bookId, $model);
|
$this->entityRepo->changeBook($isPage?'page':'chapter', $bookId, $model);
|
||||||
$model->priority = $priority;
|
$model->priority = $priority;
|
||||||
if ($isPage) $model->chapter_id = $chapterId;
|
if ($isPage) $model->chapter_id = $chapterId;
|
||||||
$model->save();
|
$model->save();
|
||||||
@ -212,12 +203,12 @@ class BookController extends Controller
|
|||||||
|
|
||||||
// Add activity for books
|
// Add activity for books
|
||||||
foreach ($sortedBooks as $bookId) {
|
foreach ($sortedBooks as $bookId) {
|
||||||
$updatedBook = $this->bookRepo->getById($bookId);
|
$updatedBook = $this->entityRepo->getById('book', $bookId);
|
||||||
Activity::add($updatedBook, 'book_sort', $updatedBook->id);
|
Activity::add($updatedBook, 'book_sort', $updatedBook->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update permissions on changed models
|
// Update permissions on changed models
|
||||||
$this->bookRepo->buildJointPermissions($updatedModels);
|
$this->entityRepo->buildJointPermissions($updatedModels);
|
||||||
|
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
@ -229,11 +220,10 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy($bookSlug)
|
public function destroy($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('book-delete', $book);
|
$this->checkOwnablePermission('book-delete', $book);
|
||||||
Activity::addMessage('book_delete', 0, $book->name);
|
Activity::addMessage('book_delete', 0, $book->name);
|
||||||
Activity::removeEntity($book);
|
$this->entityRepo->destroyBook($book);
|
||||||
$this->bookRepo->destroy($book);
|
|
||||||
return redirect('/books');
|
return redirect('/books');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +234,7 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRestrict($bookSlug)
|
public function showRestrict($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('books/restrictions', [
|
return view('books/restrictions', [
|
||||||
@ -262,9 +252,9 @@ class BookController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function restrict($bookSlug, Request $request)
|
public function restrict($bookSlug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||||
$this->bookRepo->updateEntityPermissionsFromRequest($request, $book);
|
$this->entityRepo->updateEntityPermissionsFromRequest($request, $book);
|
||||||
session()->flash('success', trans('entities.books_permissions_updated'));
|
session()->flash('success', trans('entities.books_permissions_updated'));
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,26 @@
|
|||||||
<?php namespace BookStack\Http\Controllers;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
use Activity;
|
use Activity;
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Repos\UserRepo;
|
use BookStack\Repos\UserRepo;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use BookStack\Repos\BookRepo;
|
|
||||||
use BookStack\Repos\ChapterRepo;
|
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Views;
|
use Views;
|
||||||
|
|
||||||
class ChapterController extends Controller
|
class ChapterController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $bookRepo;
|
|
||||||
protected $chapterRepo;
|
|
||||||
protected $userRepo;
|
protected $userRepo;
|
||||||
|
protected $entityRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChapterController constructor.
|
* ChapterController constructor.
|
||||||
* @param BookRepo $bookRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param ChapterRepo $chapterRepo
|
|
||||||
* @param UserRepo $userRepo
|
* @param UserRepo $userRepo
|
||||||
*/
|
*/
|
||||||
public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo, UserRepo $userRepo)
|
public function __construct(EntityRepo $entityRepo, UserRepo $userRepo)
|
||||||
{
|
{
|
||||||
$this->bookRepo = $bookRepo;
|
$this->entityRepo = $entityRepo;
|
||||||
$this->chapterRepo = $chapterRepo;
|
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
@ -36,7 +32,7 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create($bookSlug)
|
public function create($bookSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-create', $book);
|
$this->checkOwnablePermission('chapter-create', $book);
|
||||||
$this->setPageTitle(trans('entities.chapters_create'));
|
$this->setPageTitle(trans('entities.chapters_create'));
|
||||||
return view('chapters/create', ['book' => $book, 'current' => $book]);
|
return view('chapters/create', ['book' => $book, 'current' => $book]);
|
||||||
@ -54,12 +50,12 @@ class ChapterController extends Controller
|
|||||||
'name' => 'required|string|max:255'
|
'name' => 'required|string|max:255'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$this->checkOwnablePermission('chapter-create', $book);
|
$this->checkOwnablePermission('chapter-create', $book);
|
||||||
|
|
||||||
$input = $request->all();
|
$input = $request->all();
|
||||||
$input['priority'] = $this->bookRepo->getNewPriority($book);
|
$input['priority'] = $this->entityRepo->getNewBookPriority($book);
|
||||||
$chapter = $this->chapterRepo->createFromInput($input, $book);
|
$chapter = $this->entityRepo->createFromInput('chapter', $input, $book);
|
||||||
Activity::add($chapter, 'chapter_create', $book->id);
|
Activity::add($chapter, 'chapter_create', $book->id);
|
||||||
return redirect($chapter->getUrl());
|
return redirect($chapter->getUrl());
|
||||||
}
|
}
|
||||||
@ -72,15 +68,14 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show($bookSlug, $chapterSlug)
|
public function show($bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('chapter-view', $chapter);
|
$this->checkOwnablePermission('chapter-view', $chapter);
|
||||||
$sidebarTree = $this->bookRepo->getChildren($book);
|
$sidebarTree = $this->entityRepo->getBookChildren($chapter->book);
|
||||||
Views::add($chapter);
|
Views::add($chapter);
|
||||||
$this->setPageTitle($chapter->getShortName());
|
$this->setPageTitle($chapter->getShortName());
|
||||||
$pages = $this->chapterRepo->getChildren($chapter);
|
$pages = $this->entityRepo->getChapterChildren($chapter);
|
||||||
return view('chapters/show', [
|
return view('chapters/show', [
|
||||||
'book' => $book,
|
'book' => $chapter->book,
|
||||||
'chapter' => $chapter,
|
'chapter' => $chapter,
|
||||||
'current' => $chapter,
|
'current' => $chapter,
|
||||||
'sidebarTree' => $sidebarTree,
|
'sidebarTree' => $sidebarTree,
|
||||||
@ -96,11 +91,10 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit($bookSlug, $chapterSlug)
|
public function edit($bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
|
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
|
||||||
return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
|
return view('chapters/edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,16 +106,15 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Request $request, $bookSlug, $chapterSlug)
|
public function update(Request $request, $bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
if ($chapter->name !== $request->get('name')) {
|
if ($chapter->name !== $request->get('name')) {
|
||||||
$chapter->slug = $this->chapterRepo->findSuitableSlug($request->get('name'), $book->id, $chapter->id);
|
$chapter->slug = $this->entityRepo->findSuitableSlug('chapter', $request->get('name'), $chapter->id, $chapter->book->id);
|
||||||
}
|
}
|
||||||
$chapter->fill($request->all());
|
$chapter->fill($request->all());
|
||||||
$chapter->updated_by = user()->id;
|
$chapter->updated_by = user()->id;
|
||||||
$chapter->save();
|
$chapter->save();
|
||||||
Activity::add($chapter, 'chapter_update', $book->id);
|
Activity::add($chapter, 'chapter_update', $chapter->book->id);
|
||||||
return redirect($chapter->getUrl());
|
return redirect($chapter->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +126,10 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showDelete($bookSlug, $chapterSlug)
|
public function showDelete($bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||||
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
|
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
|
||||||
return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
|
return view('chapters/delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,11 +140,11 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy($bookSlug, $chapterSlug)
|
public function destroy($bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
$book = $chapter->book;
|
||||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||||
Activity::addMessage('chapter_delete', $book->id, $chapter->name);
|
Activity::addMessage('chapter_delete', $book->id, $chapter->name);
|
||||||
$this->chapterRepo->destroy($chapter);
|
$this->entityRepo->destroyChapter($chapter);
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,13 +156,12 @@ class ChapterController extends Controller
|
|||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function showMove($bookSlug, $chapterSlug) {
|
public function showMove($bookSlug, $chapterSlug) {
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
return view('chapters/move', [
|
return view('chapters/move', [
|
||||||
'chapter' => $chapter,
|
'chapter' => $chapter,
|
||||||
'book' => $book
|
'book' => $chapter->book
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,8 +174,7 @@ class ChapterController extends Controller
|
|||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function move($bookSlug, $chapterSlug, Request $request) {
|
public function move($bookSlug, $chapterSlug, Request $request) {
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('chapter-update', $chapter);
|
$this->checkOwnablePermission('chapter-update', $chapter);
|
||||||
|
|
||||||
$entitySelection = $request->get('entity_selection', null);
|
$entitySelection = $request->get('entity_selection', null);
|
||||||
@ -199,7 +189,7 @@ class ChapterController extends Controller
|
|||||||
$parent = false;
|
$parent = false;
|
||||||
|
|
||||||
if ($entityType == 'book') {
|
if ($entityType == 'book') {
|
||||||
$parent = $this->bookRepo->getById($entityId);
|
$parent = $this->entityRepo->getById('book', $entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($parent === false || $parent === null) {
|
if ($parent === false || $parent === null) {
|
||||||
@ -207,7 +197,7 @@ class ChapterController extends Controller
|
|||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->chapterRepo->changeBook($parent->id, $chapter, true);
|
$this->entityRepo->changeBook('chapter', $parent->id, $chapter, true);
|
||||||
Activity::add($chapter, 'chapter_move', $chapter->book->id);
|
Activity::add($chapter, 'chapter_move', $chapter->book->id);
|
||||||
session()->flash('success', trans('entities.chapter_move_success', ['bookName' => $parent->name]));
|
session()->flash('success', trans('entities.chapter_move_success', ['bookName' => $parent->name]));
|
||||||
|
|
||||||
@ -222,8 +212,7 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRestrict($bookSlug, $chapterSlug)
|
public function showRestrict($bookSlug, $chapterSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('chapters/restrictions', [
|
return view('chapters/restrictions', [
|
||||||
@ -241,10 +230,9 @@ class ChapterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function restrict($bookSlug, $chapterSlug, Request $request)
|
public function restrict($bookSlug, $chapterSlug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug);
|
||||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||||
$this->chapterRepo->updateEntityPermissionsFromRequest($request, $chapter);
|
$this->entityRepo->updateEntityPermissionsFromRequest($request, $chapter);
|
||||||
session()->flash('success', trans('entities.chapters_permissions_success'));
|
session()->flash('success', trans('entities.chapters_permissions_success'));
|
||||||
return redirect($chapter->getUrl());
|
return redirect($chapter->getUrl());
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers;
|
|||||||
use Activity;
|
use Activity;
|
||||||
use BookStack\Repos\EntityRepo;
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Http\Requests;
|
use BookStack\Http\Requests;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use Views;
|
use Views;
|
||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
@ -31,9 +32,9 @@ class HomeController extends Controller
|
|||||||
$activity = Activity::latest(10);
|
$activity = Activity::latest(10);
|
||||||
$draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : [];
|
$draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : [];
|
||||||
$recentFactor = count($draftPages) > 0 ? 0.5 : 1;
|
$recentFactor = count($draftPages) > 0 ? 0.5 : 1;
|
||||||
$recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreatedBooks(10*$recentFactor);
|
$recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 10*$recentFactor);
|
||||||
$recentlyCreatedPages = $this->entityRepo->getRecentlyCreatedPages(5);
|
$recentlyCreatedPages = $this->entityRepo->getRecentlyCreated('page', 5);
|
||||||
$recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdatedPages(5);
|
$recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 5);
|
||||||
return view('home', [
|
return view('home', [
|
||||||
'activity' => $activity,
|
'activity' => $activity,
|
||||||
'recents' => $recents,
|
'recents' => $recents,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php namespace BookStack\Http\Controllers;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
use BookStack\Exceptions\ImageUploadException;
|
use BookStack\Exceptions\ImageUploadException;
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Repos\ImageRepo;
|
use BookStack\Repos\ImageRepo;
|
||||||
use Illuminate\Filesystem\Filesystem as File;
|
use Illuminate\Filesystem\Filesystem as File;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -150,12 +151,12 @@ class ImageController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an image and all thumbnail/image files
|
* Deletes an image and all thumbnail/image files
|
||||||
* @param PageRepo $pageRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function destroy(PageRepo $pageRepo, Request $request, $id)
|
public function destroy(EntityRepo $entityRepo, Request $request, $id)
|
||||||
{
|
{
|
||||||
$image = $this->imageRepo->getById($id);
|
$image = $this->imageRepo->getById($id);
|
||||||
$this->checkOwnablePermission('image-delete', $image);
|
$this->checkOwnablePermission('image-delete', $image);
|
||||||
@ -163,7 +164,7 @@ class ImageController extends Controller
|
|||||||
// Check if this image is used on any pages
|
// Check if this image is used on any pages
|
||||||
$isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
|
$isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
|
||||||
if (!$isForced) {
|
if (!$isForced) {
|
||||||
$pageSearch = $pageRepo->searchForImage($image->url);
|
$pageSearch = $entityRepo->searchForImage($image->url);
|
||||||
if ($pageSearch !== false) {
|
if ($pageSearch !== false) {
|
||||||
return response()->json($pageSearch, 400);
|
return response()->json($pageSearch, 400);
|
||||||
}
|
}
|
||||||
|
@ -2,41 +2,31 @@
|
|||||||
|
|
||||||
use Activity;
|
use Activity;
|
||||||
use BookStack\Exceptions\NotFoundException;
|
use BookStack\Exceptions\NotFoundException;
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Repos\UserRepo;
|
use BookStack\Repos\UserRepo;
|
||||||
use BookStack\Services\ExportService;
|
use BookStack\Services\ExportService;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use BookStack\Http\Requests;
|
|
||||||
use BookStack\Repos\BookRepo;
|
|
||||||
use BookStack\Repos\ChapterRepo;
|
|
||||||
use BookStack\Repos\PageRepo;
|
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
use Views;
|
use Views;
|
||||||
use GatherContent\Htmldiff\Htmldiff;
|
use GatherContent\Htmldiff\Htmldiff;
|
||||||
|
|
||||||
class PageController extends Controller
|
class PageController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $pageRepo;
|
protected $entityRepo;
|
||||||
protected $bookRepo;
|
|
||||||
protected $chapterRepo;
|
|
||||||
protected $exportService;
|
protected $exportService;
|
||||||
protected $userRepo;
|
protected $userRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PageController constructor.
|
* PageController constructor.
|
||||||
* @param PageRepo $pageRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param BookRepo $bookRepo
|
|
||||||
* @param ChapterRepo $chapterRepo
|
|
||||||
* @param ExportService $exportService
|
* @param ExportService $exportService
|
||||||
* @param UserRepo $userRepo
|
* @param UserRepo $userRepo
|
||||||
*/
|
*/
|
||||||
public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ExportService $exportService, UserRepo $userRepo)
|
public function __construct(EntityRepo $entityRepo, ExportService $exportService, UserRepo $userRepo)
|
||||||
{
|
{
|
||||||
$this->pageRepo = $pageRepo;
|
$this->entityRepo = $entityRepo;
|
||||||
$this->bookRepo = $bookRepo;
|
|
||||||
$this->chapterRepo = $chapterRepo;
|
|
||||||
$this->exportService = $exportService;
|
$this->exportService = $exportService;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@ -51,14 +41,14 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create($bookSlug, $chapterSlug = null)
|
public function create($bookSlug, $chapterSlug = null)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : null;
|
$chapter = $chapterSlug ? $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug) : null;
|
||||||
$parent = $chapter ? $chapter : $book;
|
$parent = $chapter ? $chapter : $book;
|
||||||
$this->checkOwnablePermission('page-create', $parent);
|
$this->checkOwnablePermission('page-create', $parent);
|
||||||
|
|
||||||
// Redirect to draft edit screen if signed in
|
// Redirect to draft edit screen if signed in
|
||||||
if ($this->signedIn) {
|
if ($this->signedIn) {
|
||||||
$draft = $this->pageRepo->getDraftPage($book, $chapter);
|
$draft = $this->entityRepo->getDraftPage($book, $chapter);
|
||||||
return redirect($draft->getUrl());
|
return redirect($draft->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,13 +71,13 @@ class PageController extends Controller
|
|||||||
'name' => 'required|string|max:255'
|
'name' => 'required|string|max:255'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
$chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : null;
|
$chapter = $chapterSlug ? $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug) : null;
|
||||||
$parent = $chapter ? $chapter : $book;
|
$parent = $chapter ? $chapter : $book;
|
||||||
$this->checkOwnablePermission('page-create', $parent);
|
$this->checkOwnablePermission('page-create', $parent);
|
||||||
|
|
||||||
$page = $this->pageRepo->getDraftPage($book, $chapter);
|
$page = $this->entityRepo->getDraftPage($book, $chapter);
|
||||||
$this->pageRepo->publishDraft($page, [
|
$this->entityRepo->publishPageDraft($page, [
|
||||||
'name' => $request->get('name'),
|
'name' => $request->get('name'),
|
||||||
'html' => ''
|
'html' => ''
|
||||||
]);
|
]);
|
||||||
@ -102,15 +92,14 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function editDraft($bookSlug, $pageId)
|
public function editDraft($bookSlug, $pageId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$draft = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$draft = $this->pageRepo->getById($pageId, true);
|
$this->checkOwnablePermission('page-create', $draft->book);
|
||||||
$this->checkOwnablePermission('page-create', $book);
|
|
||||||
$this->setPageTitle(trans('entities.pages_edit_draft'));
|
$this->setPageTitle(trans('entities.pages_edit_draft'));
|
||||||
|
|
||||||
$draftsEnabled = $this->signedIn;
|
$draftsEnabled = $this->signedIn;
|
||||||
return view('pages/edit', [
|
return view('pages/edit', [
|
||||||
'page' => $draft,
|
'page' => $draft,
|
||||||
'book' => $book,
|
'book' => $draft->book,
|
||||||
'isDraft' => true,
|
'isDraft' => true,
|
||||||
'draftsEnabled' => $draftsEnabled
|
'draftsEnabled' => $draftsEnabled
|
||||||
]);
|
]);
|
||||||
@ -130,21 +119,21 @@ class PageController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$input = $request->all();
|
$input = $request->all();
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$book = $this->entityRepo->getBySlug('book', $bookSlug);
|
||||||
|
|
||||||
$draftPage = $this->pageRepo->getById($pageId, true);
|
$draftPage = $this->entityRepo->getById('page', $pageId, true);
|
||||||
|
|
||||||
$chapterId = intval($draftPage->chapter_id);
|
$chapterId = intval($draftPage->chapter_id);
|
||||||
$parent = $chapterId !== 0 ? $this->chapterRepo->getById($chapterId) : $book;
|
$parent = $chapterId !== 0 ? $this->entityRepo->getById('chapter', $chapterId) : $book;
|
||||||
$this->checkOwnablePermission('page-create', $parent);
|
$this->checkOwnablePermission('page-create', $parent);
|
||||||
|
|
||||||
if ($parent->isA('chapter')) {
|
if ($parent->isA('chapter')) {
|
||||||
$input['priority'] = $this->chapterRepo->getNewPriority($parent);
|
$input['priority'] = $this->entityRepo->getNewChapterPriority($parent);
|
||||||
} else {
|
} else {
|
||||||
$input['priority'] = $this->bookRepo->getNewPriority($parent);
|
$input['priority'] = $this->entityRepo->getNewBookPriority($parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
$page = $this->pageRepo->publishDraft($draftPage, $input);
|
$page = $this->entityRepo->publishPageDraft($draftPage, $input);
|
||||||
|
|
||||||
Activity::add($page, 'page_create', $book->id);
|
Activity::add($page, 'page_create', $book->id);
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
@ -152,32 +141,29 @@ class PageController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the specified page.
|
* Display the specified page.
|
||||||
* If the page is not found via the slug the
|
* If the page is not found via the slug the revisions are searched for a match.
|
||||||
* revisions are searched for a match.
|
|
||||||
* @param string $bookSlug
|
* @param string $bookSlug
|
||||||
* @param string $pageSlug
|
* @param string $pageSlug
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function show($bookSlug, $pageSlug)
|
public function show($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
$page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
|
$page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
|
||||||
if ($page === null) abort(404);
|
if ($page === null) abort(404);
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkOwnablePermission('page-view', $page);
|
$this->checkOwnablePermission('page-view', $page);
|
||||||
|
|
||||||
$sidebarTree = $this->bookRepo->getChildren($book);
|
$sidebarTree = $this->entityRepo->getBookChildren($page->book);
|
||||||
$pageNav = $this->pageRepo->getPageNav($page);
|
$pageNav = $this->entityRepo->getPageNav($page);
|
||||||
|
|
||||||
Views::add($page);
|
Views::add($page);
|
||||||
$this->setPageTitle($page->getShortName());
|
$this->setPageTitle($page->getShortName());
|
||||||
return view('pages/show', ['page' => $page, 'book' => $book,
|
return view('pages/show', ['page' => $page, 'book' => $page->book,
|
||||||
'current' => $page, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]);
|
'current' => $page, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +174,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function getPageAjax($pageId)
|
public function getPageAjax($pageId)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getById($pageId);
|
$page = $this->entityRepo->getById('page', $pageId);
|
||||||
return response()->json($page);
|
return response()->json($page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,26 +186,25 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit($bookSlug, $pageSlug)
|
public function edit($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()]));
|
||||||
$page->isDraft = false;
|
$page->isDraft = false;
|
||||||
|
|
||||||
// Check for active editing
|
// Check for active editing
|
||||||
$warnings = [];
|
$warnings = [];
|
||||||
if ($this->pageRepo->isPageEditingActive($page, 60)) {
|
if ($this->entityRepo->isPageEditingActive($page, 60)) {
|
||||||
$warnings[] = $this->pageRepo->getPageEditingActiveMessage($page, 60);
|
$warnings[] = $this->entityRepo->getPageEditingActiveMessage($page, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a current draft version for this user
|
// Check for a current draft version for this user
|
||||||
if ($this->pageRepo->hasUserGotPageDraft($page, $this->currentUser->id)) {
|
if ($this->entityRepo->hasUserGotPageDraft($page, $this->currentUser->id)) {
|
||||||
$draft = $this->pageRepo->getUserPageDraft($page, $this->currentUser->id);
|
$draft = $this->entityRepo->getUserPageDraft($page, $this->currentUser->id);
|
||||||
$page->name = $draft->name;
|
$page->name = $draft->name;
|
||||||
$page->html = $draft->html;
|
$page->html = $draft->html;
|
||||||
$page->markdown = $draft->markdown;
|
$page->markdown = $draft->markdown;
|
||||||
$page->isDraft = true;
|
$page->isDraft = true;
|
||||||
$warnings [] = $this->pageRepo->getUserPageDraftMessage($draft);
|
$warnings [] = $this->entityRepo->getUserPageDraftMessage($draft);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($warnings) > 0) session()->flash('warning', implode("\n", $warnings));
|
if (count($warnings) > 0) session()->flash('warning', implode("\n", $warnings));
|
||||||
@ -227,7 +212,7 @@ class PageController extends Controller
|
|||||||
$draftsEnabled = $this->signedIn;
|
$draftsEnabled = $this->signedIn;
|
||||||
return view('pages/edit', [
|
return view('pages/edit', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $book,
|
'book' => $page->book,
|
||||||
'current' => $page,
|
'current' => $page,
|
||||||
'draftsEnabled' => $draftsEnabled
|
'draftsEnabled' => $draftsEnabled
|
||||||
]);
|
]);
|
||||||
@ -245,11 +230,10 @@ class PageController extends Controller
|
|||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'name' => 'required|string|max:255'
|
'name' => 'required|string|max:255'
|
||||||
]);
|
]);
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->pageRepo->updatePage($page, $book->id, $request->all());
|
$this->entityRepo->updatePage($page, $page->book->id, $request->all());
|
||||||
Activity::add($page, 'page_update', $book->id);
|
Activity::add($page, 'page_update', $page->book->id);
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +245,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function saveDraft(Request $request, $pageId)
|
public function saveDraft(Request $request, $pageId)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
|
|
||||||
if (!$this->signedIn) {
|
if (!$this->signedIn) {
|
||||||
@ -271,11 +255,7 @@ class PageController extends Controller
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page->draft) {
|
$draft = $this->entityRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown']));
|
||||||
$draft = $this->pageRepo->updateDraftPage($page, $request->only(['name', 'html', 'markdown']));
|
|
||||||
} else {
|
|
||||||
$draft = $this->pageRepo->saveUpdateDraft($page, $request->only(['name', 'html', 'markdown']));
|
|
||||||
}
|
|
||||||
|
|
||||||
$updateTime = $draft->updated_at->timestamp;
|
$updateTime = $draft->updated_at->timestamp;
|
||||||
$utcUpdateTimestamp = $updateTime + Carbon::createFromTimestamp(0)->offset;
|
$utcUpdateTimestamp = $updateTime + Carbon::createFromTimestamp(0)->offset;
|
||||||
@ -294,7 +274,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function redirectFromLink($pageId)
|
public function redirectFromLink($pageId)
|
||||||
{
|
{
|
||||||
$page = $this->pageRepo->getById($pageId);
|
$page = $this->entityRepo->getById('page', $pageId);
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,11 +286,10 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showDelete($bookSlug, $pageSlug)
|
public function showDelete($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-delete', $page);
|
$this->checkOwnablePermission('page-delete', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
|
||||||
return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
|
return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -323,11 +302,10 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showDeleteDraft($bookSlug, $pageId)
|
public function showDeleteDraft($bookSlug, $pageId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
|
||||||
return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
|
return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,12 +317,12 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy($bookSlug, $pageSlug)
|
public function destroy($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
$book = $page->book;
|
||||||
$this->checkOwnablePermission('page-delete', $page);
|
$this->checkOwnablePermission('page-delete', $page);
|
||||||
Activity::addMessage('page_delete', $book->id, $page->name);
|
Activity::addMessage('page_delete', $book->id, $page->name);
|
||||||
session()->flash('success', trans('entities.pages_delete_success'));
|
session()->flash('success', trans('entities.pages_delete_success'));
|
||||||
$this->pageRepo->destroy($page);
|
$this->entityRepo->destroyPage($page);
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,11 +335,11 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroyDraft($bookSlug, $pageId)
|
public function destroyDraft($bookSlug, $pageId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getById('page', $pageId, true);
|
||||||
$page = $this->pageRepo->getById($pageId, true);
|
$book = $page->book;
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
session()->flash('success', trans('entities.pages_delete_draft_success'));
|
session()->flash('success', trans('entities.pages_delete_draft_success'));
|
||||||
$this->pageRepo->destroy($page);
|
$this->entityRepo->destroyPage($page);
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,10 +351,9 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRevisions($bookSlug, $pageSlug)
|
public function showRevisions($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
||||||
return view('pages/revisions', ['page' => $page, 'book' => $book, 'current' => $page]);
|
return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -388,16 +365,15 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRevision($bookSlug, $pageSlug, $revisionId)
|
public function showRevision($bookSlug, $pageSlug, $revisionId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
$revision = $this->entityRepo->getById('page_revision', $revisionId, false);
|
||||||
$revision = $this->pageRepo->getRevisionById($revisionId);
|
|
||||||
|
|
||||||
$page->fill($revision->toArray());
|
$page->fill($revision->toArray());
|
||||||
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
|
||||||
|
|
||||||
return view('pages/revision', [
|
return view('pages/revision', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $book,
|
'book' => $page->book,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,9 +386,8 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRevisionChanges($bookSlug, $pageSlug, $revisionId)
|
public function showRevisionChanges($bookSlug, $pageSlug, $revisionId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
$revision = $this->entityRepo->getById('page_revision', $revisionId);
|
||||||
$revision = $this->pageRepo->getRevisionById($revisionId);
|
|
||||||
|
|
||||||
$prev = $revision->getPrevious();
|
$prev = $revision->getPrevious();
|
||||||
$prevContent = ($prev === null) ? '' : $prev->html;
|
$prevContent = ($prev === null) ? '' : $prev->html;
|
||||||
@ -423,7 +398,7 @@ class PageController extends Controller
|
|||||||
|
|
||||||
return view('pages/revision', [
|
return view('pages/revision', [
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'book' => $book,
|
'book' => $page->book,
|
||||||
'diff' => $diff,
|
'diff' => $diff,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -437,11 +412,10 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
|
public function restoreRevision($bookSlug, $pageSlug, $revisionId)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
$page = $this->pageRepo->restoreRevision($page, $book, $revisionId);
|
$page = $this->entityRepo->restorePageRevision($page, $page->book, $revisionId);
|
||||||
Activity::add($page, 'page_restore', $book->id);
|
Activity::add($page, 'page_restore', $page->book->id);
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,8 +428,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function exportPdf($bookSlug, $pageSlug)
|
public function exportPdf($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$pdfContent = $this->exportService->pageToPdf($page);
|
$pdfContent = $this->exportService->pageToPdf($page);
|
||||||
return response()->make($pdfContent, 200, [
|
return response()->make($pdfContent, 200, [
|
||||||
'Content-Type' => 'application/octet-stream',
|
'Content-Type' => 'application/octet-stream',
|
||||||
@ -471,8 +444,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function exportHtml($bookSlug, $pageSlug)
|
public function exportHtml($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$containedHtml = $this->exportService->pageToContainedHtml($page);
|
$containedHtml = $this->exportService->pageToContainedHtml($page);
|
||||||
return response()->make($containedHtml, 200, [
|
return response()->make($containedHtml, 200, [
|
||||||
'Content-Type' => 'application/octet-stream',
|
'Content-Type' => 'application/octet-stream',
|
||||||
@ -488,8 +460,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function exportPlainText($bookSlug, $pageSlug)
|
public function exportPlainText($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$containedHtml = $this->exportService->pageToPlainText($page);
|
$containedHtml = $this->exportService->pageToPlainText($page);
|
||||||
return response()->make($containedHtml, 200, [
|
return response()->make($containedHtml, 200, [
|
||||||
'Content-Type' => 'application/octet-stream',
|
'Content-Type' => 'application/octet-stream',
|
||||||
@ -503,7 +474,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRecentlyCreated()
|
public function showRecentlyCreated()
|
||||||
{
|
{
|
||||||
$pages = $this->pageRepo->getRecentlyCreatedPaginated(20)->setPath(baseUrl('/pages/recently-created'));
|
$pages = $this->entityRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
|
||||||
return view('pages/detailed-listing', [
|
return view('pages/detailed-listing', [
|
||||||
'title' => trans('entities.recently_created_pages'),
|
'title' => trans('entities.recently_created_pages'),
|
||||||
'pages' => $pages
|
'pages' => $pages
|
||||||
@ -516,7 +487,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRecentlyUpdated()
|
public function showRecentlyUpdated()
|
||||||
{
|
{
|
||||||
$pages = $this->pageRepo->getRecentlyUpdatedPaginated(20)->setPath(baseUrl('/pages/recently-updated'));
|
$pages = $this->entityRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
|
||||||
return view('pages/detailed-listing', [
|
return view('pages/detailed-listing', [
|
||||||
'title' => trans('entities.recently_updated_pages'),
|
'title' => trans('entities.recently_updated_pages'),
|
||||||
'pages' => $pages
|
'pages' => $pages
|
||||||
@ -531,8 +502,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showRestrict($bookSlug, $pageSlug)
|
public function showRestrict($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||||
$roles = $this->userRepo->getRestrictableRoles();
|
$roles = $this->userRepo->getRestrictableRoles();
|
||||||
return view('pages/restrictions', [
|
return view('pages/restrictions', [
|
||||||
@ -550,11 +520,10 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showMove($bookSlug, $pageSlug)
|
public function showMove($bookSlug, $pageSlug)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
return view('pages/move', [
|
return view('pages/move', [
|
||||||
'book' => $book,
|
'book' => $page->book,
|
||||||
'page' => $page
|
'page' => $page
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -569,8 +538,7 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function move($bookSlug, $pageSlug, Request $request)
|
public function move($bookSlug, $pageSlug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('page-update', $page);
|
$this->checkOwnablePermission('page-update', $page);
|
||||||
|
|
||||||
$entitySelection = $request->get('entity_selection', null);
|
$entitySelection = $request->get('entity_selection', null);
|
||||||
@ -582,20 +550,15 @@ class PageController extends Controller
|
|||||||
$entityType = $stringExploded[0];
|
$entityType = $stringExploded[0];
|
||||||
$entityId = intval($stringExploded[1]);
|
$entityId = intval($stringExploded[1]);
|
||||||
|
|
||||||
$parent = false;
|
|
||||||
|
|
||||||
if ($entityType == 'chapter') {
|
try {
|
||||||
$parent = $this->chapterRepo->getById($entityId);
|
$parent = $this->entityRepo->getById($entityType, $entityId);
|
||||||
} else if ($entityType == 'book') {
|
} catch (\Exception $e) {
|
||||||
$parent = $this->bookRepo->getById($entityId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($parent === false || $parent === null) {
|
|
||||||
session()->flash(trans('entities.selected_book_chapter_not_found'));
|
session()->flash(trans('entities.selected_book_chapter_not_found'));
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pageRepo->changePageParent($page, $parent);
|
$this->entityRepo->changePageParent($page, $parent);
|
||||||
Activity::add($page, 'page_move', $page->book->id);
|
Activity::add($page, 'page_move', $page->book->id);
|
||||||
session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name]));
|
session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name]));
|
||||||
|
|
||||||
@ -611,10 +574,9 @@ class PageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function restrict($bookSlug, $pageSlug, Request $request)
|
public function restrict($bookSlug, $pageSlug, Request $request)
|
||||||
{
|
{
|
||||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
|
||||||
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
|
|
||||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||||
$this->pageRepo->updateEntityPermissionsFromRequest($request, $page);
|
$this->entityRepo->updateEntityPermissionsFromRequest($request, $page);
|
||||||
session()->flash('success', trans('entities.pages_permissions_success'));
|
session()->flash('success', trans('entities.pages_permissions_success'));
|
||||||
return redirect($page->getUrl());
|
return redirect($page->getUrl());
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,22 @@
|
|||||||
<?php namespace BookStack\Http\Controllers;
|
<?php namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
|
use BookStack\Repos\EntityRepo;
|
||||||
use BookStack\Services\ViewService;
|
use BookStack\Services\ViewService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use BookStack\Repos\BookRepo;
|
|
||||||
use BookStack\Repos\ChapterRepo;
|
|
||||||
use BookStack\Repos\PageRepo;
|
|
||||||
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
protected $pageRepo;
|
protected $entityRepo;
|
||||||
protected $bookRepo;
|
|
||||||
protected $chapterRepo;
|
|
||||||
protected $viewService;
|
protected $viewService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SearchController constructor.
|
* SearchController constructor.
|
||||||
* @param PageRepo $pageRepo
|
* @param EntityRepo $entityRepo
|
||||||
* @param BookRepo $bookRepo
|
|
||||||
* @param ChapterRepo $chapterRepo
|
|
||||||
* @param ViewService $viewService
|
* @param ViewService $viewService
|
||||||
*/
|
*/
|
||||||
public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ViewService $viewService)
|
public function __construct(EntityRepo $entityRepo, ViewService $viewService)
|
||||||
{
|
{
|
||||||
$this->pageRepo = $pageRepo;
|
$this->entityRepo = $entityRepo;
|
||||||
$this->bookRepo = $bookRepo;
|
|
||||||
$this->chapterRepo = $chapterRepo;
|
|
||||||
$this->viewService = $viewService;
|
$this->viewService = $viewService;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
@ -42,9 +34,9 @@ class SearchController extends Controller
|
|||||||
}
|
}
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$paginationAppends = $request->only('term');
|
$paginationAppends = $request->only('term');
|
||||||
$pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
|
$pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends);
|
||||||
$books = $this->bookRepo->getBySearch($searchTerm, 10, $paginationAppends);
|
$books = $this->entityRepo->getBySearch('book', $searchTerm, [], 10, $paginationAppends);
|
||||||
$chapters = $this->chapterRepo->getBySearch($searchTerm, [], 10, $paginationAppends);
|
$chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 10, $paginationAppends);
|
||||||
$this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm]));
|
$this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm]));
|
||||||
return view('search/all', [
|
return view('search/all', [
|
||||||
'pages' => $pages,
|
'pages' => $pages,
|
||||||
@ -65,7 +57,7 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$paginationAppends = $request->only('term');
|
$paginationAppends = $request->only('term');
|
||||||
$pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
|
$pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends);
|
||||||
$this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm]));
|
$this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm]));
|
||||||
return view('search/entity-search-list', [
|
return view('search/entity-search-list', [
|
||||||
'entities' => $pages,
|
'entities' => $pages,
|
||||||
@ -85,7 +77,7 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$paginationAppends = $request->only('term');
|
$paginationAppends = $request->only('term');
|
||||||
$chapters = $this->chapterRepo->getBySearch($searchTerm, [], 20, $paginationAppends);
|
$chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 20, $paginationAppends);
|
||||||
$this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm]));
|
$this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm]));
|
||||||
return view('search/entity-search-list', [
|
return view('search/entity-search-list', [
|
||||||
'entities' => $chapters,
|
'entities' => $chapters,
|
||||||
@ -105,7 +97,7 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$paginationAppends = $request->only('term');
|
$paginationAppends = $request->only('term');
|
||||||
$books = $this->bookRepo->getBySearch($searchTerm, 20, $paginationAppends);
|
$books = $this->entityRepo->getBySearch('book', $searchTerm, [], 20, $paginationAppends);
|
||||||
$this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm]));
|
$this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm]));
|
||||||
return view('search/entity-search-list', [
|
return view('search/entity-search-list', [
|
||||||
'entities' => $books,
|
'entities' => $books,
|
||||||
@ -128,8 +120,8 @@ class SearchController extends Controller
|
|||||||
}
|
}
|
||||||
$searchTerm = $request->get('term');
|
$searchTerm = $request->get('term');
|
||||||
$searchWhereTerms = [['book_id', '=', $bookId]];
|
$searchWhereTerms = [['book_id', '=', $bookId]];
|
||||||
$pages = $this->pageRepo->getBySearch($searchTerm, $searchWhereTerms);
|
$pages = $this->entityRepo->getBySearch('page', $searchTerm, $searchWhereTerms);
|
||||||
$chapters = $this->chapterRepo->getBySearch($searchTerm, $searchWhereTerms);
|
$chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, $searchWhereTerms);
|
||||||
return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]);
|
return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +140,11 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
// Search for entities otherwise show most popular
|
// Search for entities otherwise show most popular
|
||||||
if ($searchTerm !== false) {
|
if ($searchTerm !== false) {
|
||||||
if ($entityTypes->contains('page')) $entities = $entities->merge($this->pageRepo->getBySearch($searchTerm)->items());
|
foreach (['page', 'chapter', 'book'] as $entityType) {
|
||||||
if ($entityTypes->contains('chapter')) $entities = $entities->merge($this->chapterRepo->getBySearch($searchTerm)->items());
|
if ($entityTypes->contains($entityType)) {
|
||||||
if ($entityTypes->contains('book')) $entities = $entities->merge($this->bookRepo->getBySearch($searchTerm)->items());
|
$entities = $entities->merge($this->entityRepo->getBySearch($entityType, $searchTerm)->items());
|
||||||
|
}
|
||||||
|
}
|
||||||
$entities = $entities->sortByDesc('title_relevance');
|
$entities = $entities->sortByDesc('title_relevance');
|
||||||
} else {
|
} else {
|
||||||
$entityNames = $entityTypes->map(function ($type) {
|
$entityNames = $entityTypes->map(function ($type) {
|
||||||
|
@ -4,8 +4,6 @@ namespace BookStack\Http\Middleware;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Contracts\Auth\Guard;
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
use BookStack\Exceptions\UserRegistrationException;
|
|
||||||
use Setting;
|
|
||||||
|
|
||||||
class Authenticate
|
class Authenticate
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,10 @@ class Page extends Entity
|
|||||||
|
|
||||||
protected $simpleAttributes = ['name', 'id', 'slug'];
|
protected $simpleAttributes = ['name', 'id', 'slug'];
|
||||||
|
|
||||||
|
protected $with = ['book'];
|
||||||
|
|
||||||
|
protected $fieldsToSearch = ['name', 'text'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts this page into a simplified array.
|
* Converts this page into a simplified array.
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
@ -1,295 +0,0 @@
|
|||||||
<?php namespace BookStack\Repos;
|
|
||||||
|
|
||||||
use Alpha\B;
|
|
||||||
use BookStack\Exceptions\NotFoundException;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use BookStack\Book;
|
|
||||||
use Views;
|
|
||||||
|
|
||||||
class BookRepo extends EntityRepo
|
|
||||||
{
|
|
||||||
protected $pageRepo;
|
|
||||||
protected $chapterRepo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BookRepo constructor.
|
|
||||||
* @param PageRepo $pageRepo
|
|
||||||
* @param ChapterRepo $chapterRepo
|
|
||||||
*/
|
|
||||||
public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo)
|
|
||||||
{
|
|
||||||
$this->pageRepo = $pageRepo;
|
|
||||||
$this->chapterRepo = $chapterRepo;
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base query for getting books.
|
|
||||||
* Takes into account any restrictions.
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function bookQuery()
|
|
||||||
{
|
|
||||||
return $this->permissionService->enforceBookRestrictions($this->book, 'view');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the book that has the given id.
|
|
||||||
* @param $id
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getById($id)
|
|
||||||
{
|
|
||||||
return $this->bookQuery()->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all books, Limited by count.
|
|
||||||
* @param int $count
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getAll($count = 10)
|
|
||||||
{
|
|
||||||
$bookQuery = $this->bookQuery()->orderBy('name', 'asc');
|
|
||||||
if (!$count) return $bookQuery->get();
|
|
||||||
return $bookQuery->take($count)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all books paginated.
|
|
||||||
* @param int $count
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getAllPaginated($count = 10)
|
|
||||||
{
|
|
||||||
return $this->bookQuery()
|
|
||||||
->orderBy('name', 'asc')->paginate($count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the latest books.
|
|
||||||
* @param int $count
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getLatest($count = 10)
|
|
||||||
{
|
|
||||||
return $this->bookQuery()->orderBy('created_at', 'desc')->take($count)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the most recently viewed for a user.
|
|
||||||
* @param int $count
|
|
||||||
* @param int $page
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getRecentlyViewed($count = 10, $page = 0)
|
|
||||||
{
|
|
||||||
return Views::getUserRecentlyViewed($count, $page, $this->book);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the most viewed books.
|
|
||||||
* @param int $count
|
|
||||||
* @param int $page
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getPopular($count = 10, $page = 0)
|
|
||||||
{
|
|
||||||
return Views::getPopular($count, $page, $this->book);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a book by slug
|
|
||||||
* @param $slug
|
|
||||||
* @return mixed
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
public function getBySlug($slug)
|
|
||||||
{
|
|
||||||
$book = $this->bookQuery()->where('slug', '=', $slug)->first();
|
|
||||||
if ($book === null) throw new NotFoundException(trans('errors.book_not_found'));
|
|
||||||
return $book;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a book exists.
|
|
||||||
* @param $id
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function exists($id)
|
|
||||||
{
|
|
||||||
return $this->bookQuery()->where('id', '=', $id)->exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new book instance from request input.
|
|
||||||
* @param array $input
|
|
||||||
* @return Book
|
|
||||||
*/
|
|
||||||
public function createFromInput($input)
|
|
||||||
{
|
|
||||||
$book = $this->book->newInstance($input);
|
|
||||||
$book->slug = $this->findSuitableSlug($book->name);
|
|
||||||
$book->created_by = user()->id;
|
|
||||||
$book->updated_by = user()->id;
|
|
||||||
$book->save();
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($book);
|
|
||||||
return $book;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given book from user input.
|
|
||||||
* @param Book $book
|
|
||||||
* @param $input
|
|
||||||
* @return Book
|
|
||||||
*/
|
|
||||||
public function updateFromInput(Book $book, $input)
|
|
||||||
{
|
|
||||||
if ($book->name !== $input['name']) {
|
|
||||||
$book->slug = $this->findSuitableSlug($input['name'], $book->id);
|
|
||||||
}
|
|
||||||
$book->fill($input);
|
|
||||||
$book->updated_by = user()->id;
|
|
||||||
$book->save();
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($book);
|
|
||||||
return $book;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy the given book.
|
|
||||||
* @param Book $book
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function destroy(Book $book)
|
|
||||||
{
|
|
||||||
foreach ($book->pages as $page) {
|
|
||||||
$this->pageRepo->destroy($page);
|
|
||||||
}
|
|
||||||
foreach ($book->chapters as $chapter) {
|
|
||||||
$this->chapterRepo->destroy($chapter);
|
|
||||||
}
|
|
||||||
$book->views()->delete();
|
|
||||||
$book->permissions()->delete();
|
|
||||||
$this->permissionService->deleteJointPermissionsForEntity($book);
|
|
||||||
$book->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the next child element priority.
|
|
||||||
* @param Book $book
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getNewPriority($book)
|
|
||||||
{
|
|
||||||
$lastElem = $this->getChildren($book)->pop();
|
|
||||||
return $lastElem ? $lastElem->priority + 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $slug
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function doesSlugExist($slug, $currentId = false)
|
|
||||||
{
|
|
||||||
$query = $this->book->where('slug', '=', $slug);
|
|
||||||
if ($currentId) {
|
|
||||||
$query = $query->where('id', '!=', $currentId);
|
|
||||||
}
|
|
||||||
return $query->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a suitable slug for the given book name.
|
|
||||||
* Ensures the returned slug is unique in the system.
|
|
||||||
* @param string $name
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function findSuitableSlug($name, $currentId = false)
|
|
||||||
{
|
|
||||||
$slug = $this->nameToSlug($name);
|
|
||||||
while ($this->doesSlugExist($slug, $currentId)) {
|
|
||||||
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
|
|
||||||
}
|
|
||||||
return $slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all child objects of a book.
|
|
||||||
* Returns a sorted collection of Pages and Chapters.
|
|
||||||
* Loads the book slug onto child elements to prevent access database access for getting the slug.
|
|
||||||
* @param Book $book
|
|
||||||
* @param bool $filterDrafts
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getChildren(Book $book, $filterDrafts = false)
|
|
||||||
{
|
|
||||||
$pageQuery = $book->pages()->where('chapter_id', '=', 0);
|
|
||||||
$pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view');
|
|
||||||
|
|
||||||
if ($filterDrafts) {
|
|
||||||
$pageQuery = $pageQuery->where('draft', '=', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$pages = $pageQuery->get();
|
|
||||||
|
|
||||||
$chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) {
|
|
||||||
$this->permissionService->enforcePageRestrictions($query, 'view');
|
|
||||||
if ($filterDrafts) $query->where('draft', '=', false);
|
|
||||||
}]);
|
|
||||||
$chapterQuery = $this->permissionService->enforceChapterRestrictions($chapterQuery, 'view');
|
|
||||||
$chapters = $chapterQuery->get();
|
|
||||||
$children = $pages->values();
|
|
||||||
foreach ($chapters as $chapter) {
|
|
||||||
$children->push($chapter);
|
|
||||||
}
|
|
||||||
$bookSlug = $book->slug;
|
|
||||||
|
|
||||||
$children->each(function ($child) use ($bookSlug) {
|
|
||||||
$child->setAttribute('bookSlug', $bookSlug);
|
|
||||||
if ($child->isA('chapter')) {
|
|
||||||
$child->pages->each(function ($page) use ($bookSlug) {
|
|
||||||
$page->setAttribute('bookSlug', $bookSlug);
|
|
||||||
});
|
|
||||||
$child->pages = $child->pages->sortBy(function ($child, $key) {
|
|
||||||
$score = $child->priority;
|
|
||||||
if ($child->draft) $score -= 100;
|
|
||||||
return $score;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort items with drafts first then by priority.
|
|
||||||
return $children->sortBy(function ($child, $key) {
|
|
||||||
$score = $child->priority;
|
|
||||||
if ($child->isA('page') && $child->draft) $score -= 100;
|
|
||||||
return $score;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get books by search term.
|
|
||||||
* @param $term
|
|
||||||
* @param int $count
|
|
||||||
* @param array $paginationAppends
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getBySearch($term, $count = 20, $paginationAppends = [])
|
|
||||||
{
|
|
||||||
$terms = $this->prepareSearchTerms($term);
|
|
||||||
$bookQuery = $this->permissionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms));
|
|
||||||
$bookQuery = $this->addAdvancedSearchQueries($bookQuery, $term);
|
|
||||||
$books = $bookQuery->paginate($count)->appends($paginationAppends);
|
|
||||||
$words = join('|', explode(' ', preg_quote(trim($term), '/')));
|
|
||||||
foreach ($books as $book) {
|
|
||||||
//highlight
|
|
||||||
$result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $book->getExcerpt(100));
|
|
||||||
$book->searchSnippet = $result;
|
|
||||||
}
|
|
||||||
return $books;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,226 +0,0 @@
|
|||||||
<?php namespace BookStack\Repos;
|
|
||||||
|
|
||||||
|
|
||||||
use Activity;
|
|
||||||
use BookStack\Book;
|
|
||||||
use BookStack\Exceptions\NotFoundException;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use BookStack\Chapter;
|
|
||||||
|
|
||||||
class ChapterRepo extends EntityRepo
|
|
||||||
{
|
|
||||||
protected $pageRepo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ChapterRepo constructor.
|
|
||||||
* @param $pageRepo
|
|
||||||
*/
|
|
||||||
public function __construct(PageRepo $pageRepo)
|
|
||||||
{
|
|
||||||
$this->pageRepo = $pageRepo;
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base query for getting chapters, Takes permissions into account.
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function chapterQuery()
|
|
||||||
{
|
|
||||||
return $this->permissionService->enforceChapterRestrictions($this->chapter, 'view');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an id exists.
|
|
||||||
* @param $id
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function idExists($id)
|
|
||||||
{
|
|
||||||
return $this->chapterQuery()->where('id', '=', $id)->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a chapter by a specific id.
|
|
||||||
* @param $id
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getById($id)
|
|
||||||
{
|
|
||||||
return $this->chapterQuery()->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all chapters.
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection|static[]
|
|
||||||
*/
|
|
||||||
public function getAll()
|
|
||||||
{
|
|
||||||
return $this->chapterQuery()->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a chapter that has the given slug within the given book.
|
|
||||||
* @param $slug
|
|
||||||
* @param $bookId
|
|
||||||
* @return mixed
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
public function getBySlug($slug, $bookId)
|
|
||||||
{
|
|
||||||
$chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
|
|
||||||
if ($chapter === null) throw new NotFoundException(trans('errors.chapter_not_found'));
|
|
||||||
return $chapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the child items for a chapter
|
|
||||||
* @param Chapter $chapter
|
|
||||||
*/
|
|
||||||
public function getChildren(Chapter $chapter)
|
|
||||||
{
|
|
||||||
$pages = $this->permissionService->enforcePageRestrictions($chapter->pages())->get();
|
|
||||||
// Sort items with drafts first then by priority.
|
|
||||||
return $pages->sortBy(function ($child, $key) {
|
|
||||||
$score = $child->priority;
|
|
||||||
if ($child->draft) $score -= 100;
|
|
||||||
return $score;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new chapter from request input.
|
|
||||||
* @param $input
|
|
||||||
* @param Book $book
|
|
||||||
* @return Chapter
|
|
||||||
*/
|
|
||||||
public function createFromInput($input, Book $book)
|
|
||||||
{
|
|
||||||
$chapter = $this->chapter->newInstance($input);
|
|
||||||
$chapter->slug = $this->findSuitableSlug($chapter->name, $book->id);
|
|
||||||
$chapter->created_by = user()->id;
|
|
||||||
$chapter->updated_by = user()->id;
|
|
||||||
$chapter = $book->chapters()->save($chapter);
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($chapter);
|
|
||||||
return $chapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy a chapter and its relations by providing its slug.
|
|
||||||
* @param Chapter $chapter
|
|
||||||
*/
|
|
||||||
public function destroy(Chapter $chapter)
|
|
||||||
{
|
|
||||||
if (count($chapter->pages) > 0) {
|
|
||||||
foreach ($chapter->pages as $page) {
|
|
||||||
$page->chapter_id = 0;
|
|
||||||
$page->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Activity::removeEntity($chapter);
|
|
||||||
$chapter->views()->delete();
|
|
||||||
$chapter->permissions()->delete();
|
|
||||||
$this->permissionService->deleteJointPermissionsForEntity($chapter);
|
|
||||||
$chapter->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a chapter's slug exists.
|
|
||||||
* @param $slug
|
|
||||||
* @param $bookId
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function doesSlugExist($slug, $bookId, $currentId = false)
|
|
||||||
{
|
|
||||||
$query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
|
|
||||||
if ($currentId) {
|
|
||||||
$query = $query->where('id', '!=', $currentId);
|
|
||||||
}
|
|
||||||
return $query->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds a suitable slug for the provided name.
|
|
||||||
* Checks database to prevent duplicate slugs.
|
|
||||||
* @param $name
|
|
||||||
* @param $bookId
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function findSuitableSlug($name, $bookId, $currentId = false)
|
|
||||||
{
|
|
||||||
$slug = $this->nameToSlug($name);
|
|
||||||
while ($this->doesSlugExist($slug, $bookId, $currentId)) {
|
|
||||||
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
|
|
||||||
}
|
|
||||||
return $slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new priority value for a new page to be added
|
|
||||||
* to the given chapter.
|
|
||||||
* @param Chapter $chapter
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getNewPriority(Chapter $chapter)
|
|
||||||
{
|
|
||||||
$lastPage = $chapter->pages->last();
|
|
||||||
return $lastPage !== null ? $lastPage->priority + 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get chapters by the given search term.
|
|
||||||
* @param string $term
|
|
||||||
* @param array $whereTerms
|
|
||||||
* @param int $count
|
|
||||||
* @param array $paginationAppends
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
|
|
||||||
{
|
|
||||||
$terms = $this->prepareSearchTerms($term);
|
|
||||||
$chapterQuery = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms));
|
|
||||||
$chapterQuery = $this->addAdvancedSearchQueries($chapterQuery, $term);
|
|
||||||
$chapters = $chapterQuery->paginate($count)->appends($paginationAppends);
|
|
||||||
$words = join('|', explode(' ', preg_quote(trim($term), '/')));
|
|
||||||
foreach ($chapters as $chapter) {
|
|
||||||
//highlight
|
|
||||||
$result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100));
|
|
||||||
$chapter->searchSnippet = $result;
|
|
||||||
}
|
|
||||||
return $chapters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the book relation of this chapter.
|
|
||||||
* @param $bookId
|
|
||||||
* @param Chapter $chapter
|
|
||||||
* @param bool $rebuildPermissions
|
|
||||||
* @return Chapter
|
|
||||||
*/
|
|
||||||
public function changeBook($bookId, Chapter $chapter, $rebuildPermissions = false)
|
|
||||||
{
|
|
||||||
$chapter->book_id = $bookId;
|
|
||||||
// Update related activity
|
|
||||||
foreach ($chapter->activity as $activity) {
|
|
||||||
$activity->book_id = $bookId;
|
|
||||||
$activity->save();
|
|
||||||
}
|
|
||||||
$chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id);
|
|
||||||
$chapter->save();
|
|
||||||
// Update all child pages
|
|
||||||
foreach ($chapter->pages as $page) {
|
|
||||||
$this->pageRepo->changeBook($bookId, $page);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update permissions if applicable
|
|
||||||
if ($rebuildPermissions) {
|
|
||||||
$chapter->load('book');
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($chapter->book);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $chapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,664 +0,0 @@
|
|||||||
<?php namespace BookStack\Repos;
|
|
||||||
|
|
||||||
use Activity;
|
|
||||||
use BookStack\Book;
|
|
||||||
use BookStack\Chapter;
|
|
||||||
use BookStack\Entity;
|
|
||||||
use BookStack\Exceptions\NotFoundException;
|
|
||||||
use BookStack\Services\AttachmentService;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use DOMDocument;
|
|
||||||
use DOMXPath;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use BookStack\Page;
|
|
||||||
use BookStack\PageRevision;
|
|
||||||
|
|
||||||
class PageRepo extends EntityRepo
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $pageRevision;
|
|
||||||
protected $tagRepo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PageRepo constructor.
|
|
||||||
* @param PageRevision $pageRevision
|
|
||||||
* @param TagRepo $tagRepo
|
|
||||||
*/
|
|
||||||
public function __construct(PageRevision $pageRevision, TagRepo $tagRepo)
|
|
||||||
{
|
|
||||||
$this->pageRevision = $pageRevision;
|
|
||||||
$this->tagRepo = $tagRepo;
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base query for getting pages, Takes restrictions into account.
|
|
||||||
* @param bool $allowDrafts
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function pageQuery($allowDrafts = false)
|
|
||||||
{
|
|
||||||
$query = $this->permissionService->enforcePageRestrictions($this->page, 'view');
|
|
||||||
if (!$allowDrafts) {
|
|
||||||
$query = $query->where('draft', '=', false);
|
|
||||||
}
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a page via a specific ID.
|
|
||||||
* @param $id
|
|
||||||
* @param bool $allowDrafts
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function getById($id, $allowDrafts = false)
|
|
||||||
{
|
|
||||||
return $this->pageQuery($allowDrafts)->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a page identified by the given slug.
|
|
||||||
* @param $slug
|
|
||||||
* @param $bookId
|
|
||||||
* @return Page
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
public function getBySlug($slug, $bookId)
|
|
||||||
{
|
|
||||||
$page = $this->pageQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
|
|
||||||
if ($page === null) throw new NotFoundException(trans('errors.page_not_found'));
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search through page revisions and retrieve
|
|
||||||
* the last page in the current book that
|
|
||||||
* has a slug equal to the one given.
|
|
||||||
* @param $pageSlug
|
|
||||||
* @param $bookSlug
|
|
||||||
* @return null | Page
|
|
||||||
*/
|
|
||||||
public function findPageUsingOldSlug($pageSlug, $bookSlug)
|
|
||||||
{
|
|
||||||
$revision = $this->pageRevision->where('slug', '=', $pageSlug)
|
|
||||||
->whereHas('page', function ($query) {
|
|
||||||
$this->permissionService->enforcePageRestrictions($query);
|
|
||||||
})
|
|
||||||
->where('type', '=', 'version')
|
|
||||||
->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
|
|
||||||
->with('page')->first();
|
|
||||||
return $revision !== null ? $revision->page : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new Page instance from the given input.
|
|
||||||
* @param $input
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function newFromInput($input)
|
|
||||||
{
|
|
||||||
$page = $this->page->fill($input);
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the pages with a particular slug within a book.
|
|
||||||
* @param $slug
|
|
||||||
* @param $bookId
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function countBySlug($slug, $bookId)
|
|
||||||
{
|
|
||||||
return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish a draft page to make it a normal page.
|
|
||||||
* Sets the slug and updates the content.
|
|
||||||
* @param Page $draftPage
|
|
||||||
* @param array $input
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function publishDraft(Page $draftPage, array $input)
|
|
||||||
{
|
|
||||||
$draftPage->fill($input);
|
|
||||||
|
|
||||||
// Save page tags if present
|
|
||||||
if (isset($input['tags'])) {
|
|
||||||
$this->tagRepo->saveTagsToEntity($draftPage, $input['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$draftPage->slug = $this->findSuitableSlug($draftPage->name, $draftPage->book->id);
|
|
||||||
$draftPage->html = $this->formatHtml($input['html']);
|
|
||||||
$draftPage->text = strip_tags($draftPage->html);
|
|
||||||
$draftPage->draft = false;
|
|
||||||
|
|
||||||
$draftPage->save();
|
|
||||||
$this->saveRevision($draftPage, trans('entities.pages_initial_revision'));
|
|
||||||
|
|
||||||
return $draftPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new draft page instance.
|
|
||||||
* @param Book $book
|
|
||||||
* @param Chapter|bool $chapter
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function getDraftPage(Book $book, $chapter = false)
|
|
||||||
{
|
|
||||||
$page = $this->page->newInstance();
|
|
||||||
$page->name = trans('entities.pages_initial_name');
|
|
||||||
$page->created_by = user()->id;
|
|
||||||
$page->updated_by = user()->id;
|
|
||||||
$page->draft = true;
|
|
||||||
|
|
||||||
if ($chapter) $page->chapter_id = $chapter->id;
|
|
||||||
|
|
||||||
$book->pages()->save($page);
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($page);
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse te headers on the page to get a navigation menu
|
|
||||||
* @param Page $page
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getPageNav(Page $page)
|
|
||||||
{
|
|
||||||
if ($page->html == '') return null;
|
|
||||||
libxml_use_internal_errors(true);
|
|
||||||
$doc = new DOMDocument();
|
|
||||||
$doc->loadHTML(mb_convert_encoding($page->html, 'HTML-ENTITIES', 'UTF-8'));
|
|
||||||
$xPath = new DOMXPath($doc);
|
|
||||||
$headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6");
|
|
||||||
|
|
||||||
if (is_null($headers)) return null;
|
|
||||||
|
|
||||||
$tree = [];
|
|
||||||
foreach ($headers as $header) {
|
|
||||||
$text = $header->nodeValue;
|
|
||||||
$tree[] = [
|
|
||||||
'nodeName' => strtolower($header->nodeName),
|
|
||||||
'level' => intval(str_replace('h', '', $header->nodeName)),
|
|
||||||
'link' => '#' . $header->getAttribute('id'),
|
|
||||||
'text' => strlen($text) > 30 ? substr($text, 0, 27) . '...' : $text
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return $tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a page's html to be tagged correctly
|
|
||||||
* within the system.
|
|
||||||
* @param string $htmlText
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function formatHtml($htmlText)
|
|
||||||
{
|
|
||||||
if ($htmlText == '') return $htmlText;
|
|
||||||
libxml_use_internal_errors(true);
|
|
||||||
$doc = new DOMDocument();
|
|
||||||
$doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
|
|
||||||
|
|
||||||
$container = $doc->documentElement;
|
|
||||||
$body = $container->childNodes->item(0);
|
|
||||||
$childNodes = $body->childNodes;
|
|
||||||
|
|
||||||
// Ensure no duplicate ids are used
|
|
||||||
$idArray = [];
|
|
||||||
|
|
||||||
foreach ($childNodes as $index => $childNode) {
|
|
||||||
/** @var \DOMElement $childNode */
|
|
||||||
if (get_class($childNode) !== 'DOMElement') continue;
|
|
||||||
|
|
||||||
// Overwrite id if not a BookStack custom id
|
|
||||||
if ($childNode->hasAttribute('id')) {
|
|
||||||
$id = $childNode->getAttribute('id');
|
|
||||||
if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
|
|
||||||
$idArray[] = $id;
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an unique id for the element
|
|
||||||
// Uses the content as a basis to ensure output is the same every time
|
|
||||||
// the same content is passed through.
|
|
||||||
$contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20);
|
|
||||||
$newId = urlencode($contentId);
|
|
||||||
$loopIndex = 0;
|
|
||||||
while (in_array($newId, $idArray)) {
|
|
||||||
$newId = urlencode($contentId . '-' . $loopIndex);
|
|
||||||
$loopIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$childNode->setAttribute('id', $newId);
|
|
||||||
$idArray[] = $newId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate inner html as a string
|
|
||||||
$html = '';
|
|
||||||
foreach ($childNodes as $childNode) {
|
|
||||||
$html .= $doc->saveHTML($childNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets pages by a search term.
|
|
||||||
* Highlights page content for showing in results.
|
|
||||||
* @param string $term
|
|
||||||
* @param array $whereTerms
|
|
||||||
* @param int $count
|
|
||||||
* @param array $paginationAppends
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
|
|
||||||
{
|
|
||||||
$terms = $this->prepareSearchTerms($term);
|
|
||||||
$pageQuery = $this->permissionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms));
|
|
||||||
$pageQuery = $this->addAdvancedSearchQueries($pageQuery, $term);
|
|
||||||
$pages = $pageQuery->paginate($count)->appends($paginationAppends);
|
|
||||||
|
|
||||||
// Add highlights to page text.
|
|
||||||
$words = join('|', explode(' ', preg_quote(trim($term), '/')));
|
|
||||||
//lookahead/behind assertions ensures cut between words
|
|
||||||
$s = '\s\x00-/:-@\[-`{-~'; //character set for start/end of words
|
|
||||||
|
|
||||||
foreach ($pages as $page) {
|
|
||||||
preg_match_all('#(?<=[' . $s . ']).{1,30}((' . $words . ').{1,30})+(?=[' . $s . '])#uis', $page->text, $matches, PREG_SET_ORDER);
|
|
||||||
//delimiter between occurrences
|
|
||||||
$results = [];
|
|
||||||
foreach ($matches as $line) {
|
|
||||||
$results[] = htmlspecialchars($line[0], 0, 'UTF-8');
|
|
||||||
}
|
|
||||||
$matchLimit = 6;
|
|
||||||
if (count($results) > $matchLimit) {
|
|
||||||
$results = array_slice($results, 0, $matchLimit);
|
|
||||||
}
|
|
||||||
$result = join('... ', $results);
|
|
||||||
|
|
||||||
//highlight
|
|
||||||
$result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $result);
|
|
||||||
if (strlen($result) < 5) {
|
|
||||||
$result = $page->getExcerpt(80);
|
|
||||||
}
|
|
||||||
$page->searchSnippet = $result;
|
|
||||||
}
|
|
||||||
return $pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for image usage.
|
|
||||||
* @param $imageString
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function searchForImage($imageString)
|
|
||||||
{
|
|
||||||
$pages = $this->pageQuery()->where('html', 'like', '%' . $imageString . '%')->get();
|
|
||||||
foreach ($pages as $page) {
|
|
||||||
$page->url = $page->getUrl();
|
|
||||||
$page->html = '';
|
|
||||||
$page->text = '';
|
|
||||||
}
|
|
||||||
return count($pages) > 0 ? $pages : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a page with any fillable data and saves it into the database.
|
|
||||||
* @param Page $page
|
|
||||||
* @param int $book_id
|
|
||||||
* @param string $input
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function updatePage(Page $page, $book_id, $input)
|
|
||||||
{
|
|
||||||
// Hold the old details to compare later
|
|
||||||
$oldHtml = $page->html;
|
|
||||||
$oldName = $page->name;
|
|
||||||
|
|
||||||
// Prevent slug being updated if no name change
|
|
||||||
if ($page->name !== $input['name']) {
|
|
||||||
$page->slug = $this->findSuitableSlug($input['name'], $book_id, $page->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save page tags if present
|
|
||||||
if (isset($input['tags'])) {
|
|
||||||
$this->tagRepo->saveTagsToEntity($page, $input['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update with new details
|
|
||||||
$userId = user()->id;
|
|
||||||
$page->fill($input);
|
|
||||||
$page->html = $this->formatHtml($input['html']);
|
|
||||||
$page->text = strip_tags($page->html);
|
|
||||||
if (setting('app-editor') !== 'markdown') $page->markdown = '';
|
|
||||||
$page->updated_by = $userId;
|
|
||||||
$page->save();
|
|
||||||
|
|
||||||
// Remove all update drafts for this user & page.
|
|
||||||
$this->userUpdateDraftsQuery($page, $userId)->delete();
|
|
||||||
|
|
||||||
// Save a revision after updating
|
|
||||||
if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $input['summary'] !== null) {
|
|
||||||
$this->saveRevision($page, $input['summary']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restores a revision's content back into a page.
|
|
||||||
* @param Page $page
|
|
||||||
* @param Book $book
|
|
||||||
* @param int $revisionId
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function restoreRevision(Page $page, Book $book, $revisionId)
|
|
||||||
{
|
|
||||||
$this->saveRevision($page);
|
|
||||||
$revision = $this->getRevisionById($revisionId);
|
|
||||||
$page->fill($revision->toArray());
|
|
||||||
$page->slug = $this->findSuitableSlug($page->name, $book->id, $page->id);
|
|
||||||
$page->text = strip_tags($page->html);
|
|
||||||
$page->updated_by = user()->id;
|
|
||||||
$page->save();
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves a page revision into the system.
|
|
||||||
* @param Page $page
|
|
||||||
* @param null|string $summary
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function saveRevision(Page $page, $summary = null)
|
|
||||||
{
|
|
||||||
$revision = $this->pageRevision->newInstance($page->toArray());
|
|
||||||
if (setting('app-editor') !== 'markdown') $revision->markdown = '';
|
|
||||||
$revision->page_id = $page->id;
|
|
||||||
$revision->slug = $page->slug;
|
|
||||||
$revision->book_slug = $page->book->slug;
|
|
||||||
$revision->created_by = user()->id;
|
|
||||||
$revision->created_at = $page->updated_at;
|
|
||||||
$revision->type = 'version';
|
|
||||||
$revision->summary = $summary;
|
|
||||||
$revision->save();
|
|
||||||
|
|
||||||
// Clear old revisions
|
|
||||||
if ($this->pageRevision->where('page_id', '=', $page->id)->count() > 50) {
|
|
||||||
$this->pageRevision->where('page_id', '=', $page->id)
|
|
||||||
->orderBy('created_at', 'desc')->skip(50)->take(5)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $revision;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save a page update draft.
|
|
||||||
* @param Page $page
|
|
||||||
* @param array $data
|
|
||||||
* @return PageRevision
|
|
||||||
*/
|
|
||||||
public function saveUpdateDraft(Page $page, $data = [])
|
|
||||||
{
|
|
||||||
$userId = user()->id;
|
|
||||||
$drafts = $this->userUpdateDraftsQuery($page, $userId)->get();
|
|
||||||
|
|
||||||
if ($drafts->count() > 0) {
|
|
||||||
$draft = $drafts->first();
|
|
||||||
} else {
|
|
||||||
$draft = $this->pageRevision->newInstance();
|
|
||||||
$draft->page_id = $page->id;
|
|
||||||
$draft->slug = $page->slug;
|
|
||||||
$draft->book_slug = $page->book->slug;
|
|
||||||
$draft->created_by = $userId;
|
|
||||||
$draft->type = 'update_draft';
|
|
||||||
}
|
|
||||||
|
|
||||||
$draft->fill($data);
|
|
||||||
if (setting('app-editor') !== 'markdown') $draft->markdown = '';
|
|
||||||
|
|
||||||
$draft->save();
|
|
||||||
return $draft;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a draft page.
|
|
||||||
* @param Page $page
|
|
||||||
* @param array $data
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function updateDraftPage(Page $page, $data = [])
|
|
||||||
{
|
|
||||||
$page->fill($data);
|
|
||||||
|
|
||||||
if (isset($data['html'])) {
|
|
||||||
$page->text = strip_tags($data['html']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$page->save();
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base query for getting user update drafts.
|
|
||||||
* @param Page $page
|
|
||||||
* @param $userId
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function userUpdateDraftsQuery(Page $page, $userId)
|
|
||||||
{
|
|
||||||
return $this->pageRevision->where('created_by', '=', $userId)
|
|
||||||
->where('type', 'update_draft')
|
|
||||||
->where('page_id', '=', $page->id)
|
|
||||||
->orderBy('created_at', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a user has a draft version of a particular page or not.
|
|
||||||
* @param Page $page
|
|
||||||
* @param $userId
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasUserGotPageDraft(Page $page, $userId)
|
|
||||||
{
|
|
||||||
return $this->userUpdateDraftsQuery($page, $userId)->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the latest updated draft revision for a particular page and user.
|
|
||||||
* @param Page $page
|
|
||||||
* @param $userId
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getUserPageDraft(Page $page, $userId)
|
|
||||||
{
|
|
||||||
return $this->userUpdateDraftsQuery($page, $userId)->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the notification message that informs the user that they are editing a draft page.
|
|
||||||
* @param PageRevision $draft
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getUserPageDraftMessage(PageRevision $draft)
|
|
||||||
{
|
|
||||||
$message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]);
|
|
||||||
if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) return $message;
|
|
||||||
return $message . "\n" . trans('entities.pages_draft_edited_notification');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a page is being actively editing.
|
|
||||||
* Checks for edits since last page updated.
|
|
||||||
* Passing in a minuted range will check for edits
|
|
||||||
* within the last x minutes.
|
|
||||||
* @param Page $page
|
|
||||||
* @param null $minRange
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isPageEditingActive(Page $page, $minRange = null)
|
|
||||||
{
|
|
||||||
$draftSearch = $this->activePageEditingQuery($page, $minRange);
|
|
||||||
return $draftSearch->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a notification message concerning the editing activity on
|
|
||||||
* a particular page.
|
|
||||||
* @param Page $page
|
|
||||||
* @param null $minRange
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPageEditingActiveMessage(Page $page, $minRange = null)
|
|
||||||
{
|
|
||||||
$pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get();
|
|
||||||
|
|
||||||
$userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]);
|
|
||||||
$timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]);
|
|
||||||
return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A query to check for active update drafts on a particular page.
|
|
||||||
* @param Page $page
|
|
||||||
* @param null $minRange
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function activePageEditingQuery(Page $page, $minRange = null)
|
|
||||||
{
|
|
||||||
$query = $this->pageRevision->where('type', '=', 'update_draft')
|
|
||||||
->where('page_id', '=', $page->id)
|
|
||||||
->where('updated_at', '>', $page->updated_at)
|
|
||||||
->where('created_by', '!=', user()->id)
|
|
||||||
->with('createdBy');
|
|
||||||
|
|
||||||
if ($minRange !== null) {
|
|
||||||
$query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a single revision via it's id.
|
|
||||||
* @param $id
|
|
||||||
* @return PageRevision
|
|
||||||
*/
|
|
||||||
public function getRevisionById($id)
|
|
||||||
{
|
|
||||||
return $this->pageRevision->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a slug exists within a book already.
|
|
||||||
* @param $slug
|
|
||||||
* @param $bookId
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function doesSlugExist($slug, $bookId, $currentId = false)
|
|
||||||
{
|
|
||||||
$query = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId);
|
|
||||||
if ($currentId) $query = $query->where('id', '!=', $currentId);
|
|
||||||
return $query->count() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the related book for the specified page.
|
|
||||||
* Changes the book id of any relations to the page that store the book id.
|
|
||||||
* @param int $bookId
|
|
||||||
* @param Page $page
|
|
||||||
* @return Page
|
|
||||||
*/
|
|
||||||
public function changeBook($bookId, Page $page)
|
|
||||||
{
|
|
||||||
$page->book_id = $bookId;
|
|
||||||
foreach ($page->activity as $activity) {
|
|
||||||
$activity->book_id = $bookId;
|
|
||||||
$activity->save();
|
|
||||||
}
|
|
||||||
$page->slug = $this->findSuitableSlug($page->name, $bookId, $page->id);
|
|
||||||
$page->save();
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the page's parent to the given entity.
|
|
||||||
* @param Page $page
|
|
||||||
* @param Entity $parent
|
|
||||||
*/
|
|
||||||
public function changePageParent(Page $page, Entity $parent)
|
|
||||||
{
|
|
||||||
$book = $parent->isA('book') ? $parent : $parent->book;
|
|
||||||
$page->chapter_id = $parent->isA('chapter') ? $parent->id : 0;
|
|
||||||
$page->save();
|
|
||||||
$page = $this->changeBook($book->id, $page);
|
|
||||||
$page->load('book');
|
|
||||||
$this->permissionService->buildJointPermissionsForEntity($book);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a suitable slug for the resource
|
|
||||||
* @param string $name
|
|
||||||
* @param int $bookId
|
|
||||||
* @param bool|false $currentId
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function findSuitableSlug($name, $bookId, $currentId = false)
|
|
||||||
{
|
|
||||||
$slug = $this->nameToSlug($name);
|
|
||||||
while ($this->doesSlugExist($slug, $bookId, $currentId)) {
|
|
||||||
$slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
|
|
||||||
}
|
|
||||||
return $slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy a given page along with its dependencies.
|
|
||||||
* @param $page
|
|
||||||
*/
|
|
||||||
public function destroy(Page $page)
|
|
||||||
{
|
|
||||||
Activity::removeEntity($page);
|
|
||||||
$page->views()->delete();
|
|
||||||
$page->tags()->delete();
|
|
||||||
$page->revisions()->delete();
|
|
||||||
$page->permissions()->delete();
|
|
||||||
$this->permissionService->deleteJointPermissionsForEntity($page);
|
|
||||||
|
|
||||||
// Delete AttachedFiles
|
|
||||||
$attachmentService = app(AttachmentService::class);
|
|
||||||
foreach ($page->attachments as $attachment) {
|
|
||||||
$attachmentService->deleteFile($attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
$page->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the latest pages added to the system.
|
|
||||||
* @param $count
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getRecentlyCreatedPaginated($count = 20)
|
|
||||||
{
|
|
||||||
return $this->pageQuery()->orderBy('created_at', 'desc')->paginate($count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the latest pages added to the system.
|
|
||||||
* @param $count
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getRecentlyUpdatedPaginated($count = 20)
|
|
||||||
{
|
|
||||||
return $this->pageQuery()->orderBy('updated_at', 'desc')->paginate($count);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -38,7 +38,7 @@ class TagRepo
|
|||||||
{
|
{
|
||||||
$entityInstance = $this->entity->getEntityInstance($entityType);
|
$entityInstance = $this->entity->getEntityInstance($entityType);
|
||||||
$searchQuery = $entityInstance->where('id', '=', $entityId)->with('tags');
|
$searchQuery = $entityInstance->where('id', '=', $entityId)->with('tags');
|
||||||
$searchQuery = $this->permissionService->enforceEntityRestrictions($searchQuery, $action);
|
$searchQuery = $this->permissionService->enforceEntityRestrictions($entityType, $searchQuery, $action);
|
||||||
return $searchQuery->first();
|
return $searchQuery->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,13 +168,13 @@ class UserRepo
|
|||||||
public function getRecentlyCreated(User $user, $count = 20)
|
public function getRecentlyCreated(User $user, $count = 20)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'pages' => $this->entityRepo->getRecentlyCreatedPages($count, 0, function ($query) use ($user) {
|
'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) {
|
||||||
$query->where('created_by', '=', $user->id);
|
$query->where('created_by', '=', $user->id);
|
||||||
}),
|
}),
|
||||||
'chapters' => $this->entityRepo->getRecentlyCreatedChapters($count, 0, function ($query) use ($user) {
|
'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) {
|
||||||
$query->where('created_by', '=', $user->id);
|
$query->where('created_by', '=', $user->id);
|
||||||
}),
|
}),
|
||||||
'books' => $this->entityRepo->getRecentlyCreatedBooks($count, 0, function ($query) use ($user) {
|
'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) {
|
||||||
$query->where('created_by', '=', $user->id);
|
$query->where('created_by', '=', $user->id);
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
@ -114,7 +114,7 @@ class ActivityService
|
|||||||
|
|
||||||
$activity = $this->permissionService
|
$activity = $this->permissionService
|
||||||
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
||||||
->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get();
|
->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get();
|
||||||
|
|
||||||
return $this->filterSimilar($activity);
|
return $this->filterSimilar($activity);
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ use BookStack\Ownable;
|
|||||||
use BookStack\Page;
|
use BookStack\Page;
|
||||||
use BookStack\Role;
|
use BookStack\Role;
|
||||||
use BookStack\User;
|
use BookStack\User;
|
||||||
|
use Illuminate\Database\Connection;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class PermissionService
|
class PermissionService
|
||||||
{
|
{
|
||||||
@ -23,6 +24,8 @@ class PermissionService
|
|||||||
public $chapter;
|
public $chapter;
|
||||||
public $page;
|
public $page;
|
||||||
|
|
||||||
|
protected $db;
|
||||||
|
|
||||||
protected $jointPermission;
|
protected $jointPermission;
|
||||||
protected $role;
|
protected $role;
|
||||||
|
|
||||||
@ -31,18 +34,21 @@ class PermissionService
|
|||||||
/**
|
/**
|
||||||
* PermissionService constructor.
|
* PermissionService constructor.
|
||||||
* @param JointPermission $jointPermission
|
* @param JointPermission $jointPermission
|
||||||
|
* @param Connection $db
|
||||||
* @param Book $book
|
* @param Book $book
|
||||||
* @param Chapter $chapter
|
* @param Chapter $chapter
|
||||||
* @param Page $page
|
* @param Page $page
|
||||||
* @param Role $role
|
* @param Role $role
|
||||||
*/
|
*/
|
||||||
public function __construct(JointPermission $jointPermission, Book $book, Chapter $chapter, Page $page, Role $role)
|
public function __construct(JointPermission $jointPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role)
|
||||||
{
|
{
|
||||||
|
$this->db = $db;
|
||||||
$this->jointPermission = $jointPermission;
|
$this->jointPermission = $jointPermission;
|
||||||
$this->role = $role;
|
$this->role = $role;
|
||||||
$this->book = $book;
|
$this->book = $book;
|
||||||
$this->chapter = $chapter;
|
$this->chapter = $chapter;
|
||||||
$this->page = $page;
|
$this->page = $page;
|
||||||
|
// TODO - Update so admin still goes through filters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,6 +308,10 @@ class PermissionService
|
|||||||
$explodedAction = explode('-', $action);
|
$explodedAction = explode('-', $action);
|
||||||
$restrictionAction = end($explodedAction);
|
$restrictionAction = end($explodedAction);
|
||||||
|
|
||||||
|
if ($role->system_name === 'admin') {
|
||||||
|
return $this->createJointPermissionDataArray($entity, $role, $action, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
if ($entity->isA('book')) {
|
if ($entity->isA('book')) {
|
||||||
|
|
||||||
if (!$entity->restricted) {
|
if (!$entity->restricted) {
|
||||||
@ -461,61 +471,77 @@ class PermissionService
|
|||||||
return $q;
|
return $q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function bookChildrenQuery($book_id, $filterDrafts = false) {
|
||||||
* Add restrictions for a page query
|
|
||||||
* @param $query
|
|
||||||
* @param string $action
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function enforcePageRestrictions($query, $action = 'view')
|
|
||||||
{
|
|
||||||
// Prevent drafts being visible to others.
|
|
||||||
$query = $query->where(function ($query) {
|
|
||||||
$query->where('draft', '=', false);
|
|
||||||
if ($this->currentUser()) {
|
|
||||||
$query->orWhere(function ($query) {
|
|
||||||
$query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return $this->enforceEntityRestrictions($query, $action);
|
// Draft setup
|
||||||
}
|
$params = [
|
||||||
|
'userId' => $this->currentUser()->id,
|
||||||
|
'bookIdPage' => $book_id,
|
||||||
|
'bookIdChapter' => $book_id
|
||||||
|
];
|
||||||
|
if (!$filterDrafts) {
|
||||||
|
$params['userIdDrafts'] = $this->currentUser()->id;
|
||||||
|
}
|
||||||
|
// Role setup
|
||||||
|
$userRoles = $this->getRoles();
|
||||||
|
$roleBindings = [];
|
||||||
|
$roleValues = [];
|
||||||
|
foreach ($userRoles as $index => $roleId) {
|
||||||
|
$roleBindings[':role'.$index] = $roleId;
|
||||||
|
$roleValues['role'.$index] = $roleId;
|
||||||
|
}
|
||||||
|
// TODO - Clean this up, Maybe extract into a nice class for doing these kind of manual things
|
||||||
|
// Something which will handle the above role crap in a nice clean way
|
||||||
|
$roleBindingString = implode(',', array_keys($roleBindings));
|
||||||
|
$query = "SELECT * from (
|
||||||
|
(SELECT 'Bookstack\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft FROM {$this->page->getTable()}
|
||||||
|
where book_id = :bookIdPage AND ". ($filterDrafts ? '(draft = 0)' : '(draft = 0 OR (draft = 1 AND created_by = :userIdDrafts))') .")
|
||||||
|
UNION
|
||||||
|
(SELECT 'Bookstack\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft FROM {$this->chapter->getTable()} WHERE book_id = :bookIdChapter)
|
||||||
|
) as U WHERE (
|
||||||
|
SELECT COUNT(*) FROM {$this->jointPermission->getTable()} jp
|
||||||
|
WHERE
|
||||||
|
jp.entity_id=U.id AND
|
||||||
|
jp.entity_type=U.entity_type AND
|
||||||
|
jp.action = 'view' AND
|
||||||
|
jp.role_id IN ({$roleBindingString}) AND
|
||||||
|
(
|
||||||
|
jp.has_permission = 1 OR
|
||||||
|
(jp.has_permission_own = 1 AND jp.created_by = :userId)
|
||||||
|
)
|
||||||
|
) > 0
|
||||||
|
ORDER BY draft desc, priority asc";
|
||||||
|
|
||||||
/**
|
$this->clean();
|
||||||
* Add on permission restrictions to a chapter query.
|
return $this->db->select($query, array_replace($roleValues, $params));
|
||||||
* @param $query
|
|
||||||
* @param string $action
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function enforceChapterRestrictions($query, $action = 'view')
|
|
||||||
{
|
|
||||||
return $this->enforceEntityRestrictions($query, $action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add restrictions to a book query.
|
|
||||||
* @param $query
|
|
||||||
* @param string $action
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function enforceBookRestrictions($query, $action = 'view')
|
|
||||||
{
|
|
||||||
return $this->enforceEntityRestrictions($query, $action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add restrictions for a generic entity
|
* Add restrictions for a generic entity
|
||||||
* @param $query
|
* @param string $entityType
|
||||||
|
* @param Builder|Entity $query
|
||||||
* @param string $action
|
* @param string $action
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function enforceEntityRestrictions($query, $action = 'view')
|
public function enforceEntityRestrictions($entityType, $query, $action = 'view')
|
||||||
{
|
{
|
||||||
|
if (strtolower($entityType) === 'page') {
|
||||||
|
// Prevent drafts being visible to others.
|
||||||
|
$query = $query->where(function ($query) {
|
||||||
|
$query->where('draft', '=', false);
|
||||||
|
if ($this->currentUser()) {
|
||||||
|
$query->orWhere(function ($query) {
|
||||||
|
$query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->isAdmin()) {
|
if ($this->isAdmin()) {
|
||||||
$this->clean();
|
$this->clean();
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->currentAction = $action;
|
$this->currentAction = $action;
|
||||||
return $this->entityRestrictionQuery($query);
|
return $this->entityRestrictionQuery($query);
|
||||||
}
|
}
|
||||||
@ -601,7 +627,7 @@ class PermissionService
|
|||||||
private function isAdmin()
|
private function isAdmin()
|
||||||
{
|
{
|
||||||
if ($this->isAdminUser === null) {
|
if ($this->isAdminUser === null) {
|
||||||
$this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasRole('admin') : false;
|
$this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasSystemRole('admin') : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->isAdminUser;
|
return $this->isAdminUser;
|
||||||
|
@ -5,9 +5,7 @@ use BookStack\View;
|
|||||||
|
|
||||||
class ViewService
|
class ViewService
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $view;
|
protected $view;
|
||||||
protected $user;
|
|
||||||
protected $permissionService;
|
protected $permissionService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,7 +16,6 @@ class ViewService
|
|||||||
public function __construct(View $view, PermissionService $permissionService)
|
public function __construct(View $view, PermissionService $permissionService)
|
||||||
{
|
{
|
||||||
$this->view = $view;
|
$this->view = $view;
|
||||||
$this->user = user();
|
|
||||||
$this->permissionService = $permissionService;
|
$this->permissionService = $permissionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,8 +26,9 @@ class ViewService
|
|||||||
*/
|
*/
|
||||||
public function add(Entity $entity)
|
public function add(Entity $entity)
|
||||||
{
|
{
|
||||||
if ($this->user === null) return 0;
|
$user = user();
|
||||||
$view = $entity->views()->where('user_id', '=', $this->user->id)->first();
|
if ($user === null || $user->isDefault()) return 0;
|
||||||
|
$view = $entity->views()->where('user_id', '=', $user->id)->first();
|
||||||
// Add view if model exists
|
// Add view if model exists
|
||||||
if ($view) {
|
if ($view) {
|
||||||
$view->increment('views');
|
$view->increment('views');
|
||||||
@ -39,7 +37,7 @@ class ViewService
|
|||||||
|
|
||||||
// Otherwise create new view count
|
// Otherwise create new view count
|
||||||
$entity->views()->save($this->view->create([
|
$entity->views()->save($this->view->create([
|
||||||
'user_id' => $this->user->id,
|
'user_id' => $user->id,
|
||||||
'views' => 1
|
'views' => 1
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -78,13 +76,14 @@ class ViewService
|
|||||||
*/
|
*/
|
||||||
public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
|
public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
|
||||||
{
|
{
|
||||||
if ($this->user === null) return collect();
|
$user = user();
|
||||||
|
if ($user === null || $user->isDefault()) return collect();
|
||||||
|
|
||||||
$query = $this->permissionService
|
$query = $this->permissionService
|
||||||
->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
|
->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
|
||||||
|
|
||||||
if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
|
if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
|
||||||
$query = $query->where('user_id', '=', user()->id);
|
$query = $query->where('user_id', '=', $user->id);
|
||||||
|
|
||||||
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
|
$viewables = $query->with('viewable')->orderBy('updated_at', 'desc')
|
||||||
->skip($count * $page)->take($count)->get()->pluck('viewable');
|
->skip($count * $page)->take($count)->get()->pluck('viewable');
|
||||||
|
10
app/User.php
10
app/User.php
@ -74,6 +74,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return $this->roles->pluck('name')->contains($role);
|
return $this->roles->pluck('name')->contains($role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the user has a role.
|
||||||
|
* @param $role
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function hasSystemRole($role)
|
||||||
|
{
|
||||||
|
return $this->roles->pluck('system_name')->contains('admin');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all permissions belonging to a the current user.
|
* Get all permissions belonging to a the current user.
|
||||||
* @param bool $cache
|
* @param bool $cache
|
||||||
|
@ -168,7 +168,7 @@ class EntityTest extends TestCase
|
|||||||
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
|
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
|
||||||
$this->actingAs($creator);
|
$this->actingAs($creator);
|
||||||
app('BookStack\Repos\UserRepo')->destroy($creator);
|
app('BookStack\Repos\UserRepo')->destroy($creator);
|
||||||
app('BookStack\Repos\PageRepo')->saveRevision($entities['page']);
|
app('BookStack\Repos\EntityRepo')->savePageRevision($entities['page']);
|
||||||
|
|
||||||
$this->checkEntitiesViewable($entities);
|
$this->checkEntitiesViewable($entities);
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ class EntityTest extends TestCase
|
|||||||
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
|
$entities = $this->createEntityChainBelongingToUser($creator, $updater);
|
||||||
$this->actingAs($updater);
|
$this->actingAs($updater);
|
||||||
app('BookStack\Repos\UserRepo')->destroy($updater);
|
app('BookStack\Repos\UserRepo')->destroy($updater);
|
||||||
app('BookStack\Repos\PageRepo')->saveRevision($entities['page']);
|
app('BookStack\Repos\EntityRepo')->savePageRevision($entities['page']);
|
||||||
|
|
||||||
$this->checkEntitiesViewable($entities);
|
$this->checkEntitiesViewable($entities);
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
class PageDraftTest extends TestCase
|
class PageDraftTest extends TestCase
|
||||||
{
|
{
|
||||||
protected $page;
|
protected $page;
|
||||||
protected $pageRepo;
|
protected $entityRepo;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->page = \BookStack\Page::first();
|
$this->page = \BookStack\Page::first();
|
||||||
$this->pageRepo = app('\BookStack\Repos\PageRepo');
|
$this->entityRepo = app('\BookStack\Repos\EntityRepo');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_draft_content_shows_if_available()
|
public function test_draft_content_shows_if_available()
|
||||||
@ -20,7 +20,7 @@ class PageDraftTest extends TestCase
|
|||||||
->dontSeeInField('html', $addedContent);
|
->dontSeeInField('html', $addedContent);
|
||||||
|
|
||||||
$newContent = $this->page->html . $addedContent;
|
$newContent = $this->page->html . $addedContent;
|
||||||
$this->pageRepo->saveUpdateDraft($this->page, ['html' => $newContent]);
|
$this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]);
|
||||||
$this->asAdmin()->visit($this->page->getUrl() . '/edit')
|
$this->asAdmin()->visit($this->page->getUrl() . '/edit')
|
||||||
->seeInField('html', $newContent);
|
->seeInField('html', $newContent);
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ class PageDraftTest extends TestCase
|
|||||||
|
|
||||||
$newContent = $this->page->html . $addedContent;
|
$newContent = $this->page->html . $addedContent;
|
||||||
$newUser = $this->getEditor();
|
$newUser = $this->getEditor();
|
||||||
$this->pageRepo->saveUpdateDraft($this->page, ['html' => $newContent]);
|
$this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]);
|
||||||
$this->actingAs($newUser)->visit($this->page->getUrl() . '/edit')
|
$this->actingAs($newUser)->visit($this->page->getUrl() . '/edit')
|
||||||
->dontSeeInField('html', $newContent);
|
->dontSeeInField('html', $newContent);
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ class PageDraftTest extends TestCase
|
|||||||
public function test_alert_message_shows_if_editing_draft()
|
public function test_alert_message_shows_if_editing_draft()
|
||||||
{
|
{
|
||||||
$this->asAdmin();
|
$this->asAdmin();
|
||||||
$this->pageRepo->saveUpdateDraft($this->page, ['html' => 'test content']);
|
$this->entityRepo->updatePageDraft($this->page, ['html' => 'test content']);
|
||||||
$this->asAdmin()->visit($this->page->getUrl() . '/edit')
|
$this->asAdmin()->visit($this->page->getUrl() . '/edit')
|
||||||
->see('You are currently editing a draft');
|
->see('You are currently editing a draft');
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ class PageDraftTest extends TestCase
|
|||||||
|
|
||||||
$newContent = $this->page->html . $addedContent;
|
$newContent = $this->page->html . $addedContent;
|
||||||
$newUser = $this->getEditor();
|
$newUser = $this->getEditor();
|
||||||
$this->pageRepo->saveUpdateDraft($this->page, ['html' => $newContent]);
|
$this->entityRepo->updatePageDraft($this->page, ['html' => $newContent]);
|
||||||
|
|
||||||
$this->actingAs($newUser)
|
$this->actingAs($newUser)
|
||||||
->visit($this->page->getUrl() . '/edit')
|
->visit($this->page->getUrl() . '/edit')
|
||||||
|
@ -13,8 +13,8 @@ class SortTest extends TestCase
|
|||||||
public function test_drafts_do_not_show_up()
|
public function test_drafts_do_not_show_up()
|
||||||
{
|
{
|
||||||
$this->asAdmin();
|
$this->asAdmin();
|
||||||
$pageRepo = app('\BookStack\Repos\PageRepo');
|
$entityRepo = app('\BookStack\Repos\EntityRepo');
|
||||||
$draft = $pageRepo->getDraftPage($this->book);
|
$draft = $entityRepo->getDraftPage($this->book);
|
||||||
|
|
||||||
$this->visit($this->book->getUrl())
|
$this->visit($this->book->getUrl())
|
||||||
->see($draft->name)
|
->see($draft->name)
|
||||||
|
@ -90,7 +90,7 @@ class ImageTest extends TestCase
|
|||||||
'type' => 'gallery'
|
'type' => 'gallery'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded image has been deleted');
|
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded image has not been deleted as expected');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -65,9 +65,9 @@ class RestrictionsTest extends TestCase
|
|||||||
$this->forceVisit($bookUrl)
|
$this->forceVisit($bookUrl)
|
||||||
->see('Book not found');
|
->see('Book not found');
|
||||||
$this->forceVisit($bookPage->getUrl())
|
$this->forceVisit($bookPage->getUrl())
|
||||||
->see('Book not found');
|
->see('Page not found');
|
||||||
$this->forceVisit($bookChapter->getUrl())
|
$this->forceVisit($bookChapter->getUrl())
|
||||||
->see('Book not found');
|
->see('Chapter not found');
|
||||||
|
|
||||||
$this->setEntityRestrictions($book, ['view']);
|
$this->setEntityRestrictions($book, ['view']);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user