diff --git a/backend/app/Controllers/ElementController.php b/backend/app/Controllers/ElementController.php index 0101dea..36528d4 100644 --- a/backend/app/Controllers/ElementController.php +++ b/backend/app/Controllers/ElementController.php @@ -9,8 +9,6 @@ use App\Element\UseCases\DeleteChildElement\DeleteChildElement; use App\Element\UseCases\DeleteChildElement\DeleteChildElementRequest; use App\Element\UseCases\GetElement\GetElement; use App\Element\UseCases\GetElement\GetElementRequest; -use App\Element\UseCases\ReorderChildElements\ReorderChildElements; -use App\Element\UseCases\ReorderChildElements\ReorderChildElementsRequest; use App\Element\UseCases\UpdateElement\UpdateElement; use App\Element\UseCases\UpdateElement\UpdateElementRequest; use App\Exceptions\BadRequestException; @@ -26,7 +24,6 @@ class ElementController private GetElement $getElement, private CreateChildElement $createChildElement, private DeleteChildElement $deleteChildElement, - private ReorderChildElements $reorderChildElements, private UpdateElement $updateElement, private FileUploader $fileUploader, ) { @@ -107,37 +104,6 @@ class ElementController return new JsonResponse(null, 204); } - public function reorderChildren( - Request $request, - ?int $parentId, - ): JsonResponse { - try { - $childElements = $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: $parentId, - childElementIds: $this->intArrayInput( - $request, - 'childElementIds', - ), - ) - ); - } catch (BadRequestException $exception) { - return new JsonResponse([ - 'error' => $exception->getMessage(), - ], 400); - } catch (NotFoundException $exception) { - return new JsonResponse([ - 'error' => $exception->getMessage(), - ], 404); - } - - return new JsonResponse([ - 'childElements' => $this->buildElementSummaryPayloads( - $childElements, - ), - ], 200); - } - public function update(Request $request): JsonResponse { $file = $this->uploadedFileInput($request, 'file'); @@ -192,38 +158,6 @@ class ElementController return null; } - /** - * @return int[]|null - */ - private function intArrayInput(Request $request, string $key): ?array - { - if (! $request->exists($key)) { - return null; - } - - $value = $request->input($key); - if (! is_array($value)) { - return null; - } - - $integerValues = []; - foreach ($value as $item) { - if (is_int($item)) { - $integerValues[] = $item; - continue; - } - - if (is_string($item) && ctype_digit($item)) { - $integerValues[] = (int) $item; - continue; - } - - return null; - } - - return $integerValues; - } - private function stringInput(Request $request, string $key): ?string { if (! $request->exists($key)) { diff --git a/backend/app/Element/ElementModel.php b/backend/app/Element/ElementModel.php index dfd12b1..3a8a435 100644 --- a/backend/app/Element/ElementModel.php +++ b/backend/app/Element/ElementModel.php @@ -16,7 +16,6 @@ use Illuminate\Database\Eloquent\Model; * @property string|null $long_pdf_path * @property string|null $youtube_url * @property int|null $parent_element_id - * @property int $sort_order * * @method static Builder|ElementModel newModelQuery() * @method static Builder|ElementModel newQuery() @@ -31,7 +30,6 @@ use Illuminate\Database\Eloquent\Model; * @method static Builder|ElementModel whereShortPdfPath($value) * @method static Builder|ElementModel whereLongPdfPath($value) * @method static Builder|ElementModel whereYoutubeUrl($value) - * @method static Builder|ElementModel whereSortOrder($value) * * @mixin \Eloquent */ @@ -51,12 +49,10 @@ class ElementModel extends Model 'long_pdf_path', 'youtube_url', 'parent_element_id', - 'sort_order', ]; protected $casts = [ 'set_id' => 'integer', 'parent_element_id' => 'integer', - 'sort_order' => 'integer', ]; } diff --git a/backend/app/Element/ElementRepository.php b/backend/app/Element/ElementRepository.php index e1f84e4..f759322 100644 --- a/backend/app/Element/ElementRepository.php +++ b/backend/app/Element/ElementRepository.php @@ -25,13 +25,4 @@ interface ElementRepository * @return Element[] */ public function findByParentElement(Element $parentElement): array; - - /** - * @param int[] $childElementIds - * @return Element[] - */ - public function reorderChildren( - Element $parentElement, - array $childElementIds, - ): array; } diff --git a/backend/app/Element/EloquentElementRepository.php b/backend/app/Element/EloquentElementRepository.php index f585eb1..77a110b 100644 --- a/backend/app/Element/EloquentElementRepository.php +++ b/backend/app/Element/EloquentElementRepository.php @@ -5,7 +5,6 @@ namespace App\Element; use App\Set\Set as DomainSet; use App\Set\SetRepository; use DomainException; -use Illuminate\Support\Facades\DB; class EloquentElementRepository implements ElementRepository { @@ -15,7 +14,6 @@ class EloquentElementRepository implements ElementRepository public function create(CreateElementDto $dto): Element { - $parentElementId = $dto->parentElement?->getId(); $model = ElementModel::create([ 'set_id' => $dto->set->getId(), 'title' => $dto->title, @@ -25,8 +23,7 @@ class EloquentElementRepository implements ElementRepository 'short_pdf_path' => $dto->shortPdfPath, 'long_pdf_path' => $dto->longPdfPath, 'youtube_url' => $dto->youtubeUrl, - 'parent_element_id' => $parentElementId, - 'sort_order' => $this->nextSortOrder($dto->set, $parentElementId), + 'parent_element_id' => $dto->parentElement?->getId(), ]); return new Element( @@ -89,7 +86,6 @@ class EloquentElementRepository implements ElementRepository { $model = ElementModel::where('set_id', $set->getId()) ->whereNull('parent_element_id') - ->orderBy('sort_order') ->orderBy('id') ->first(); @@ -121,7 +117,6 @@ class EloquentElementRepository implements ElementRepository 'parent_element_id', $parentElement->getId(), ) - ->orderBy('sort_order') ->orderBy('id') ->get(); $elements = []; @@ -132,46 +127,6 @@ class EloquentElementRepository implements ElementRepository return $elements; } - /** - * @param int[] $childElementIds - * @return Element[] - */ - public function reorderChildren( - Element $parentElement, - array $childElementIds, - ): array { - DB::transaction(function () use ($parentElement, $childElementIds) { - $sortOrder = 1; - foreach ($childElementIds as $childElementId) { - ElementModel::where('id', $childElementId) - ->where('parent_element_id', $parentElement->getId()) - ->update(['sort_order' => $sortOrder]); - $sortOrder++; - } - }); - - return $this->findByParentElement($parentElement); - } - - private function nextSortOrder( - DomainSet $set, - ?int $parentElementId, - ): int { - $query = ElementModel::where('set_id', $set->getId()); - if ($parentElementId === null) { - $query->whereNull('parent_element_id'); - } else { - $query->where('parent_element_id', $parentElementId); - } - - $currentMaxSortOrder = $query->max('sort_order'); - if ($currentMaxSortOrder === null) { - return 1; - } - - return (int) $currentMaxSortOrder + 1; - } - private function toDomain(ElementModel $model): Element { $set = $this->setRepo->find($model->set_id); diff --git a/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElements.php b/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElements.php deleted file mode 100644 index 45d94c0..0000000 --- a/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElements.php +++ /dev/null @@ -1,154 +0,0 @@ -parentElementId === null) { - throw new BadRequestException('parentElementId is required'); - } - - if ($request->childElementIds === null) { - throw new BadRequestException('childElementIds is required'); - } - - $parentElement = $this->elementRepository->find( - $request->parentElementId, - ); - if ($parentElement === null) { - throw new NotFoundException('Parent element not found'); - } - - $childElementIds = $this->validatedChildElementIds( - $request->childElementIds, - ); - $directChildElementIds = $this->elementIds( - $this->elementRepository->findByParentElement($parentElement), - ); - - $this->validateNoDuplicateIds($childElementIds); - $this->validateAllIdsAreDirectChildren( - $childElementIds, - $directChildElementIds, - ); - $this->validateEveryDirectChildWasSubmitted( - $childElementIds, - $directChildElementIds, - ); - - return $this->elementRepository->reorderChildren( - $parentElement, - $childElementIds, - ); - } - - /** - * @param mixed[] $childElementIds - * @return int[] - * @throws BadRequestException - */ - private function validatedChildElementIds(array $childElementIds): array - { - $validatedChildElementIds = []; - foreach ($childElementIds as $childElementId) { - if (! is_int($childElementId)) { - throw new BadRequestException( - 'childElementIds must contain integers', - ); - } - - $validatedChildElementIds[] = $childElementId; - } - - return $validatedChildElementIds; - } - - /** - * @param int[] $childElementIds - * @throws BadRequestException - */ - private function validateNoDuplicateIds(array $childElementIds): void - { - $seenChildElementIds = []; - foreach ($childElementIds as $childElementId) { - if (isset($seenChildElementIds[$childElementId])) { - throw new BadRequestException( - 'Child order contains duplicate ids', - ); - } - - $seenChildElementIds[$childElementId] = true; - } - } - - /** - * @param int[] $childElementIds - * @param int[] $directChildElementIds - * @throws BadRequestException - */ - private function validateAllIdsAreDirectChildren( - array $childElementIds, - array $directChildElementIds, - ): void { - $directChildElementIdsById = []; - foreach ($directChildElementIds as $directChildElementId) { - $directChildElementIdsById[$directChildElementId] = true; - } - - foreach ($childElementIds as $childElementId) { - if (! isset($directChildElementIdsById[$childElementId])) { - throw new BadRequestException( - 'Child order contains invalid child', - ); - } - } - } - - /** - * @param int[] $childElementIds - * @param int[] $directChildElementIds - * @throws BadRequestException - */ - private function validateEveryDirectChildWasSubmitted( - array $childElementIds, - array $directChildElementIds, - ): void { - if (count($childElementIds) === count($directChildElementIds)) { - return; - } - - throw new BadRequestException( - 'Child order must include every direct child', - ); - } - - /** - * @param Element[] $elements - * @return int[] - */ - private function elementIds(array $elements): array - { - $elementIds = []; - foreach ($elements as $element) { - $elementIds[] = $element->getId(); - } - - return $elementIds; - } -} diff --git a/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElementsRequest.php b/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElementsRequest.php deleted file mode 100644 index d8e3267..0000000 --- a/backend/app/Element/UseCases/ReorderChildElements/ReorderChildElementsRequest.php +++ /dev/null @@ -1,15 +0,0 @@ - ['api/*'], - 'allowed_methods' => [ - 'GET', - 'POST', - 'PATCH', - 'OPTIONS', - 'DELETE', - 'PUT', - ], + 'allowed_methods' => ['GET', 'POST', 'PATCH', 'OPTIONS', 'DELETE'], 'allowed_origins' => $allowedOrigins, 'allowed_origins_patterns' => [], 'allowed_headers' => [ diff --git a/backend/database/migrations/2026_05_24_000001_elements_table.php b/backend/database/migrations/2026_05_24_000001_elements_table.php index 030593c..1941e03 100644 --- a/backend/database/migrations/2026_05_24_000001_elements_table.php +++ b/backend/database/migrations/2026_05_24_000001_elements_table.php @@ -21,7 +21,6 @@ return new class extends Migration $table->foreignId('parent_element_id') ->nullable() ->constrained('elements'); - $table->unsignedInteger('sort_order'); }); } diff --git a/backend/routes/api.php b/backend/routes/api.php index f084592..1eb4ef1 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -17,11 +17,6 @@ Route::post('/elements/{parentId}/children', [ 'createChild', ]) ->middleware(AuthMiddleware::class); -Route::put('/elements/{parentId}/children/order', [ - ElementController::class, - 'reorderChildren', -]) - ->middleware(AuthMiddleware::class); Route::delete('/elements/{parentId}/children/{childId}', [ ElementController::class, 'deleteChild', diff --git a/backend/tests/Fakes/FakeElementRepository.php b/backend/tests/Fakes/FakeElementRepository.php index 41eaa74..4e08547 100644 --- a/backend/tests/Fakes/FakeElementRepository.php +++ b/backend/tests/Fakes/FakeElementRepository.php @@ -14,11 +14,6 @@ class FakeElementRepository implements ElementRepository */ private array $elementsById = []; - /** - * @var array - */ - private array $sortOrdersById = []; - public function create(CreateElementDto $dto): Element { $id = count($this->elementsById) + 1; @@ -35,9 +30,6 @@ class FakeElementRepository implements ElementRepository parentElement: $dto->parentElement, ); $this->elementsById[$id] = $element; - $this->sortOrdersById[$id] = $this->nextSortOrder( - $dto->parentElement, - ); return $element; } @@ -53,7 +45,6 @@ class FakeElementRepository implements ElementRepository public function delete(Element $element): void { unset($this->elementsById[$element->getId()]); - unset($this->sortOrdersById[$element->getId()]); } public function find(int $id): ?Element @@ -109,43 +100,10 @@ class FakeElementRepository implements ElementRepository $elements[] = $this->cloneElement($element); } } - usort($elements, function ( - Element $firstElement, - Element $secondElement, - ): int { - $firstSortOrder = $this->sortOrdersById[ - $firstElement->getId() - ] ?? $firstElement->getId(); - $secondSortOrder = $this->sortOrdersById[ - $secondElement->getId() - ] ?? $secondElement->getId(); - if ($firstSortOrder === $secondSortOrder) { - return $firstElement->getId() <=> $secondElement->getId(); - } - - return $firstSortOrder <=> $secondSortOrder; - }); return $elements; } - /** - * @param int[] $childElementIds - * @return Element[] - */ - public function reorderChildren( - Element $parentElement, - array $childElementIds, - ): array { - $sortOrder = 1; - foreach ($childElementIds as $childElementId) { - $this->sortOrdersById[$childElementId] = $sortOrder; - $sortOrder++; - } - - return $this->findByParentElement($parentElement); - } - private function cloneElement(Element $element): Element { $parentElement = $element->getParentElement(); @@ -166,24 +124,4 @@ class FakeElementRepository implements ElementRepository parentElement: $parentElement, ); } - - private function nextSortOrder(?Element $parentElement): int - { - $parentElementId = $parentElement?->getId(); - $nextSortOrder = 1; - foreach ($this->elementsById as $element) { - $currentParentElement = $element->getParentElement(); - $currentParentElementId = $currentParentElement?->getId(); - if ($currentParentElementId !== $parentElementId) { - continue; - } - - $currentSortOrder = $this->sortOrdersById[$element->getId()] ?? 0; - if ($currentSortOrder >= $nextSortOrder) { - $nextSortOrder = $currentSortOrder + 1; - } - } - - return $nextSortOrder; - } } diff --git a/backend/tests/Feature/ElementsEndpointTest.php b/backend/tests/Feature/ElementsEndpointTest.php index 329e932..a914dd9 100644 --- a/backend/tests/Feature/ElementsEndpointTest.php +++ b/backend/tests/Feature/ElementsEndpointTest.php @@ -297,234 +297,6 @@ class ElementsEndpointTest extends TestCase ); } - public function testReorderChildElementsRequiresAuthentication(): void - { - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $this->createSet($setRepository); - $parentElement = $this->createElement( - $elementRepository, - $set, - 'Baderech HaAvodah', - 'A structured path for growth', - null, - '

A structured path for growth

', - null, - null, - null, - null, - ); - $firstChildElement = $this->createElement( - $elementRepository, - $set, - 'First child', - 'First child description', - null, - '', - null, - null, - null, - $parentElement, - ); - - $response = $this->putJson( - "/api/elements/{$parentElement->getId()}/children/order", - [ - 'childElementIds' => [$firstChildElement->getId()], - ], - ); - - $response->assertUnauthorized(); - $response->assertExactJson([ - 'error' => 'unauthenticated', - ]); - } - - public function testAuthenticatedReorderChildElementsPersistsOrder(): void - { - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $this->createSet($setRepository); - $parentElement = $this->createElement( - $elementRepository, - $set, - 'Baderech HaAvodah', - 'A structured path for growth', - null, - '

A structured path for growth

', - null, - null, - null, - null, - ); - $firstChildElement = $this->createElement( - $elementRepository, - $set, - 'First child', - 'First child description', - null, - '', - null, - null, - null, - $parentElement, - ); - $secondChildElement = $this->createElement( - $elementRepository, - $set, - 'Second child', - 'Second child description', - null, - '', - null, - null, - null, - $parentElement, - ); - $thirdChildElement = $this->createElement( - $elementRepository, - $set, - 'Third child', - 'Third child description', - null, - '', - null, - null, - null, - $parentElement, - ); - $this->createSession('valid-token'); - - $response = $this->withCredentials() - ->withUnencryptedCookie('auth_token', 'valid-token') - ->putJson( - "/api/elements/{$parentElement->getId()}/children/order", - [ - 'childElementIds' => [ - $thirdChildElement->getId(), - $firstChildElement->getId(), - $secondChildElement->getId(), - ], - ], - ); - - $response->assertOk(); - $response->assertExactJson([ - 'childElements' => [ - [ - 'id' => $thirdChildElement->getId(), - 'title' => 'Third child', - 'description' => 'Third child description', - ], - [ - 'id' => $firstChildElement->getId(), - 'title' => 'First child', - 'description' => 'First child description', - ], - [ - 'id' => $secondChildElement->getId(), - 'title' => 'Second child', - 'description' => 'Second child description', - ], - ], - ]); - - $this->getJson("/api/elements/{$parentElement->getId()}") - ->assertJsonPath('childElements.0.id', $thirdChildElement->getId()) - ->assertJsonPath('childElements.1.id', $firstChildElement->getId()) - ->assertJsonPath( - 'childElements.2.id', - $secondChildElement->getId(), - ); - $this->getJson("/api/elements/{$thirdChildElement->getId()}") - ->assertJsonPath( - 'siblingElements.0.id', - $thirdChildElement->getId(), - ) - ->assertJsonPath( - 'siblingElements.1.id', - $firstChildElement->getId(), - ) - ->assertJsonPath( - 'siblingElements.2.id', - $secondChildElement->getId(), - ); - } - - public function testAuthenticatedReorderRejectsNestedChildElement(): void - { - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $this->createSet($setRepository); - $parentElement = $this->createElement( - $elementRepository, - $set, - 'Baderech HaAvodah', - 'A structured path for growth', - null, - '

A structured path for growth

', - null, - null, - null, - null, - ); - $firstChildElement = $this->createElement( - $elementRepository, - $set, - 'First child', - 'First child description', - null, - '', - null, - null, - null, - $parentElement, - ); - $secondChildElement = $this->createElement( - $elementRepository, - $set, - 'Second child', - 'Second child description', - null, - '', - null, - null, - null, - $parentElement, - ); - $nestedChildElement = $this->createElement( - $elementRepository, - $set, - 'Nested child', - 'Nested child description', - null, - '', - null, - null, - null, - $firstChildElement, - ); - $this->createSession('valid-token'); - - $response = $this->withCredentials() - ->withUnencryptedCookie('auth_token', 'valid-token') - ->putJson( - "/api/elements/{$parentElement->getId()}/children/order", - [ - 'childElementIds' => [ - $firstChildElement->getId(), - $nestedChildElement->getId(), - $secondChildElement->getId(), - ], - ], - ); - - $response->assertBadRequest(); - $response->assertExactJson([ - 'error' => 'Child order contains invalid child', - ]); - } - public function testDeleteChildRequiresAuthentication(): void { $setRepository = app(SetRepository::class); diff --git a/backend/tests/Unit/Controllers/ElementControllerTest.php b/backend/tests/Unit/Controllers/ElementControllerTest.php index 7704306..c32ac21 100644 --- a/backend/tests/Unit/Controllers/ElementControllerTest.php +++ b/backend/tests/Unit/Controllers/ElementControllerTest.php @@ -8,7 +8,6 @@ use App\Element\Element; use App\Element\UseCases\CreateChildElement\CreateChildElement; use App\Element\UseCases\DeleteChildElement\DeleteChildElement; use App\Element\UseCases\GetElement\GetElement; -use App\Element\UseCases\ReorderChildElements\ReorderChildElements; use App\Element\UseCases\UpdateElement\UpdateDescription; use App\Element\UseCases\UpdateElement\UpdateElement; use App\Element\UseCases\UpdateElement\UpdateIconImage; @@ -66,7 +65,6 @@ class ElementControllerTest extends TestCase $getElement, new CreateChildElement($this->elementRepo), new DeleteChildElement($this->elementRepo, $this->fileUploader), - new ReorderChildElements($this->elementRepo), $updateElement, $this->fileUploader, ); diff --git a/backend/tests/Unit/Element/UseCases/ReorderChildElementsTest.php b/backend/tests/Unit/Element/UseCases/ReorderChildElementsTest.php deleted file mode 100644 index 1b4829f..0000000 --- a/backend/tests/Unit/Element/UseCases/ReorderChildElementsTest.php +++ /dev/null @@ -1,237 +0,0 @@ -elementRepository = new FakeElementRepository(); - $this->reorderChildElements = new ReorderChildElements( - $this->elementRepository, - ); - } - - public function testReordersDirectChildElements(): void - { - $set = $this->createSet(1, 'Baderech'); - $parentElement = $this->createElement($set, 'Parent', null); - $firstChildElement = $this->createElement( - $set, - 'First child', - $parentElement, - ); - $secondChildElement = $this->createElement( - $set, - 'Second child', - $parentElement, - ); - $thirdChildElement = $this->createElement( - $set, - 'Third child', - $parentElement, - ); - $this->createElement($set, 'Nested child', $firstChildElement); - - $childElements = $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: $parentElement->getId(), - childElementIds: [ - $thirdChildElement->getId(), - $firstChildElement->getId(), - $secondChildElement->getId(), - ], - ) - ); - - $this->assertSame( - [ - $thirdChildElement->getId(), - $firstChildElement->getId(), - $secondChildElement->getId(), - ], - $this->elementIds($childElements), - ); - $this->assertSame( - [ - $thirdChildElement->getId(), - $firstChildElement->getId(), - $secondChildElement->getId(), - ], - $this->elementIds( - $this->elementRepository->findByParentElement($parentElement), - ), - ); - } - - public function testThrowsWhenParentElementIsMissing(): void - { - $this->expectException(NotFoundException::class); - $this->expectExceptionMessage('Parent element not found'); - - $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: 999, - childElementIds: [1, 2], - ) - ); - } - - public function testThrowsWhenChildIdsAreMissing(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('childElementIds is required'); - - $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: 1, - childElementIds: null, - ) - ); - } - - public function testThrowsWhenChildOrderHasDuplicates(): void - { - $set = $this->createSet(1, 'Baderech'); - $parentElement = $this->createElement($set, 'Parent', null); - $firstChildElement = $this->createElement( - $set, - 'First child', - $parentElement, - ); - $secondChildElement = $this->createElement( - $set, - 'Second child', - $parentElement, - ); - - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('Child order contains duplicate ids'); - - $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: $parentElement->getId(), - childElementIds: [ - $firstChildElement->getId(), - $firstChildElement->getId(), - $secondChildElement->getId(), - ], - ) - ); - } - - public function testThrowsWhenChildOrderHasInvalidElement(): void - { - $set = $this->createSet(1, 'Baderech'); - $parentElement = $this->createElement($set, 'Parent', null); - $firstChildElement = $this->createElement( - $set, - 'First child', - $parentElement, - ); - $secondChildElement = $this->createElement( - $set, - 'Second child', - $parentElement, - ); - $nestedChildElement = $this->createElement( - $set, - 'Nested child', - $firstChildElement, - ); - - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('Child order contains invalid child'); - - $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: $parentElement->getId(), - childElementIds: [ - $firstChildElement->getId(), - $nestedChildElement->getId(), - $secondChildElement->getId(), - ], - ) - ); - } - - public function testThrowsWhenChildOrderOmitsDirectChild(): void - { - $set = $this->createSet(1, 'Baderech'); - $parentElement = $this->createElement($set, 'Parent', null); - $firstChildElement = $this->createElement( - $set, - 'First child', - $parentElement, - ); - $this->createElement($set, 'Second child', $parentElement); - - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage( - 'Child order must include every direct child', - ); - - $this->reorderChildElements->execute( - new ReorderChildElementsRequest( - parentElementId: $parentElement->getId(), - childElementIds: [$firstChildElement->getId()], - ) - ); - } - - private function createSet(int $id, string $name): DomainSet - { - return new DomainSet( - id: $id, - name: $name, - description: "$name description", - iconImageUrl: '/assets/baderech-icon.png', - ); - } - - private function createElement( - DomainSet $set, - string $title, - ?Element $parentElement, - ): Element { - return $this->elementRepository->create(new CreateElementDto( - set: $set, - title: $title, - description: "$title description", - iconImageUrl: null, - richText: '', - shortPdfPath: null, - longPdfPath: null, - youtubeUrl: null, - parentElement: $parentElement, - )); - } - - /** - * @param Element[] $elements - * @return int[] - */ - private function elementIds(array $elements): array - { - $elementIds = []; - foreach ($elements as $element) { - $elementIds[] = $element->getId(); - } - - return $elementIds; - } -} diff --git a/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts index ab70619..8c1f7f3 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts @@ -191,46 +191,6 @@ describe('admin element editing', () => { cy.resetDb() }) - it('reorders child elements through admin controls', () => { - cy.resetDb() - loginAsAdmin() - cy.visit('/admin/element/1') - cy.intercept('PUT', /\/api\/elements\/1\/children\/order$/) - .as('reorderChildElements') - - cy.contains('[data-cy="admin-child-item"]', '2. Foundations') - .within(() => { - cy.get('[data-cy="admin-move-child-up"]').click() - }) - cy.wait('@reorderChildElements') - - cy.get('[data-cy="admin-child-status"]') - .should('be.visible') - .and('contain.text', 'Child order saved') - cy.get('[data-cy="admin-child-item"]') - .eq(0) - .should('contain.text', '2. Foundations') - cy.get('[data-cy="admin-child-item"]') - .eq(1) - .should('contain.text', '1. Introduction') - - cy.contains('header.site-header a', 'View Element').click() - cy.get('[data-cy="child-element-link"]') - .eq(0) - .should('contain.text', '2. Foundations') - cy.get('[data-cy="child-element-link"]') - .eq(1) - .should('contain.text', '1. Introduction') - - cy.visit('/element/3') - cy.get('[data-cy="element-sibling-previous"]') - .should('have.attr', 'href', '/element/7') - cy.get('[data-cy="element-sibling-next"]') - .should('have.attr', 'href', '/element/2') - - cy.resetDb() - }) - it('uploads icon and pdf files immediately through the UI', () => { cy.resetDb() loginAsAdmin() diff --git a/frontend/rabbi_gerzi/src/stores/elements.ts b/frontend/rabbi_gerzi/src/stores/elements.ts index 074ba04..5118f39 100644 --- a/frontend/rabbi_gerzi/src/stores/elements.ts +++ b/frontend/rabbi_gerzi/src/stores/elements.ts @@ -38,10 +38,6 @@ interface UpdateElementResponse { element: Element } -interface ReorderChildElementsResponse { - childElements: ChildElement[] -} - interface ElementPatchInput { title?: string description?: string @@ -149,34 +145,6 @@ export const useElementsStore = defineStore('elements', () => { } } - async function reorderChildElements( - parentElementId: string, - childElementIds: number[], - ): Promise { - childActionError.value = null - isManagingChildren.value = true - - try { - const encodedParentElementId = encodeURIComponent(parentElementId) - const response = await fetch( - `${ELEMENTS_URL}/${encodedParentElementId}/children/order`, - { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - credentials: 'include', - body: JSON.stringify({ childElementIds }), - }, - ) - - return await handleReorderChildElementsResponse(response) - } catch { - childActionError.value = 'Network error - could not save child order' - return false - } finally { - isManagingChildren.value = false - } - } - async function deleteChildElement( parentElementId: string, childElementId: number, @@ -382,32 +350,6 @@ export const useElementsStore = defineStore('elements', () => { return data.element } - async function handleReorderChildElementsResponse( - response: Response, - ): Promise { - if (response.status === 401) { - childActionError.value = 'Please log in again' - return false - } - - if (response.status === 400 || response.status === 404) { - childActionError.value = await errorMessage( - response, - 'Could not save child order', - ) - return false - } - - if (!response.ok) { - childActionError.value = 'Could not save child order' - return false - } - - const data: ReorderChildElementsResponse = await response.json() - childElements.value = data.childElements - return true - } - async function handleDeleteChildElementResponse( response: Response, childElementId: number, @@ -464,7 +406,6 @@ export const useElementsStore = defineStore('elements', () => { fetchElement, updateElement, createChildElement, - reorderChildElements, deleteChildElement, uploadElementIconImage, uploadElementShortPdf, diff --git a/frontend/rabbi_gerzi/src/views/AdminElementPage.vue b/frontend/rabbi_gerzi/src/views/AdminElementPage.vue index 2c66cfc..29f66fe 100644 --- a/frontend/rabbi_gerzi/src/views/AdminElementPage.vue +++ b/frontend/rabbi_gerzi/src/views/AdminElementPage.vue @@ -1,18 +1,12 @@