0
0
Fork 0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-05-01 06:59:52 +00:00

Got chapter conversion to books working

- Added required UI within edit view.
- Added required routes and controller actions.
This commit is contained in:
Dan Brown 2022-06-14 16:42:29 +01:00
parent 90ec40691a
commit 8da856bac3
No known key found for this signature in database
GPG key ID: 46D9F943C24A2EF9
7 changed files with 69 additions and 6 deletions
app
resources
lang/en
views/chapters
routes

View file

@ -16,6 +16,7 @@ class ActivityType
const CHAPTER_MOVE = 'chapter_move'; const CHAPTER_MOVE = 'chapter_move';
const BOOK_CREATE = 'book_create'; const BOOK_CREATE = 'book_create';
const BOOK_CREATE_FROM_CHAPTER = 'book_create_from_chapter';
const BOOK_UPDATE = 'book_update'; const BOOK_UPDATE = 'book_update';
const BOOK_DELETE = 'book_delete'; const BOOK_DELETE = 'book_delete';
const BOOK_SORT = 'book_sort'; const BOOK_SORT = 'book_sort';

View file

@ -91,7 +91,7 @@ class BookRepo
{ {
$book = new Book(); $book = new Book();
$this->baseRepo->create($book, $input); $this->baseRepo->create($book, $input);
$this->baseRepo->updateCoverImage($book, $input['image']); $this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
Activity::add(ActivityType::BOOK_CREATE, $book); Activity::add(ActivityType::BOOK_CREATE, $book);
return $book; return $book;
@ -104,7 +104,7 @@ class BookRepo
{ {
$this->baseRepo->update($book, $input); $this->baseRepo->update($book, $input);
if (isset($input['image'])) { if (array_key_exists('image', $input)) {
$this->baseRepo->updateCoverImage($book, $input['image'], $input['image'] === null); $this->baseRepo->updateCoverImage($book, $input['image'], $input['image'] === null);
} }

View file

@ -2,12 +2,14 @@
namespace BookStack\Entities\Tools; namespace BookStack\Entities\Tools;
use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo; use BookStack\Entities\Repos\BookshelfRepo;
use BookStack\Facades\Activity;
class HierarchyTransformer class HierarchyTransformer
{ {
@ -16,10 +18,20 @@ class HierarchyTransformer
protected Cloner $cloner; protected Cloner $cloner;
protected TrashCan $trashCan; protected TrashCan $trashCan;
public function __construct(BookRepo $bookRepo, BookshelfRepo $shelfRepo, Cloner $cloner, TrashCan $trashCan)
{
$this->bookRepo = $bookRepo;
$this->shelfRepo = $shelfRepo;
$this->cloner = $cloner;
$this->trashCan = $trashCan;
}
/**
* Transform a chapter into a book.
* Does not check permissions, check before calling.
*/
public function transformChapterToBook(Chapter $chapter): Book public function transformChapterToBook(Chapter $chapter): Book
{ {
// TODO - Check permissions before call
// Permissions: edit-chapter, delete-chapter, create-book
$inputData = $this->cloner->entityToInputData($chapter); $inputData = $this->cloner->entityToInputData($chapter);
$book = $this->bookRepo->create($inputData); $book = $this->bookRepo->create($inputData);
$this->cloner->copyEntityPermissions($chapter, $book); $this->cloner->copyEntityPermissions($chapter, $book);
@ -32,7 +44,7 @@ class HierarchyTransformer
$this->trashCan->destroyEntity($chapter); $this->trashCan->destroyEntity($chapter);
// TODO - Log activity for change Activity::add(ActivityType::BOOK_CREATE_FROM_CHAPTER);
return $book; return $book;
} }

View file

@ -7,6 +7,7 @@ use BookStack\Entities\Models\Book;
use BookStack\Entities\Repos\ChapterRepo; use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\Cloner;
use BookStack\Entities\Tools\HierarchyTransformer;
use BookStack\Entities\Tools\NextPreviousContentLocator; use BookStack\Entities\Tools\NextPreviousContentLocator;
use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Exceptions\MoveOperationException; use BookStack\Exceptions\MoveOperationException;
@ -272,4 +273,20 @@ class ChapterController extends Controller
return redirect($chapter->getUrl()); return redirect($chapter->getUrl());
} }
/**
* Convert the chapter to a book.
*/
public function convertToBook(HierarchyTransformer $transformer, string $bookSlug, string $chapterSlug)
{
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter);
$this->checkPermission('book-create-all');
$book = $transformer->transformChapterToBook($chapter);
return redirect($book->getUrl());
}
} }

View file

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'created book', 'book_create' => 'created book',
'book_create_notification' => 'Book successfully created', 'book_create_notification' => 'Book successfully created',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'updated book', 'book_update' => 'updated book',
'book_update_notification' => 'Book successfully updated', 'book_update_notification' => 'Book successfully updated',
'book_delete' => 'deleted book', 'book_delete' => 'deleted book',

View file

@ -15,7 +15,7 @@
]]) ]])
</div> </div>
<main class="content-wrap card"> <main class="content-wrap card auto-height">
<h1 class="list-heading">{{ trans('entities.chapters_edit') }}</h1> <h1 class="list-heading">{{ trans('entities.chapters_edit') }}</h1>
<form action="{{ $chapter->getUrl() }}" method="POST"> <form action="{{ $chapter->getUrl() }}" method="POST">
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@ -23,6 +23,36 @@
</form> </form>
</main> </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>
</div> </div>
@stop @stop

View file

@ -132,6 +132,7 @@ Route::middleware('auth')->group(function () {
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'showCopy']); Route::get('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'showCopy']);
Route::post('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'copy']); Route::post('/books/{bookSlug}/chapter/{chapterSlug}/copy', [ChapterController::class, 'copy']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/edit', [ChapterController::class, 'edit']); Route::get('/books/{bookSlug}/chapter/{chapterSlug}/edit', [ChapterController::class, 'edit']);
Route::post('/books/{bookSlug}/chapter/{chapterSlug}/convert-to-book', [ChapterController::class, 'convertToBook']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/permissions', [ChapterController::class, 'showPermissions']); Route::get('/books/{bookSlug}/chapter/{chapterSlug}/permissions', [ChapterController::class, 'showPermissions']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/pdf', [ChapterExportController::class, 'pdf']); Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/pdf', [ChapterExportController::class, 'pdf']);
Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/html', [ChapterExportController::class, 'html']); Route::get('/books/{bookSlug}/chapter/{chapterSlug}/export/html', [ChapterExportController::class, 'html']);