Skip to content
3 changes: 2 additions & 1 deletion app/Actions/Draft/UserDrafts.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ 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
{
[$user_id, $team_id] = $user->getUserTeamData();

return Draft::doesntHave('files')
->where('owner_id', $user_id)
->where('team_id', $team_id)
->first();
}

Expand Down
18 changes: 18 additions & 0 deletions app/Http/Controllers/DraftController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
30 changes: 23 additions & 7 deletions resources/js/Pages/Upload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down Expand Up @@ -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 "";

Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand Down
29 changes: 29 additions & 0 deletions tests/Feature/DraftFeatureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
Loading