From 9baa96d41ce6b4f7949c5a1f4b2b9fa699d3d679 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 25 Jun 2016 15:31:38 +0100 Subject: [PATCH] Added chapter move actions. Closes #86 --- app/Http/Controllers/ChapterController.php | 49 +++++++++++++++++++ app/Http/Controllers/PageController.php | 8 +++ app/Http/routes.php | 2 + app/Repos/ChapterRepo.php | 21 ++++++++ resources/lang/en/activities.php | 3 +- resources/views/chapters/move.blade.php | 33 +++++++++++++ resources/views/chapters/show.blade.php | 26 +++++++--- resources/views/pages/move.blade.php | 9 +--- .../views/partials/entity-selector.blade.php | 8 +++ tests/Entity/SortTest.php | 25 ++++++++++ 10 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 resources/views/chapters/move.blade.php create mode 100644 resources/views/partials/entity-selector.blade.php diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index 69e9488b9..a3a939f61 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -154,6 +154,55 @@ class ChapterController extends Controller return redirect($book->getUrl()); } + /** + * Show the page for moving a chapter. + * @param $bookSlug + * @param $chapterSlug + * @return mixed + * @throws \BookStack\Exceptions\NotFoundException + */ + public function showMove($bookSlug, $chapterSlug) { + $book = $this->bookRepo->getBySlug($bookSlug); + $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); + $this->checkOwnablePermission('chapter-update', $chapter); + return view('chapters/move', [ + 'chapter' => $chapter, + 'book' => $book + ]); + } + + public function move($bookSlug, $chapterSlug, Request $request) { + $book = $this->bookRepo->getBySlug($bookSlug); + $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); + $this->checkOwnablePermission('chapter-update', $chapter); + + $entitySelection = $request->get('entity_selection', null); + if ($entitySelection === null || $entitySelection === '') { + return redirect($chapter->getUrl()); + } + + $stringExploded = explode(':', $entitySelection); + $entityType = $stringExploded[0]; + $entityId = intval($stringExploded[1]); + + $parent = false; + + if ($entityType == 'book') { + $parent = $this->bookRepo->getById($entityId); + } + + if ($parent === false || $parent === null) { + session()->flash('The selected Book was not found'); + return redirect()->back(); + } + + $this->chapterRepo->changeBook($parent->id, $chapter); + Activity::add($chapter, 'chapter_move', $chapter->book->id); + session()->flash('success', sprintf('Chapter moved to "%s"', $parent->name)); + + return redirect($chapter->getUrl()); + } + /** * Show the Restrictions view. * @param $bookSlug diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 373e49de7..f35834e62 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -468,6 +468,14 @@ class PageController extends Controller ]); } + /** + * Does the action of moving the location of a page + * @param $bookSlug + * @param $pageSlug + * @param Request $request + * @return mixed + * @throws NotFoundException + */ public function move($bookSlug, $pageSlug, Request $request) { $book = $this->bookRepo->getBySlug($bookSlug); diff --git a/app/Http/routes.php b/app/Http/routes.php index d7c090953..eb35f2a11 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -55,6 +55,8 @@ Route::group(['middleware' => 'auth'], function () { Route::post('/{bookSlug}/chapter/create', 'ChapterController@store'); Route::get('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@show'); Route::put('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@update'); + Route::get('/{bookSlug}/chapter/{chapterSlug}/move', 'ChapterController@showMove'); + Route::put('/{bookSlug}/chapter/{chapterSlug}/move', 'ChapterController@move'); Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit'); Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showRestrict'); Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@restrict'); diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php index 048e0a63b..3c518bde9 100644 --- a/app/Repos/ChapterRepo.php +++ b/app/Repos/ChapterRepo.php @@ -9,6 +9,18 @@ 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 @@ -189,12 +201,21 @@ class ChapterRepo extends EntityRepo public function changeBook($bookId, Chapter $chapter) { $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 + $chapter->load('book'); + $this->permissionService->buildJointPermissionsForEntity($chapter->book); + return $chapter; } diff --git a/resources/lang/en/activities.php b/resources/lang/en/activities.php index c59513aa9..56af4ca07 100644 --- a/resources/lang/en/activities.php +++ b/resources/lang/en/activities.php @@ -4,7 +4,7 @@ return [ /** * Activity text strings. - * Is used for all the text within activity logs. + * Is used for all the text within activity logs & notifications. */ // Pages @@ -25,6 +25,7 @@ return [ 'chapter_update_notification' => 'Chapter Successfully Updated', 'chapter_delete' => 'deleted chapter', 'chapter_delete_notification' => 'Chapter Successfully Deleted', + 'chapter_move' => 'moved chapter', // Books 'book_create' => 'created book', diff --git a/resources/views/chapters/move.blade.php b/resources/views/chapters/move.blade.php new file mode 100644 index 000000000..024fc6684 --- /dev/null +++ b/resources/views/chapters/move.blade.php @@ -0,0 +1,33 @@ +@extends('base') + +@section('content') + +
+ +
+ +
+

