Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app/Actions/Draft/FindOrCreateDraftStudy.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public function execute(FileSystemObject $folder, Draft $draft, Project $project
if (! $study) {
$study = $this->createNewStudy($folder, $draft, $project, $validation);
$this->updateFolderWithStudy($folder, $study);
} else {
$this->reassignStudyToProject($study, $project);
}

return $study;
Expand Down Expand Up @@ -66,4 +68,20 @@ private function updateFolderWithStudy(FileSystemObject $folder, Study $study):
$folder->study_id = $study->id;
$folder->save();
}

/**
* Keep an existing study on the project this process run is using.
*/
private function reassignStudyToProject(Study $study, Project $project): void
{
if ($study->project_id === $project->id) {
return;
}

$study->project_id = $project->id;
$study->save();

$study->sample()->update(['project_id' => $project->id]);
$study->datasets()->update(['project_id' => $project->id]);
}
}
52 changes: 46 additions & 6 deletions app/Actions/Draft/ProcessDraft.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use App\Models\Validation;
use App\Support\Draft\HifsaPdfResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
Expand All @@ -36,7 +35,7 @@ public function __construct(
/**
* Process draft and create project structure.
*/
public function execute(Request $request, Draft $draft, User $user): Response|JsonResponse|RedirectResponse
public function execute(Request $request, Draft $draft, User $user): Response|JsonResponse
{
[$user_id, $team_id, $team] = $user->getUserTeamData();

Expand Down Expand Up @@ -94,7 +93,7 @@ private function prepareDraft(Request $request, Draft $draft): void
*/
public function createOrUpdateProject(Draft $draft, int $user_id, int $team_id, $user, $team): Project
{
$project = Project::where('draft_id', $draft->id)->first();
$project = $this->resolveDraftProject($draft);

if (! $project) {
$project = $this->createNewProject($draft, $user_id, $team_id, $user, $team);
Expand All @@ -105,6 +104,40 @@ public function createOrUpdateProject(Draft $draft, int $user_id, int $team_id,
return $project;
}

/**
* Pick the existing project for this draft.
*
* A draft can accumulate more than one project row (retries, concurrent
* process requests). `first()` without an order then often returns an
* empty newer project while studies still belong to an older one, so
* finalizeProcessing sees zero studies and redirects.
*/
public function resolveDraftProject(Draft $draft): ?Project
{
$studyProjectId = Study::query()
->where('draft_id', $draft->id)
->whereNotNull('project_id')
->value('project_id');

if ($studyProjectId) {
$project = Project::query()->find($studyProjectId);

if ($project) {
if ($project->draft_id !== $draft->id) {
$project->draft_id = $draft->id;
$project->save();
}

return $project;
}
}

return Project::query()
->where('draft_id', $draft->id)
->orderBy('id')
->first();
}

/**
* Create a new project from draft.
*/
Expand Down Expand Up @@ -363,16 +396,23 @@ public function createDatasetFromOrphanedFile(FileSystemObject $folder, Study $s
/**
* Finalize processing and return response.
*/
public function finalizeProcessing(Draft $draft, Project $project): Response|JsonResponse|RedirectResponse
public function finalizeProcessing(Draft $draft, Project $project): Response|JsonResponse
{
$draft->save();

$studies = $project->studies()->orderBy('name')->get()->load(['datasets', 'sample.molecules', 'tags']);
$this->hifsaPdfResolver->persistCsvData($studies);
$studies = $this->hifsaPdfResolver->enrichStudies($studies, $draft);

if (count($studies) == 0) {
return redirect()->back()->withErrors(['studies' => 'nmrXiv requires raw or processed raw instrument output files. If you data is from a single sample organise all the files in one folder and click proceed. If you have multiple samples, group your data in subfolders with each subfolder corresponding to a sample. Thank you.']);
if ($studies->isEmpty()) {
$message = 'nmrXiv requires raw or processed raw instrument output files. If you data is from a single sample organise all the files in one folder and click proceed. If you have multiple samples, group your data in subfolders with each subfolder corresponding to a sample. Thank you.';

return response()->json([
'message' => $message,
'errors' => [
'studies' => [$message],
],
], 422);
}

Log::info('Finalizing processing for draft '.$draft->id);
Expand Down
4 changes: 2 additions & 2 deletions app/Actions/Project/PublishEmbargoProject.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private function validateForPublication(Project $project, bool $restoreReleaseDa
$project->release_date = now()->startOfDay()->toDateString();
$project->save();

$validation->process();
$validation->process(project: $project);
$publishAttemptValidation = $validation->fresh();

if (! $publishAttemptValidation['report']['project']['status']) {
Expand All @@ -113,7 +113,7 @@ private function validateForPublication(Project $project, bool $restoreReleaseDa
$project->refresh();

if ($project->validation) {
$project->validation->process();
$project->validation->process(project: $project);
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/Actions/Project/UpdateProject.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public function update(Project $project, array $input)
}
}
}
$validation->process();
$validation->process(project: $project);

$project = $project->fresh();

Expand Down
21 changes: 10 additions & 11 deletions app/Http/Controllers/DraftController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use App\Support\ProvisionalDoi;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
Expand Down Expand Up @@ -67,10 +66,8 @@ public function all(Request $request): JsonResponse

/**
* Process draft and convert to project structure.
*
* @return Response|JsonResponse|RedirectResponse
*/
public function process(Request $request, Draft $draft)
public function process(Request $request, Draft $draft): Response|JsonResponse
{
$this->authorize('updateDraft', $draft);

Expand Down Expand Up @@ -176,7 +173,7 @@ public function complete(Request $request, Draft $draft): JsonResponse
{
$this->authorize('updateDraft', $draft);

$project = Project::where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
return response()->json([
Expand All @@ -186,10 +183,12 @@ public function complete(Request $request, Draft $draft): JsonResponse
}

$validation = $project->validation;
$validation->process();
$validation->process(project: $project);

$project->load(['studies.datasets', 'owner', 'citations', 'authors', 'tags']);

return response()->json([
'project' => Project::with(['studies.datasets', 'owner', 'citations', 'authors', 'tags'])->where('draft_id', $draft->id)->first(),
'project' => $project,
'validation' => $validation,
]);
}
Expand All @@ -201,7 +200,7 @@ public function info(Request $request, Draft $draft): JsonResponse
{
$this->authorize('updateDraft', $draft);

$project = Project::where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
return response()->json([
Expand Down Expand Up @@ -268,7 +267,7 @@ public function status(Request $request, Draft $draft): JsonResponse
{
$this->authorize('updateDraft', $draft);

$project = Project::where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
return response()->json([
Expand Down Expand Up @@ -321,7 +320,7 @@ public function storeProvisionalDoi(Request $request, Draft $draft): JsonRespons
$payload = DB::transaction(function () use ($draft, $user, $user_id, $team_id, $team): array {
Draft::query()->whereKey($draft->id)->lockForUpdate()->firstOrFail();

$project = Project::query()->where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
$project = $this->processDraft->createNewProject($draft, $user_id, $team_id, $user, $team);
Expand Down Expand Up @@ -357,7 +356,7 @@ public function destroyProvisionalDoi(Request $request, Draft $draft): Response
{
$this->authorize('updateDraft', $draft);

$project = Project::query()->where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
return response()->noContent();
Expand Down
10 changes: 5 additions & 5 deletions app/Http/Controllers/ProjectController.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ public function validation(Request $request, Project $project)
}
}

$validation->process();
$validation->process(project: $project);

return Inertia::render('Project/Validation', [
'project' => $project->load('projectInvitations', 'tags', 'authors', 'citations', 'fundingReferences'),
Expand Down Expand Up @@ -377,7 +377,7 @@ public function validationReport(Request $request, Project $project)
}
}

$validation->process();
$validation->process(project: $project);

return $validation->fresh();
}
Expand Down Expand Up @@ -409,7 +409,7 @@ public function publish(Request $request, Project $project, PublishProject $publ
}

$project->release_date = $request->get('release_date');
$validation->process();
$validation->process(project: $project);
$validation = $validation->fresh();
if ($validation['report']['project']['status']) {
$project->status = 'queued';
Expand Down Expand Up @@ -467,7 +467,7 @@ public function publish(Request $request, Project $project, PublishProject $publ

$validation = $project->validation;
if ($validation) {
$validation->process(forceSamplesMode: true);
$validation->process(forceSamplesMode: true, project: $project);
$validation = $validation->fresh();
}

Expand Down Expand Up @@ -562,7 +562,7 @@ protected function publishValidationHintsFromReport(?array $report): array

$citations = $project['citations'] ?? null;
if (is_string($citations) && str_starts_with($citations, 'false|')) {
$hints[] = 'Add a DOI to every citation, or choose a future release date if you are not ready to publish immediately.';
$hints[] = 'Add at least one citation before publishing in project mode.';
}

$labels = [
Expand Down
24 changes: 19 additions & 5 deletions app/Http/Controllers/UploadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace App\Http\Controllers;

use App\Actions\Draft\ProcessDraft;
use App\Models\Draft;
use App\Models\Project;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
Expand All @@ -12,6 +12,8 @@

class UploadController extends Controller
{
public function __construct(private ProcessDraft $processDraft) {}

public function upload(Request $request)
{
$draftId = $request->get('draft_id');
Expand All @@ -20,7 +22,7 @@ public function upload(Request $request)
$draft = Draft::find((int) $draftId);

if ($draft && $request->user()?->can('updateDraft', $draft)) {
$project = Project::where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if ($project && $project->status !== 'draft') {
return redirect()->route('publish', ['draft' => $draft->id]);
Expand All @@ -39,7 +41,7 @@ public function publish(Request $request, Draft $draft)
{
$this->authorize('updateDraft', $draft);

$project = Project::where('draft_id', $draft->id)->first();
$project = $this->processDraft->resolveDraftProject($draft);

if (! $project) {
return redirect()->route('upload', ['draft_id' => $draft->id]);
Expand All @@ -50,11 +52,23 @@ public function publish(Request $request, Draft $draft)
}

$validation = $project->validation;
$validation->process();
$validation->process(project: $project);

$project->load([
'studies.datasets',
'studies.sample.molecules',
'studies.sample.mixtureComposition.components.molecule',
'owner',
'citations',
'fundingReferences',
'authors',
'tags',
'license',
]);

return Inertia::render('Publish', [
'draft' => $draft,
'project' => Project::with(['studies.datasets', 'studies.sample.molecules', 'studies.sample.mixtureComposition.components.molecule', 'owner', 'citations', 'fundingReferences', 'authors', 'tags', 'license'])->where('draft_id', $draft->id)->first(),
'project' => $project,
'validation' => $validation,
]);
}
Expand Down
4 changes: 2 additions & 2 deletions app/Jobs/ProcessFiles.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace App\Jobs;

use App\Actions\Draft\ProcessDraft;
use App\Models\Draft;
use App\Models\FileSystemObject;
use App\Models\Project;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
Expand Down Expand Up @@ -119,7 +119,7 @@ private function updateFileSystemObjectStatus(FileSystemObject $fsObject): bool
*/
private function handleMissingFilesRestored(): void
{
$project = Project::where('draft_id', $this->draft->id)->first();
$project = app(ProcessDraft::class)->resolveDraftProject($this->draft);

if (! $project) {
Log::warning('No project found for draft '.$this->draft->id);
Expand Down
2 changes: 1 addition & 1 deletion app/Jobs/ValidateAndSubmitELNDraft.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function handle(): void

// Process validation
$validation = $project->validation;
$validation->process();
$validation->process(project: $project);
$validation = $validation->fresh();

$status = true;
Expand Down
Loading
Loading