mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Got book to shelf conversions working
- Also extracted shelf to book view elements to own partial. - Fixed some existing logic including image param handling in update request and activity logging against correct element.
This commit is contained in:
parent
8da856bac3
commit
8c67011a1d
@ -22,6 +22,7 @@ class ActivityType
|
||||
const BOOK_SORT = 'book_sort';
|
||||
|
||||
const BOOKSHELF_CREATE = 'bookshelf_create';
|
||||
const BOOKSHELF_CREATE_FROM_BOOK = 'bookshelf_create_from_book';
|
||||
const BOOKSHELF_UPDATE = 'bookshelf_update';
|
||||
const BOOKSHELF_DELETE = 'bookshelf_delete';
|
||||
|
||||
|
@ -89,7 +89,7 @@ class BookshelfRepo
|
||||
{
|
||||
$shelf = new Bookshelf();
|
||||
$this->baseRepo->create($shelf, $input);
|
||||
$this->baseRepo->updateCoverImage($shelf, $input['image']);
|
||||
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
|
||||
$this->updateBooks($shelf, $bookIds);
|
||||
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
|
||||
|
||||
@ -107,7 +107,7 @@ class BookshelfRepo
|
||||
$this->updateBooks($shelf, $bookIds);
|
||||
}
|
||||
|
||||
if (isset($input['image'])) {
|
||||
if (array_key_exists('image', $input)) {
|
||||
$this->baseRepo->updateCoverImage($shelf, $input['image'], $input['image'] === null);
|
||||
}
|
||||
|
||||
|
@ -392,23 +392,6 @@ class PageRepo
|
||||
return $parentClass::visible()->where('id', '=', $entityId)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the page's parent to the given entity.
|
||||
*/
|
||||
protected function changeParent(Page $page, Entity $parent)
|
||||
{
|
||||
$book = ($parent instanceof Chapter) ? $parent->book : $parent;
|
||||
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : 0;
|
||||
$page->save();
|
||||
|
||||
if ($page->book->id !== $book->id) {
|
||||
$page->changeBook($book->id);
|
||||
}
|
||||
|
||||
$page->load('book');
|
||||
$book->rebuildPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a page revision to update for the given page.
|
||||
* Checks for an existing revisions before providing a fresh one.
|
||||
|
@ -44,14 +44,16 @@ class HierarchyTransformer
|
||||
|
||||
$this->trashCan->destroyEntity($chapter);
|
||||
|
||||
Activity::add(ActivityType::BOOK_CREATE_FROM_CHAPTER);
|
||||
Activity::add(ActivityType::BOOK_CREATE_FROM_CHAPTER, $book);
|
||||
return $book;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a book into a shelf.
|
||||
* Does not check permissions, check before calling.
|
||||
*/
|
||||
public function transformBookToShelf(Book $book): Bookshelf
|
||||
{
|
||||
// TODO - Check permissions before call
|
||||
// Permissions: edit-book, delete-book, create-shelf
|
||||
$inputData = $this->cloner->entityToInputData($book);
|
||||
$shelf = $this->shelfRepo->create($inputData, []);
|
||||
$this->cloner->copyEntityPermissions($book, $shelf);
|
||||
@ -62,17 +64,22 @@ class HierarchyTransformer
|
||||
foreach ($book->chapters as $index => $chapter) {
|
||||
$newBook = $this->transformChapterToBook($chapter);
|
||||
$shelfBookSyncData[$newBook->id] = ['order' => $index];
|
||||
if (!$newBook->restricted) {
|
||||
$this->cloner->copyEntityPermissions($shelf, $newBook);
|
||||
}
|
||||
}
|
||||
|
||||
$shelf->books()->sync($shelfBookSyncData);
|
||||
|
||||
if ($book->directPages->count() > 0) {
|
||||
$book->name .= ' ' . trans('entities.pages');
|
||||
$shelfBookSyncData[$book->id] = ['order' => count($shelfBookSyncData) + 1];
|
||||
$book->save();
|
||||
} else {
|
||||
$this->trashCan->destroyEntity($book);
|
||||
}
|
||||
|
||||
// TODO - Log activity for change
|
||||
$shelf->books()->sync($shelfBookSyncData);
|
||||
|
||||
Activity::add(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $shelf);
|
||||
return $shelf;
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Entities\Repos\BookRepo;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
use BookStack\Entities\Tools\Cloner;
|
||||
use BookStack\Entities\Tools\HierarchyTransformer;
|
||||
use BookStack\Entities\Tools\PermissionsUpdater;
|
||||
use BookStack\Entities\Tools\ShelfContext;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
@ -166,7 +167,7 @@ class BookController extends Controller
|
||||
|
||||
if ($request->has('image_reset')) {
|
||||
$validated['image'] = null;
|
||||
} else if (is_null($validated['image'])) {
|
||||
} else if (array_key_exists('image', $validated) && is_null($validated['image'])) {
|
||||
unset($validated['image']);
|
||||
}
|
||||
|
||||
@ -266,4 +267,20 @@ class BookController extends Controller
|
||||
|
||||
return redirect($bookCopy->getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the chapter to a book.
|
||||
*/
|
||||
public function convertToShelf(HierarchyTransformer $transformer, string $bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$this->checkOwnablePermission('book-update', $book);
|
||||
$this->checkOwnablePermission('book-delete', $book);
|
||||
$this->checkPermission('bookshelf-create-all');
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$shelf = $transformer->transformBookToShelf($book);
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ class BookshelfController extends Controller
|
||||
|
||||
if ($request->has('image_reset')) {
|
||||
$validated['image'] = null;
|
||||
} else if (is_null($validated['image'])) {
|
||||
} else if (array_key_exists('image', $validated) && is_null($validated['image'])) {
|
||||
unset($validated['image']);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@ return [
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'created bookshelf',
|
||||
'bookshelf_create_notification' => 'Bookshelf successfully created',
|
||||
'bookshelf_create_from_book' => 'converted book to bookshelf',
|
||||
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
|
||||
'bookshelf_update' => 'updated bookshelf',
|
||||
'bookshelf_update_notification' => 'Bookshelf successfully updated',
|
||||
'bookshelf_delete' => 'deleted bookshelf',
|
||||
|
@ -14,12 +14,17 @@
|
||||
]])
|
||||
</div>
|
||||
|
||||
<main class="content-wrap card">
|
||||
<main class="content-wrap card auto-height">
|
||||
<h1 class="list-heading">{{ trans('entities.books_edit') }}</h1>
|
||||
<form action="{{ $book->getUrl() }}" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
@include('books.parts.form', ['model' => $book, 'returnLocation' => $book->getUrl()])
|
||||
</form>
|
||||
</main>
|
||||
|
||||
|
||||
@if(userCan('book-delete', $book) && userCan('book-create-all') && userCan('bookshelf-create-all'))
|
||||
@include('books.parts.convert-to-shelf', ['book' => $book])
|
||||
@endif
|
||||
</div>
|
||||
@stop
|
35
resources/views/books/parts/convert-to-shelf.blade.php
Normal file
35
resources/views/books/parts/convert-to-shelf.blade.php
Normal file
@ -0,0 +1,35 @@
|
||||
<div class="content-wrap card auto-height">
|
||||
<h2 class="list-heading">Convert to Shelf</h2>
|
||||
<p>
|
||||
You can convert this book to a new shelf with the same contents.
|
||||
Chapters contained within this book will be converted to new books.
|
||||
|
||||
If this book contains any pages, that are not in a chapter, this book will be renamed
|
||||
and contain such pages, and this book will become part of the new shelf.
|
||||
|
||||
<br><br>
|
||||
|
||||
Any permissions set on this book will be copied to the new shelf and to all new child books
|
||||
that don't have their own permissions enforced.
|
||||
|
||||
Note that permissions on shelves do not auto-cascade to content within, as they do for books.
|
||||
</p>
|
||||
<div class="text-right">
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<button refs="dropdown@toggle" class="button outline" aria-haspopup="true" aria-expanded="false">Convert Book</button>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s text-small text-muted">
|
||||
Are you sure you want to convert this book?
|
||||
<br>
|
||||
This cannot be as easily undone.
|
||||
</li>
|
||||
<li>
|
||||
<form action="{{ $book->getUrl('/convert-to-shelf') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<button type="submit" class="text-primary text-item">{{ trans('common.confirm') }}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -23,35 +23,9 @@
|
||||
</form>
|
||||
</main>
|
||||
|
||||
{{-- TODO - Permissions--}}
|
||||
<div class="content-wrap card auto-height">
|
||||
<h2 class="list-heading">Convert to Book</h2>
|
||||
<div class="grid half left-focus no-row-gap">
|
||||
<p>
|
||||
You can convert this chapter to a new book with the same contents.
|
||||
Any permissions set on this chapter will be copied to the new book but any inherited permissions,
|
||||
from the parent book, will not be copied which could lead to a change of access control.
|
||||
</p>
|
||||
<div class="text-m-right">
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<button refs="dropdown@toggle" class="button outline" aria-haspopup="true" aria-expanded="false">Convert Chapter</button>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s text-small text-muted">
|
||||
Are you sure you want to convert this chapter?
|
||||
<br>
|
||||
This cannot be as easily undone.
|
||||
</li>
|
||||
<li>
|
||||
<form action="{{ $chapter->getUrl('/convert-to-book') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<button type="submit" class="text-primary text-item">{{ trans('common.confirm') }}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if(userCan('chapter-delete', $chapter) && userCan('book-create-all'))
|
||||
@include('chapters.parts.convert-to-book')
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
28
resources/views/chapters/parts/convert-to-book.blade.php
Normal file
28
resources/views/chapters/parts/convert-to-book.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
<div class="content-wrap card auto-height">
|
||||
<h2 class="list-heading">Convert to Book</h2>
|
||||
<div class="grid half left-focus no-row-gap">
|
||||
<p>
|
||||
You can convert this chapter to a new book with the same contents.
|
||||
Any permissions set on this chapter will be copied to the new book but any inherited permissions,
|
||||
from the parent book, will not be copied which could lead to a change of access control.
|
||||
</p>
|
||||
<div class="text-m-right">
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<button refs="dropdown@toggle" class="button outline" aria-haspopup="true" aria-expanded="false">Convert Chapter</button>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s text-small text-muted">
|
||||
Are you sure you want to convert this chapter?
|
||||
<br>
|
||||
This cannot be as easily undone.
|
||||
</li>
|
||||
<li>
|
||||
<form action="{{ $chapter->getUrl('/convert-to-book') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<button type="submit" class="text-primary text-item">{{ trans('common.confirm') }}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -82,6 +82,7 @@ Route::middleware('auth')->group(function () {
|
||||
Route::get('/books/{slug}/delete', [BookController::class, 'showDelete']);
|
||||
Route::get('/books/{bookSlug}/copy', [BookController::class, 'showCopy']);
|
||||
Route::post('/books/{bookSlug}/copy', [BookController::class, 'copy']);
|
||||
Route::post('/books/{bookSlug}/convert-to-shelf', [BookController::class, 'convertToShelf']);
|
||||
Route::get('/books/{bookSlug}/sort', [BookSortController::class, 'show']);
|
||||
Route::put('/books/{bookSlug}/sort', [BookSortController::class, 'update']);
|
||||
Route::get('/books/{bookSlug}/export/html', [BookExportController::class, 'html']);
|
||||
|
Loading…
Reference in New Issue
Block a user