Move Chapter {{$chapter->name}}

+ +
+ {!! csrf_field() !!} + + + @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) + + Cancel + +
+
+ +@stop diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index 269358471..b79cd8415 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -2,15 +2,15 @@ @section('content') -
+
-
+ -
+
@if(userCan('page-create', $chapter)) New Page @@ -18,11 +18,21 @@ @if(userCan('chapter-update', $chapter)) Edit @endif - @if(userCan('restrictions-manage', $chapter)) - Permissions - @endif - @if(userCan('chapter-delete', $chapter)) - Delete + @if(userCan('chapter-update', $chapter) || userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter)) + @endif
diff --git a/resources/views/pages/move.blade.php b/resources/views/pages/move.blade.php index 5b02c827e..27ee4cd92 100644 --- a/resources/views/pages/move.blade.php +++ b/resources/views/pages/move.blade.php @@ -30,14 +30,7 @@ {!! csrf_field() !!} -
-
- - -
@include('partials/loading-icon')
-
-
-
+ @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) Cancel diff --git a/resources/views/partials/entity-selector.blade.php b/resources/views/partials/entity-selector.blade.php new file mode 100644 index 000000000..59e174155 --- /dev/null +++ b/resources/views/partials/entity-selector.blade.php @@ -0,0 +1,8 @@ +
+
+ + +
@include('partials/loading-icon')
+
+
+
\ No newline at end of file diff --git a/tests/Entity/SortTest.php b/tests/Entity/SortTest.php index 2f2f9109d..80783912a 100644 --- a/tests/Entity/SortTest.php +++ b/tests/Entity/SortTest.php @@ -40,4 +40,29 @@ class SortTest extends TestCase ->seeInNthElement('.activity-list-item', 0, $page->name); } + public function test_chapter_move() + { + $chapter = \BookStack\Chapter::first(); + $currentBook = $chapter->book; + $pageToCheck = $chapter->pages->first(); + $newBook = \BookStack\Book::where('id', '!=', $currentBook->id)->first(); + + $this->asAdmin()->visit($chapter->getUrl() . '/move') + ->see('Move Chapter')->see($chapter->name) + ->type('book:' . $newBook->id, 'entity_selection')->press('Move Chapter'); + + $chapter = \BookStack\Chapter::find($chapter->id); + $this->seePageIs($chapter->getUrl()); + $this->assertTrue($chapter->book->id === $newBook->id, 'Chapter Book is now the new book'); + + $this->visit($newBook->getUrl()) + ->seeInNthElement('.activity-list-item', 0, 'moved chapter') + ->seeInNthElement('.activity-list-item', 0, $chapter->name); + + $pageToCheck = \BookStack\Page::find($pageToCheck->id); + $this->assertTrue($pageToCheck->book_id === $newBook->id, 'Chapter child page\'s book id has changed to the new book'); + $this->visit($pageToCheck->getUrl()) + ->see($newBook->name); + } + } \ No newline at end of file