diff --git a/app/Actions/Draft/UserDrafts.php b/app/Actions/Draft/UserDrafts.php index c3f7246d..6bbc5ddb 100644 --- a/app/Actions/Draft/UserDrafts.php +++ b/app/Actions/Draft/UserDrafts.php @@ -28,7 +28,7 @@ public function execute(User $user): Collection } /** - * Find existing default draft without files. + * Find existing default draft without files for the user's current team. */ public function findDefaultDraft(User $user): ?Draft { @@ -36,6 +36,7 @@ public function findDefaultDraft(User $user): ?Draft return Draft::doesntHave('files') ->where('owner_id', $user_id) + ->where('team_id', $team_id) ->first(); } diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index eb9e2fc8..603ec3c0 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -81,6 +81,24 @@ public function missingFiles(Request $request, Draft $draft): JsonResponse return response()->json($missingFilesData); } + /** + * Get a single draft by ID with ownership verification. + */ + public function show(Request $request, Draft $draft): JsonResponse + { + /** @var \App\Models\User $user */ + $user = Auth::user(); + [$user_id] = $user->getUserTeamData(); + + if ($draft->owner_id !== $user_id) { + abort(403); + } + + return response()->json([ + 'draft' => $draft->load('Tags'), + ]); + } + /** * Update draft properties. */ diff --git a/resources/js/Pages/Upload.vue b/resources/js/Pages/Upload.vue index 2c70ea5b..1000b5a9 100644 --- a/resources/js/Pages/Upload.vue +++ b/resources/js/Pages/Upload.vue @@ -2581,14 +2581,26 @@ export default { (d) => d.id == this.draft_id ); } + if ( + !selectedDraft && + response.data.default.id == this.draft_id + ) { + selectedDraft = response.data.default; + } if (selectedDraft) { this.selectDraft(selectedDraft); + this.loading = false; } else { - if (response.data.default.id == this.draft_id) { - this.selectDraft(response.data.default); - } + this.fetchDraftById(this.draft_id).then( + (draftResponse) => { + this.selectDraft(draftResponse.data.draft); + this.loading = false; + }, + () => { + this.loading = false; + } + ); } - this.loading = false; } else { alert( "Could not find the draft. Redirecting to the upload page." @@ -2643,6 +2655,9 @@ export default { this.loading = true; return axios.get("/dashboard/drafts"); }, + fetchDraftById(draftId) { + return axios.get("/dashboard/drafts/" + draftId + "/show"); + }, formatStatus(status) { if (!status) return ""; @@ -2800,9 +2815,10 @@ export default { } else if (id == 2) { this.updateDraft(null, 2); this.$nextTick(function () { - // if (this.$refs.spectraEditorREF) { - // this.$refs.spectraEditorREF.registerEvents(); - // } + this.setQueryStringParameter( + "draft_id", + this.currentDraft.id + ); this.setQueryStringParameter("step", 2); this.step = "2"; this.fetchValidations(); diff --git a/routes/web.php b/routes/web.php index 66cb84a7..26a765e4 100644 --- a/routes/web.php +++ b/routes/web.php @@ -295,6 +295,8 @@ Route::post('datasets/{dataset}/snapshot', [DatasetController::class, 'snapshot']) ->name('dashboard.dataset.snapshot'); + Route::get('drafts/{draft}/show', [DraftController::class, 'show']) + ->name('dashboard.draft.show'); Route::get('drafts/{draft}/info', [DraftController::class, 'info']) ->name('dashboard.draft.info'); Route::get('drafts/{draft}/files', [DraftController::class, 'files']) diff --git a/tests/Feature/DraftFeatureTest.php b/tests/Feature/DraftFeatureTest.php index b02f0ae8..0a194234 100644 --- a/tests/Feature/DraftFeatureTest.php +++ b/tests/Feature/DraftFeatureTest.php @@ -285,6 +285,35 @@ public function test_nonexistent_draft_returns_404(): void $response->assertStatus(404); } + public function test_owner_can_show_draft(): void + { + $response = $this->actingAs($this->user) + ->get("/dashboard/drafts/{$this->draft->id}/show"); + + $response->assertStatus(200); + + $responseData = $response->json(); + $this->assertArrayHasKey('draft', $responseData); + $this->assertEquals($this->draft->id, $responseData['draft']['id']); + } + + public function test_show_draft_returns_403_for_non_owner(): void + { + $otherUser = User::factory()->withPersonalTeam()->create(); + + $response = $this->actingAs($otherUser) + ->get("/dashboard/drafts/{$this->draft->id}/show"); + + $response->assertStatus(403); + } + + public function test_show_draft_requires_authentication(): void + { + $response = $this->get("/dashboard/drafts/{$this->draft->id}/show"); + + $response->assertStatus(302); + } + public function test_draft_processed_mail_can_be_rendered(): void { $project = Project::factory()->create([