// Sort our changes from our map to be chapters first
// Since they need to be process to ensure book alignment for child page changes.
$sortMapItems = $sortMap->all();
- usort($sortMapItems, function(BookSortMapItem $itemA, BookSortMapItem $itemB) {
+ usort($sortMapItems, function (BookSortMapItem $itemA, BookSortMapItem $itemB) {
$aScore = $itemA->type === 'page' ? 2 : 1;
$bScore = $itemB->type === 'page' ? 2 : 1;
+
return $aScore - $bScore;
});
return;
}
- $currentParentKey = 'book:' . $model->book_id;
+ $currentParentKey = 'book:' . $model->book_id;
if ($model instanceof Page && $model->chapter_id) {
- $currentParentKey = 'chapter:' . $model->chapter_id;
+ $currentParentKey = 'chapter:' . $model->chapter_id;
}
$currentParent = $modelMap[$currentParentKey] ?? null;
/** @var Book $newBook */
- $newBook = $modelMap['book:' . $sortMapItem->parentBookId];
+ $newBook = $modelMap['book:' . $sortMapItem->parentBookId] ?? null;
/** @var ?Chapter $newChapter */
$newChapter = $sortMapItem->parentChapterId ? ($modelMap['chapter:' . $sortMapItem->parentChapterId] ?? null) : null;
/**
* Check if the current user has permissions to apply the given sorting change.
+ * Is quite complex since items can gain a different parent change. Acts as a:
+ * - Update of old parent element (Change of content/order).
+ * - Update of sorted/moved element.
+ * - Deletion of element (Relative to parent upon move).
+ * - Creation of element within parent (Upon move to new parent).
*/
- protected function isSortChangePermissible(BookSortMapItem $sortMapItem, Entity $model, ?Entity $currentParent, ?Entity $newBook, ?Entity $newChapter): bool
+ protected function isSortChangePermissible(BookSortMapItem $sortMapItem, BookChild $model, ?Entity $currentParent, ?Entity $newBook, ?Entity $newChapter): bool
{
- // TODO - Move operations check for create permissions, Needs these also/instead?
-
// Stop if we can't see the current parent or new book.
if (!$currentParent || !$newBook) {
return false;
}
+ $hasNewParent = $newBook->id !== $model->book_id || ($model instanceof Page && $model->chapter_id !== ($sortMapItem->parentChapterId ?? 0));
if ($model instanceof Chapter) {
$hasPermission = userCan('book-update', $currentParent)
- && userCan('book-update', $newBook);
+ && userCan('book-update', $newBook)
+ && userCan('chapter-update', $model)
+ && (!$hasNewParent || userCan('chapter-create', $newBook))
+ && (!$hasNewParent || userCan('chapter-delete', $model));
+
if (!$hasPermission) {
return false;
}
return false;
}
+ $hasPageEditPermission = userCan('page-update', $model);
$newParentInRightLocation = ($newParent instanceof Book || $newParent->book_id === $newBook->id);
$newParentPermission = ($newParent instanceof Chapter) ? 'chapter-update' : 'book-update';
$hasNewParentPermission = userCan($newParentPermission, $newParent);
- $hasPermission = $hasCurrentParentPermission && $newParentInRightLocation && $hasNewParentPermission;
+ $hasDeletePermissionIfMoving = (!$hasNewParent || userCan('page-delete', $model));
+ $hasCreatePermissionIfMoving = (!$hasNewParent || userCan('page-create', $newParent));
+
+ $hasPermission = $hasCurrentParentPermission
+ && $newParentInRightLocation
+ && $hasNewParentPermission
+ && $hasPageEditPermission
+ && $hasDeletePermissionIfMoving
+ && $hasCreatePermissionIfMoving;
+
if (!$hasPermission) {
return false;
}
/**
* Load models from the database into the given sort map.
+ *
* @return array<string, Entity>
*/
protected function loadModelsFromSortMap(BookSortMap $sortMap): array
$modelMap = [];
$ids = [
'chapter' => [],
- 'page' => [],
- 'book' => [],
+ 'page' => [],
+ 'book' => [],
];
foreach ($sortMap->all() as $sortMapItem) {