diff --git a/app/Entities/Models/Book.php b/app/Entities/Models/Book.php index c1644dcf5..7d240e5ca 100644 --- a/app/Entities/Models/Book.php +++ b/app/Entities/Models/Book.php @@ -2,6 +2,7 @@ namespace BookStack\Entities\Models; +use BookStack\Sorting\SortSet; use BookStack\Uploads\Image; use Exception; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -16,12 +17,14 @@ use Illuminate\Support\Collection; * @property string $description * @property int $image_id * @property ?int $default_template_id + * @property ?int $sort_set_id * @property Image|null $cover * @property \Illuminate\Database\Eloquent\Collection $chapters * @property \Illuminate\Database\Eloquent\Collection $pages * @property \Illuminate\Database\Eloquent\Collection $directPages * @property \Illuminate\Database\Eloquent\Collection $shelves * @property ?Page $defaultTemplate + * @property ?SortSet $sortSet */ class Book extends Entity implements HasCoverImage { @@ -82,6 +85,14 @@ class Book extends Entity implements HasCoverImage return $this->belongsTo(Page::class, 'default_template_id'); } + /** + * Get the sort set assigned to this book, if existing. + */ + public function sortSet(): BelongsTo + { + return $this->belongsTo(SortSet::class); + } + /** * Get all pages within this book. */ diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php index 19d159eb1..b3b811647 100644 --- a/app/Entities/Repos/BookRepo.php +++ b/app/Entities/Repos/BookRepo.php @@ -8,6 +8,7 @@ use BookStack\Entities\Models\Book; use BookStack\Entities\Tools\TrashCan; use BookStack\Exceptions\ImageUploadException; use BookStack\Facades\Activity; +use BookStack\Sorting\SortSet; use BookStack\Uploads\ImageRepo; use Exception; use Illuminate\Http\UploadedFile; @@ -33,6 +34,12 @@ class BookRepo $this->baseRepo->updateDefaultTemplate($book, intval($input['default_template_id'] ?? null)); Activity::add(ActivityType::BOOK_CREATE, $book); + $defaultBookSortSetting = intval(setting('sorting-book-default', '0')); + if ($defaultBookSortSetting && SortSet::query()->find($defaultBookSortSetting)) { + $book->sort_set_id = $defaultBookSortSetting; + $book->save(); + } + return $book; } diff --git a/app/Sorting/SortSet.php b/app/Sorting/SortSet.php index 971b3e29a..a73407bfa 100644 --- a/app/Sorting/SortSet.php +++ b/app/Sorting/SortSet.php @@ -3,8 +3,10 @@ namespace BookStack\Sorting; use BookStack\Activity\Models\Loggable; +use BookStack\Entities\Models\Book; use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * @property int $id @@ -41,4 +43,9 @@ class SortSet extends Model implements Loggable { return url("/settings/sorting/sets/{$this->id}"); } + + public function books(): HasMany + { + return $this->hasMany(Book::class); + } } diff --git a/app/Sorting/SortSetController.php b/app/Sorting/SortSetController.php index 0d77bd88f..8f5120791 100644 --- a/app/Sorting/SortSetController.php +++ b/app/Sorting/SortSetController.php @@ -62,7 +62,7 @@ class SortSetController extends Controller $set = SortSet::query()->findOrFail($id); $operations = SortSetOperation::fromSequence($request->input('sequence')); if (count($operations) === 0) { - return redirect()->withInput()->withErrors(['sequence' => 'No operations set.']); + return redirect($set->getUrl())->withInput()->withErrors(['sequence' => 'No operations set.']); } $set->name = $request->input('name'); @@ -78,7 +78,16 @@ class SortSetController extends Controller { $set = SortSet::query()->findOrFail($id); - // TODO - Check if it's in use + if ($set->books()->count() > 0) { + $this->showErrorNotification(trans('settings.sort_set_delete_fail_books')); + return redirect($set->getUrl()); + } + + $defaultBookSortSetting = intval(setting('sorting-book-default', '0')); + if ($defaultBookSortSetting === intval($id)) { + $this->showErrorNotification(trans('settings.sort_set_delete_fail_default')); + return redirect($set->getUrl()); + } $set->delete(); $this->logActivity(ActivityType::SORT_SET_DELETE, $set); diff --git a/database/migrations/2025_02_05_150842_add_sort_set_id_to_books.php b/database/migrations/2025_02_05_150842_add_sort_set_id_to_books.php new file mode 100644 index 000000000..c0b32c552 --- /dev/null +++ b/database/migrations/2025_02_05_150842_add_sort_set_id_to_books.php @@ -0,0 +1,28 @@ +unsignedInteger('sort_set_id')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('books', function (Blueprint $table) { + $table->dropColumn('sort_set_id'); + }); + } +}; diff --git a/lang/en/settings.php b/lang/en/settings.php index cda097590..eb046d278 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -84,6 +84,8 @@ return [ 'sort_set_edit' => 'Edit Sort Set', 'sort_set_delete' => 'Delete Sort Set', 'sort_set_delete_desc' => 'Remove this sort set from the system. Deletion will only go ahead if the sort is not in active use.', + 'sort_set_delete_fail_books' => 'Unable to delete this sort set since it has books assigned.', + 'sort_set_delete_fail_default' => 'Unable to delete this sort set since it\'s used as the default book sort.', 'sort_set_details' => 'Sort Set Details', 'sort_set_details_desc' => 'Set a name for this sort set, which will appear in lists when users are selecting a sort.', 'sort_set_operations' => 'Sort Operations', diff --git a/resources/views/settings/categories/sorting.blade.php b/resources/views/settings/categories/sorting.blade.php index b5d613840..0af3a8fb8 100644 --- a/resources/views/settings/categories/sorting.blade.php +++ b/resources/views/settings/categories/sorting.blade.php @@ -1,5 +1,9 @@ @extends('settings.layout') +@php + $sortSets = \BookStack\Sorting\SortSet::query()->orderBy('name', 'asc')->get(); +@endphp + @section('card')