From 7e2086ea1e52a05deda833a07c0f2e787ca9962f Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Tue, 12 Sep 2023 16:08:42 +0200 Subject: [PATCH 01/38] wip: submission flow updates --- app/Console/Commands/ManageFiles.php | 66 + app/Http/Controllers/DatasetController.php | 2 +- app/Http/Controllers/DownloadController.php | 3 + app/Http/Controllers/DraftController.php | 63 +- app/Http/Controllers/StudyController.php | 163 +- app/Http/Controllers/UploadController.php | 39 + app/Models/Dataset.php | 4 +- app/Models/NMRium.php | 8 +- app/Models/Study.php | 6 + app/Models/Validation.php | 1 + config/validations.php | 3 +- .../2023_08_25_111326_update_nmrium_table.php | 32 + public/img/bruker.jpeg | Bin 0 -> 3298 bytes resources/js/Layouts/AppLayout.vue | 38 +- resources/js/Pages/Project/Show.vue | 2 +- resources/js/Pages/Public/Project/Study.vue | 16 +- resources/js/Pages/Publish.vue | 760 +++++ resources/js/Pages/Study/Datasets.vue | 6 +- resources/js/Pages/Upload.vue | 2941 +++++++++++++++++ resources/js/Pages/Welcome.vue | 211 +- resources/js/Shared/Children.vue | 2 +- resources/js/Shared/CreateButton.vue | 4 +- resources/js/Shared/FileDetails.vue | 24 +- resources/js/Shared/FileSystemBrowser.vue | 28 +- resources/js/Shared/ManageAuthor.vue | 4 +- resources/js/Shared/ManageCitation.vue | 4 +- resources/js/Shared/Primer.vue | 59 + resources/js/Shared/SpectraEditor.vue | 273 +- resources/js/Shared/SpectraViewer.vue | 182 +- resources/js/Shared/StudyInfo.vue | 133 + resources/js/Shared/Submission.vue | 2 +- resources/js/Shared/Validation.vue | 4 +- routes/web.php | 18 + 33 files changed, 4591 insertions(+), 510 deletions(-) create mode 100644 app/Console/Commands/ManageFiles.php create mode 100644 app/Http/Controllers/UploadController.php create mode 100644 database/migrations/2023_08_25_111326_update_nmrium_table.php create mode 100644 public/img/bruker.jpeg create mode 100644 resources/js/Pages/Publish.vue create mode 100644 resources/js/Pages/Upload.vue create mode 100644 resources/js/Shared/Primer.vue create mode 100644 resources/js/Shared/StudyInfo.vue diff --git a/app/Console/Commands/ManageFiles.php b/app/Console/Commands/ManageFiles.php new file mode 100644 index 00000000..d782c0d0 --- /dev/null +++ b/app/Console/Commands/ManageFiles.php @@ -0,0 +1,66 @@ +get(); + + foreach ($drafts as $draft) { + $path = $draft->path; + $this->processFiles($path); + } + }); + } + + public function processFiles($path) + { + $listing = Storage::disk(env('FILESYSTEM_DRIVER'))->listContents($path, true); + foreach ($listing as $item) { + $path = $item->path(); + + if ($item instanceof \League\Flysystem\FileAttributes) { + $fsObject = FileSystemObject::where([ + ['path', '/'.$path], + ])->first(); + if ($fsObject) { + $metaData = $item->extraMetadata(); + $fsInfo = json_decode($fsObject->info, true); + $fsInfo = array_merge($metaData, $fsInfo); + $fsObject->info = $fsInfo; + $fsObject->save(); + } + } elseif ($item instanceof \League\Flysystem\DirectoryAttributes) { + // echo($item); + } + } + } +} diff --git a/app/Http/Controllers/DatasetController.php b/app/Http/Controllers/DatasetController.php index 28028434..62962477 100644 --- a/app/Http/Controllers/DatasetController.php +++ b/app/Http/Controllers/DatasetController.php @@ -75,8 +75,8 @@ public function nmriumInfo(Request $request, Dataset $dataset) } else { $nmrium = NMRium::create([ 'nmrium_info' => json_encode($nmriumData), - 'dataset_id' => $dataset->id, ]); + $dataset->nmrium()->save($nmrium); $dataset->has_nmrium = true; } diff --git a/app/Http/Controllers/DownloadController.php b/app/Http/Controllers/DownloadController.php index cd16a119..06031a8b 100644 --- a/app/Http/Controllers/DownloadController.php +++ b/app/Http/Controllers/DownloadController.php @@ -20,6 +20,9 @@ public function downloadSet(Request $request, $username, $project, $study = null if (str_contains($dataset, '.zip')) { $dataset = str_replace('.zip', '', $dataset); } + if (str_contains($study, '.zip')) { + $study = str_replace('.zip', '', $study); + } $user = User::where('username', $username)->firstOrFail(); if ($project) { $project = Project::where([['slug', $project], ['owner_id', $user->id]])->firstOrFail(); diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 38a315f1..5250e4b0 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -57,7 +57,7 @@ public function all(Request $request) ); $defaultDraft = Draft::create([ - 'name' => 'Untitled Project', + 'name' => "Untitled Project", 'slug' => Str::slug('"Untitled Project"'), 'description' => '', 'relative_url' => rtrim( @@ -96,6 +96,13 @@ public function files(Request $request, Draft $draft) ]); } + public function update(Request $request, Draft $draft) + { + $draft->name = $request->get('name'); + $draft->save(); + return $draft; + } + public function deleteFSO(Request $request, Draft $draft, FileSystemObject $filesystemobject) { $fsoIds = $this->getChildrenIds($filesystemobject, []); @@ -131,7 +138,7 @@ public function complete(Request $request, Draft $draft) // ProcessDraft::dispatch($draft); return response()->json([ - 'project' => Project::with(['studies.datasets', 'owner'])->where('draft_id', $draft->id)->first(), + 'project' => Project::with(['studies.datasets', 'owner', 'citations', 'authors'])->where('draft_id', $draft->id)->first(), 'validation' => $validation, ]); } @@ -140,16 +147,16 @@ public function process(Request $request, Draft $draft) { $input = $request->all(); $project = Project::where('draft_id', $draft->id)->first(); - if ($project) { - $rule = Rule::unique('projects')->where('owner_id', $input['owner_id'])->ignore($project->id); - } else { - $rule = Rule::unique('projects')->where('owner_id', $input['owner_id']); - } + // if ($project) { + // $rule = Rule::unique('projects')->where('owner_id', $input['owner_id'])->ignore($project->id); + // } else { + // $rule = Rule::unique('projects')->where('owner_id', $input['owner_id']); + // } - $validation = $request->validate([ - 'name' => ['required', 'string', 'max:255', Rule::unique('drafts') - ->where('owner_id', $input['owner_id'])->ignore($draft->id), $rule, ], - ]); + // $validation = $request->validate([ + // 'name' => ['required', 'string', 'max:255', Rule::unique('drafts') + // ->where('owner_id', $input['owner_id'])->ignore($draft->id), $rule, ], + // ]); $draftFolders = FileSystemObject::with('children') ->where([ @@ -290,7 +297,7 @@ public function process(Request $request, Draft $draft) $sChildren = $folder->children; foreach ($sChildren as $sChild) { - if ($sChild->instrument_type != null) { + if ($sChild->instrument_type != null && $sChild->instrument_type != 'nmredata') { // associate all children with the study_id, project_id, dataset_id // create samples // create assays @@ -398,7 +405,7 @@ public function process(Request $request, Draft $draft) } return response()->json([ - 'project' => $project->load(['owner']), + 'project' => $project->load(['owner', 'citations', 'authors']), 'studies' => $studies, ]); }); @@ -449,11 +456,24 @@ public function processFolder($folders) } elseif ($this->isJcampDX($folder)) { $this->saveInstrumentType($folder, 'jcamp'); $this->saveModelType($folder->parent); + } elseif ($this->isNMReData($folder)) { + $this->saveInstrumentType($folder, 'nmredata'); + $this->saveAnnotationsDetected($folder->parent); } } } } + public function saveAnnotationsDetected($folder) + { + $study = $folder->study; + + if ($study) { + $study->has_nmredata = true; + $study->save(); + } + } + public function saveModelType($folder) { if ($folder) { @@ -517,6 +537,23 @@ public function isJcampDX($folder) return false; } + public function isNMReData($folder) + { + $fileTypes = ['nmredata']; + $names = [$folder->name]; + $extensions = array_map(fn ($s) => substr("$s", (strrpos($s, '.') + 1)), $names); + $isNMReData = false; + if (array_intersect($fileTypes, $extensions) == $fileTypes) { + $isNMReData = true; + } + + if ($isNMReData) { + return true; + } + + return false; + } + public function isJOEL($folder) { $fileTypes = ['jdf']; diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index 1d42e2bb..c1c77bc9 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -7,6 +7,7 @@ use App\Actions\Study\UpdateStudy; use App\Models\FileSystemObject; use App\Models\Molecule; +use App\Models\NMRium; use App\Models\Sample; use App\Models\Study; use Auth; @@ -127,6 +128,7 @@ public function moleculeStore(Request $request, Study $study) 'FORMULA' => $request->get('formula') ? $request->get('formula') : '', 'INCHI_KEY' => $request->get('InChIKey') ? $request->get('InChIKey') : '', 'MOL' => $request->get('mol') ? $request->get('mol') : '', + 'CANONICAL_SMILES' => $request->get('cannonical_smiles') ? $request->get('cannonical_smiles') : '', ]); $sample->molecules()->syncWithPivotValues([$molecule->id], ['percentage_composition' => $request->get('percentage')], false); } @@ -135,6 +137,69 @@ public function moleculeStore(Request $request, Study $study) return $sample->molecules; } + public function fetchNMRium(Request $request, Study $study) + { + if ($study) { + $nmrium = $study->nmrium; + if ($nmrium) { + return json_decode($nmrium->nmrium_info); + } else { + return null; + } + } + } + + public function nmriumVersions(Request $request, Study $study) + { + if ($study) { + $nmrium = $study->nmrium; + + if ($nmrium) { + return $nmrium->versions()->orderBy('created_at', 'DESC')->get()->map(function ($version) { + $user = User::find($version->user_id); + + return [ + 'updated_at' => $version->updated_at, + 'user' => [ + 'name' => $user->first_name.' '.$user->last_name, + 'profile_photo_url' => $user->profile_photo_url, + ], + ]; + }); + } + } + } + + public function nmriumInfo(Request $request, Study $study) + { + if ($study) { + $user = Auth::user(); + $data = $request->all(); + $version = $request->get('version'); + // $spectra = $request->get('spectra'); + // $molecules = $request->get('molecules'); + + $nmriumInfo = $data; + // $molecularInfo = $molecules; + $nmrium = $study->nmrium; + + if ($nmrium) { + $nmrium->nmrium_info = $nmriumInfo; + $study->has_nmrium = true; + $nmrium->save(); + } else { + $nmrium = NMRium::create([ + 'nmrium_info' => json_encode($nmriumInfo), + ]); + $study->nmrium()->save($nmrium); + $study->has_nmrium = true; + } + $study->save(); + + return $study->fresh(); + } + } + public function moleculeDetach(Request $request, Study $study, Molecule $molecule) { if ($molecule) { @@ -180,39 +245,81 @@ public function files(Request $request, Study $study) ]); } + public function annotations(Request $request, Study $study) + { + if (! Gate::forUser($request->user())->check('viewStudy', $study)) { + throw new AuthorizationException; + } + + $studyFSObject = FileSystemObject::with('children') + ->where([ + ['study_id', $study->id], + ['level', $study->fsObject->level], + ]) + ->orderBy('type') + ->first(); + + return $studyFSObject->children->filter(function ($child) { + return $child->instrument_type == 'nmredata'; + })->values(); + } + public function file(Request $request, $code, Study $study, $filename) { $file = FileSystemObject::with('project', 'study') ->where([['name', $filename], ['study_id', $study->id]]) ->first(); - - $environment = env('APP_ENV', 'local'); - - $path = preg_replace( - '~//+~', - '/', - '/'. - $environment. - '/'. - $file->project->uuid. - '/'. - $file->study->uuid. - '/'. - $file->relative_url - ); - - if (Storage::has($path)) { - $data = Storage::get($path); - $newFileName = $file->name; - $headers = [ - 'Access-Control-Allow-Origin' => '*', - 'Content-Disposition' => sprintf( - 'attachment; filename="%s"', - $newFileName - ), - ]; - - return Response::make($data, 200, $headers); + if (! $file) { + $file = FileSystemObject::with('project', 'study') + ->where([['slug', $filename], ['draft_id', $study->draft->id]]) + ->first(); + + $file->project = $study->project; + $file->study = $study; + + if (Storage::has($file->path)) { + $data = Storage::get($file->path); + $newFileName = $file->name; + $headers = [ + 'Access-Control-Allow-Origin' => '*', + 'Content-Disposition' => sprintf( + 'attachment; filename="%s"', + $newFileName + ), + ]; + + return Response::make($data, 200, $headers); + } + + } else { + if ($file) { + $environment = env('APP_ENV', 'local'); + $path = preg_replace( + '~//+~', + '/', + '/'. + $environment. + '/'. + $file->project->uuid. + '/'. + $file->study->uuid. + '/'. + $file->relative_url + ); + if (Storage::has($path)) { + $data = Storage::get($path); + $newFileName = $file->name; + $headers = [ + 'Access-Control-Allow-Origin' => '*', + 'Content-Disposition' => sprintf( + 'attachment; filename="%s"', + $newFileName + ), + ]; + + return Response::make($data, 200, $headers); + } + } } return Response::make(null, 404); diff --git a/app/Http/Controllers/UploadController.php b/app/Http/Controllers/UploadController.php new file mode 100644 index 00000000..7fed67e4 --- /dev/null +++ b/app/Http/Controllers/UploadController.php @@ -0,0 +1,39 @@ + $request->get('draft_id'), + ]); + } + + public function publish(Request $request, Draft $draft) + { + $project = Project::where('draft_id', $draft->id)->first(); + + if (! Gate::forUser(Auth::user())->check('updateProject', $project)) { + throw new AuthorizationException; + } + + $validation = $project->validation; + $validation->process(); + + return Inertia::render('Publish', [ + 'draft' => $draft, + 'project' => Project::with(['studies.datasets', 'studies.sample.molecules', 'owner', 'citations', 'authors'])->where('draft_id', $draft->id)->first(), + 'validation' => $validation, + ]); + } +} diff --git a/app/Models/Dataset.php b/app/Models/Dataset.php index beb73099..38fc7279 100644 --- a/app/Models/Dataset.php +++ b/app/Models/Dataset.php @@ -111,9 +111,9 @@ public function team() return $this->belongsTo(Team::class, 'Team_id'); } - public function nmrium() + public function nmrium(): MorphOne { - return $this->hasOne(NMRium::class); + return $this->morphOne(NMRium::class, 'nmriumable'); } public function fsObject() diff --git a/app/Models/NMRium.php b/app/Models/NMRium.php index 35bd5e21..7917b8d7 100644 --- a/app/Models/NMRium.php +++ b/app/Models/NMRium.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphTo; use Mpociot\Versionable\VersionableTrait; class NMRium extends Model @@ -20,9 +21,12 @@ class NMRium extends Model 'dataset_id', ]; - public function dataset() + /** + * Get the parent nmriumable model (Dataset or Study). + */ + public function nmriumable(): MorphTo { - return $this->belongsTo(Dataset::class, 'dataset_id'); + return $this->morphTo(); } public function user() diff --git a/app/Models/Study.php b/app/Models/Study.php index d390404d..963c357e 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphOne; use Laravel\Scout\Searchable; use Maize\Markable\Markable; use Maize\Markable\Models\Bookmark; @@ -163,6 +164,11 @@ public function studyInvitations() return $this->hasMany(StudyInvitation::class); } + public function nmrium(): MorphOne + { + return $this->morphOne(NMRium::class, 'nmriumable'); + } + /** * Get the user study role * diff --git a/app/Models/Validation.php b/app/Models/Validation.php index 4d0e1715..5615b1a9 100644 --- a/app/Models/Validation.php +++ b/app/Models/Validation.php @@ -142,6 +142,7 @@ public function process() 'description' => $study->description, 'keywords' => $study->tags->pluck('id')->toArray(), 'composition' => $study->sample->molecules->pluck('id')->toArray(), + 'nmrium_info' => $study->has_nmrium ? $study->has_nmrium : null, 'sample' => $study->sample, ]; diff --git a/config/validations.php b/config/validations.php index 3d7b552e..549d4d65 100644 --- a/config/validations.php +++ b/config/validations.php @@ -20,13 +20,14 @@ 'study' => [ 'title' => 'required', 'description' => '', + 'nmrium_info' => 'required', 'keywords' => 'array|min:1', 'composition' => 'array|min:1', 'sample' => 'required', ], 'dataset' => [ 'files' => 'required', - 'nmrium_info' => 'required', + 'nmrium_info' => '', 'assay' => '', 'assignments' => 'array|min:1', ], diff --git a/database/migrations/2023_08_25_111326_update_nmrium_table.php b/database/migrations/2023_08_25_111326_update_nmrium_table.php new file mode 100644 index 00000000..b690e4a9 --- /dev/null +++ b/database/migrations/2023_08_25_111326_update_nmrium_table.php @@ -0,0 +1,32 @@ +renameColumn('dataset_id', 'nmriumable_id'); + $table->string('nmriumable_type')->default('App\Models\Dataset'); + }); + + Schema::table('studies', function (Blueprint $table) { + $table->boolean('has_nmrium')->nullable()->default(0); + $table->boolean('has_nmredata')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/public/img/bruker.jpeg b/public/img/bruker.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a476544792b1e6cb34eb3ff0f49ad8163627b6c5 GIT binary patch literal 3298 zcmb7GS5y;P7EJ&NRScqZB2^HGG!ts5!UIHURib?L(8D}o{-R|FvtF-avEF$wvr5QwaX zto#kQs;a7}w5Fb>vaXVfDjdkd!otqR&d0&Q2N#Ek!~bubwgJFQfJi_jJx~Nd2L{rE zfv4X90>3Su`)&1aFajCQftcv%&)7dM0DufYI(mk4Objfnzh3|WzdJ@Sr?5QeqV`=b z5huUrmlVwW(fO5wmqm5jxfS)yEu90Bt2UX$m2@qhq!j$sF?2SG2lyZSEpk@S(*YUI z7;!Lwjt)rAKu7<#i8ICD0t^b;cb(9F&)YAajsw`vXgV-G7@!H5mW+uI5dp-+(1~1O z`rk6{CFRr47TfwGlNhIyA+4EC73FdJG|5l-U#*byG9A}P-aw|yXG$t%dO~wo_c~h+ zLMjj;zd~s7r3#^<34Zp~*W!Bu=Ys8(z+k{l6TEUH{m^y6h442=_ui3IvQzZ*RL=-K zJq9;h5>%W08V`{HRs~~V&-zt&GW@Fc9;9G1Wunu$@bT^NP^zZw&%8u&?{Ovn&etDP zDyF66>xi06TaR@QqQtxH;`WriN09>NavH_c13&xl=8$1sQi*-VkEha3a<2*9CI0Dpr{1 z>;{PW4Bm>kPb&=eJv!Nqvucs@3G`2qmL-S2rDDg%?Wv440b)53caBHhpJ7eqT*i;~ zgT|PCDIz~DY@XBe=}Yf7G2gAi9ZWuG^KI6%<4@ds^&H_ts)Ny+&dbZ+7(2v4MGvUK z8@`7#Y2x*kPc}4Wx*-qngvl+3zMpvolD)OlNJ4C-b6IY-?#neQW}RgPIzTa9eOP;5 zrz7#sXwKJl@!M@eMi`maBI8Q&16Y%F%i@GEvb{?TK2rb2^CUg}@xgVa6Z4_QM;7Zd zNhjAR1w8N5--;0>}xf`xyx%4jE=b$@UYp?0X9zS8XNwwil7J^6N6O3VYo5`QS-1; z{tAl8Bq)tLYY`L?wD`F$CD20t`vw!@R^NttLl0)GhOrsq@GC z2d98|zxncAgr{aul~=3rb@lm4U*c0^sKE6QhLGB$gTqNXi1SE;tZ}(wBhWJQ<6d5y zy*MTS<2ca~b5N>-yV+S@q>rsNG*nl5>Sz%X;i29Lwg0|i;#R!YA&}WUY)tGDG}_F0 zkvpN*F>5hlxvEZ1=$6Z9STivd)|g`(YI~;E6^(^cg)W4xJd6#@Csf;Ewh_th)!sj& zhU?Sa@SB>}+d_EchbJbXo}HA!DBRneE{79umzJzOO@gL>>^^;Zuj}gKd+b!^@LZ?} z+-R*2$T9QyOIRGY=e-qJV1eJK{%NigTQ7})&}YxoekccSPb5`iz=P)!mlrKugUkQi zTUsi+G*``vsw$(z~!e^d&(^l-!j!Sx0|m zE;qTXp%$5F3NV)JRlyrkkDYvfWUWGds=6{U@bK3|VHSE?WMc*JSuiAa)9oIdtYA2V-1d*%;!?vV-KlQ@rIIHlCX{qixhLM49 z@Kr9`axmN_GKZ(o{Gc;ukU-azfoQ#M(rL8XQ z3is*;zO3VS|3c}GZcK2yF!o~O!0XeKlv~kX)~>Oos3x!l8rD%%-lgjNI8ns3OtyUR z?l&=zebLK?YTB!Q)=xwJQ3ehGp@lJtPRol$wl31K*t?#U>~S!-k0f7Pw|;26!NQ=G zrJ;fC6gX-tIokm@l(#ITjaP0(_Gs>_I9KIl9csEB(9Csg+%j+%?PC&dp{7{14iSjI zOl8ylu^ zN31f0mKUC3iAxnmKK3&@2Ff8gWGnS4c>TOG{`@(t}7r@~^{5gk*HzF%eQUdkyFVABzpQoC7J<8Rs zZ>e)R3ye*Xf`UXs~P>qwnUVh7_;v;b! zWf%6;#jYI@!ndg#J&TGFO&V3j+`iYYMsAkSPVdbcXuMARj1Vq71qkJmvsApbGxvPQ zHnhr-DKkQqLf)?*Q_FA;$scWdFmIA>rRtuD3?Lw-)2M@MR#T?3C$ZLFr<|p!?W}x# z!pTW&K4yKsxBvs>L-ZT!i(&5**M&|mnahfTuM5Vuyc}asD$&I;*l=`Eoa+~53O;;Q z*e1z)$3aCUcVR@*qRI5G2T>4~-jnfeCcst)c*Ic}b{seHbi9)L!{Mfh{`kWTS>u_v zF7;zAvO)K2)Oe^dH=rWH+Z41)GG^YsIN-$&WgaQ;{g zT5xKH4?aRefAfhuLhKZf$5p}k-LD?~WS%g9WSAAiTLOrddbG%2jF(pIDEH}_x)j+|Bo8*2oPqHYKoTM - + - + diff --git a/resources/js/Pages/Project/Show.vue b/resources/js/Pages/Project/Show.vue index 75051db9..92355064 100644 --- a/resources/js/Pages/Project/Show.vue +++ b/resources/js/Pages/Project/Show.vue @@ -577,7 +577,7 @@
- +
diff --git a/resources/js/Pages/Public/Project/Study.vue b/resources/js/Pages/Public/Project/Study.vue index 9fdf36a6..d82bcc3e 100644 --- a/resources/js/Pages/Public/Project/Study.vue +++ b/resources/js/Pages/Public/Project/Study.vue @@ -98,7 +98,13 @@
-
+
-
-
-
+
--> -
+
+ + +
+
+
+
+
+
+
+
+
+
+

+ Drafts +

+

+ Please select one of the + drafts below to continue or + start a new submission +

+
+
+ +
+
+
+ +
    +
  • + +
    +
    +

    + {{ + draft.name + }} +

    +

    + {{ + draft.description + }} +

    +

    + ID: {{ draft.key }} +

    +

    + Created at: + {{ + formatDateTime( + draft.created_at + ) + }} +

    + +
    +
    + +
    +
    + +
  • +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ Draft ID: + {{ currentDraft.key }} +
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+

+ {{ + selectedStudy.name + }} +

+
+
+
    +
  • +
    + +
    +
  • + + +
+
+
+
    +
  • +
    + +
    +
  • +
+
+
+ + +
+ +
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+

+ Sample + Details +

+ +
+
+

+ Chemical + composition + (optional) +

+
+

+ Residual + Complexity + (RC) + refers + to + the + subtle + but + significant + convolution + of + major + and + minor + ("hidden") + chemical + species + in + materials + that + originate + from + biochemical + or + synthetic + reaction + mixtures. + Certain + levels + of + these + chemical + species + (molecules) + usually + remain + present + even + after + a + number + of + purification + steps, + and + this + RC + is + to + some + degree + conserved + even + in + highly + purified + materials. + In + principle, + RC + affects + all + "pure" + materials, + including + synthetic + compound, + whenever + chromatographic + or + other + purification + steps + are + required + prior + to + their + biological + evaluation. + Please + report + the + chemical + composition + (if + known) + of + your + sample. + If + unknown + please + report + the + molecules + that + you + expect + to + be + present + in + your + sample + with-out + the + composition. +

+
+ +
+
+
+
    +
  • +
    + +
    +
    +
    + {{ + molecule + .pivot + .percentage_composition + }}% +
    + +
    +
    + +
    +
    + +
    + + +
    +
    +
    +
    +
  • +
+
+ Sample + chemical + composition +
+
+
+
+ +

+ No + structures + associated + with + the + sample + yet! +

+

+ Get + started + by + adding + a + new + molecule. +

+
+
+
+
+
+ +
+ +
+ + +
+
+ + + Need + help? + + +
+
+ + +
+ +
+
+
+
+ +
+
+ Mols +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ + Citation + + +
+
+
+ +
+
+
+
+ +
+ + Author + + +
+
+
+
+ +
+
+
+
+
+
+ + +

+ Publish your data + now or choose a + release date to auto + publish your project + to public. +

+
+
+

+ Terms & Conditions +

+ +
+
+
+ +
+ I + understand + once the + project + is + published, + all the + underlying + studies + and + spectra + will + also be + made + public + and + agree to + make + this + data + persistently + available + in this + location. +
+
+
+
+
+
+
+ +
+ I agree + to the + Terms + of + Service + and + Privacy + Policy + and + hereby + also + grant + nmrXiv + permissions + to + distribute + the + datasets + (and + meta-data) + under + the + specified + license. +
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
+ + +
+
+

+ Error + publishing + your + project +

+
+
    +
  • + {{ + errors + }} +
  • +
+
+
+
+
+
+
+ +
+
+ Whats next? +
+

+ Upon clicking + publish, your + project is + submitted to our + queue system for + automatic + processing. Once + successfully + processed, your + data is assigned + with stable + identifiers, and + DOIs are + generated. You + will receive an + email with + citation details + and other + helpful + information to + share your + datasets. +

+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+ + + + + Loading... +
+
+
+
+ + + diff --git a/resources/js/Pages/Welcome.vue b/resources/js/Pages/Welcome.vue index 17bc1411..855884e2 100644 --- a/resources/js/Pages/Welcome.vue +++ b/resources/js/Pages/Welcome.vue @@ -29,71 +29,6 @@ as="nav" class="hidden md:flex space-x-10" > -
-
-
Built to be FAIR from ground up - +
@@ -653,17 +583,13 @@
- -

- -

+ >

-
@@ -1015,10 +889,6 @@ const features = [ }, ]; const footerNavigation = { - // Search: [ - // { name: "Browse", href: "/projects" }, - // { name: "Advanced Search", href: "/projects" }, - // ], support: [ { name: "Documentation", href: "https://docs.nmrxiv.org" }, { @@ -1035,58 +905,12 @@ const footerNavigation = { name: "Adivsory Board", href: "https://docs.nmrxiv.org/docs/contributing/contributors-and-steering-committee", }, - // { name: "Metrics", href: "#" }, - // { name: "Blog", href: "#" }, - // { name: "Press", href: "#" }, ], legal: [ { name: "Privacy", href: "/privacy-policy" }, { name: "Terms", href: "/terms-of-service" }, ], social: [ - // { - // name: "Facebook", - // href: "#", - // icon: defineComponent({ - // render: () => - // h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [ - // h("path", { - // "fill-rule": "evenodd", - // d: - // "M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z", - // "clip-rule": "evenodd", - // }), - // ]), - // }), - // }, - // { - // name: "Instagram", - // href: "#", - // icon: defineComponent({ - // render: () => - // h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [ - // h("path", { - // "fill-rule": "evenodd", - // d: - // "M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z", - // "clip-rule": "evenodd", - // }), - // ]), - // }), - // }, - // { - // name: "Twitter", - // href: "#", - // icon: defineComponent({ - // render: () => - // h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [ - // h("path", { - // d: - // "M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84", - // }), - // ]), - // }), - // }, { name: "GitHub", href: "https://github.com/nfdi4chem/nmrxiv", @@ -1101,21 +925,6 @@ const footerNavigation = { ]), }), }, - // { - // name: "Dribbble", - // href: "#", - // icon: defineComponent({ - // render: () => - // h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [ - // h("path", { - // "fill-rule": "evenodd", - // d: - // "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10c5.51 0 10-4.48 10-10S17.51 2 12 2zm6.605 4.61a8.502 8.502 0 011.93 5.314c-.281-.054-3.101-.629-5.943-.271-.065-.141-.12-.293-.184-.445a25.416 25.416 0 00-.564-1.236c3.145-1.28 4.577-3.124 4.761-3.362zM12 3.475c2.17 0 4.154.813 5.662 2.148-.152.216-1.443 1.941-4.48 3.08-1.399-2.57-2.95-4.675-3.189-5A8.687 8.687 0 0112 3.475zm-3.633.803a53.896 53.896 0 013.167 4.935c-3.992 1.063-7.517 1.04-7.896 1.04a8.581 8.581 0 014.729-5.975zM3.453 12.01v-.26c.37.01 4.512.065 8.775-1.215.25.477.477.965.694 1.453-.109.033-.228.065-.336.098-4.404 1.42-6.747 5.303-6.942 5.629a8.522 8.522 0 01-2.19-5.705zM12 20.547a8.482 8.482 0 01-5.239-1.8c.152-.315 1.888-3.656 6.703-5.337.022-.01.033-.01.054-.022a35.318 35.318 0 011.823 6.475 8.4 8.4 0 01-3.341.684zm4.761-1.465c-.086-.52-.542-3.015-1.659-6.084 2.679-.423 5.022.271 5.314.369a8.468 8.468 0 01-3.655 5.715z", - // "clip-rule": "evenodd", - // }), - // ]), - // }), - // }, ], }; diff --git a/resources/js/Shared/Children.vue b/resources/js/Shared/Children.vue index cf7f6c0c..d731fd58 100644 --- a/resources/js/Shared/Children.vue +++ b/resources/js/Shared/Children.vue @@ -316,7 +316,7 @@ export default { composeIcon(file) { if (file.instrument_type) { if (file.instrument_type == "bruker") { - return ''; + return ''; } else if (file.instrument_type == "varian") { return ''; } else if (file.instrument_type == "joel") { diff --git a/resources/js/Shared/CreateButton.vue b/resources/js/Shared/CreateButton.vue index 412d5fb5..09f01bdf 100644 --- a/resources/js/Shared/CreateButton.vue +++ b/resources/js/Shared/CreateButton.vue @@ -24,7 +24,7 @@ - {{ bytesToSize(JSON.parse(file.info).size) }} + {{ bytesToSize(fileInfo.size) }} + +
ETag
+
+
+ {{ fileInfo.ETag.replace(/"/g, "") }} +
+
+ - +
@@ -76,12 +87,6 @@
-
@@ -128,8 +133,9 @@ export default { url() { return String(this.$page.props.url); }, + fileInfo(){ + return JSON.parse(this.file.info) + } }, - mounted() {}, - methods: {}, }; diff --git a/resources/js/Shared/FileSystemBrowser.vue b/resources/js/Shared/FileSystemBrowser.vue index 39141faa..1fac8900 100644 --- a/resources/js/Shared/FileSystemBrowser.vue +++ b/resources/js/Shared/FileSystemBrowser.vue @@ -10,7 +10,7 @@ >
-
+
@@ -88,7 +88,10 @@
-
+
-
+
{ - this.updateBusyStatus(false); this.file = response.data.file; this.file.has_children = true; this.$page.props.selectedFileSystemObject = this.file; this.$page.props.selectedFolder = "/"; + this.updateBusyStatus(true); }); }, annotate() { diff --git a/resources/js/Shared/ManageAuthor.vue b/resources/js/Shared/ManageAuthor.vue index 59cdecdf..62bd7b49 100644 --- a/resources/js/Shared/ManageAuthor.vue +++ b/resources/js/Shared/ManageAuthor.vue @@ -1099,7 +1099,7 @@ export default { this.authorsForm.delete(route("author.delete", this.project.id), { preserveScroll: true, onSuccess: () => { - Inertia.reload({ only: ["project"] }); + Inertia.reload(); this.loadInitial(); this.authorsForm.reset(); this.confirmDelete = false; @@ -1130,7 +1130,7 @@ export default { { preserveScroll: true, onSuccess: () => { - Inertia.reload({ only: ["project"] }); + Inertia.reload(); this.loadInitial(); this.updateRoleForm.reset(); this.showManageRoleDialog = false; diff --git a/resources/js/Shared/ManageCitation.vue b/resources/js/Shared/ManageCitation.vue index 7ed56ebc..33a78099 100644 --- a/resources/js/Shared/ManageCitation.vue +++ b/resources/js/Shared/ManageCitation.vue @@ -747,7 +747,7 @@ export default { this.citationsForm.post(route("citation.save", this.project.id), { preserveScroll: true, onSuccess: () => { - Inertia.reload({ only: ["project"] }); + Inertia.reload(); this.citationsForm.reset(); this.loadInitial(); this.form.reset(); @@ -841,7 +841,7 @@ export default { { preserveScroll: true, onSuccess: () => { - Inertia.reload({ only: ["project"] }); + Inertia.reload(); this.loadInitial(); this.citationsForm.reset(); this.confirmDelete = false; diff --git a/resources/js/Shared/Primer.vue b/resources/js/Shared/Primer.vue new file mode 100644 index 00000000..f4fe9592 --- /dev/null +++ b/resources/js/Shared/Primer.vue @@ -0,0 +1,59 @@ + diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index fca0e7cf..60f796ff 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -10,7 +10,7 @@ >Learn more Reset @@ -75,7 +75,7 @@ :src="nmriumURL" @load="loadSpectra()" > -
+
@@ -348,6 +348,12 @@ export default { this.loadSpectra(); }, }, + study: { + immediate: true, + handler() { + this.loadSpectra(); + }, + }, }, setup() { const versionsElement = ref(null); @@ -372,8 +378,9 @@ export default { }, nmriumURL() { return this.$page.props.nmriumURL - ? String(this.$page.props.nmriumURL + "?id=" + Math.random()) - : "http://nmriumdev.nmrxiv.org?id=" + Math.random(); + ? String(this.$page.props.nmriumURL + "&id=" + Math.random()) + : "https://nmriumdev.nmrxiv.org?workspace=embedded&id=" + + Math.random(); }, mailFromAddress() { @@ -384,58 +391,89 @@ export default { registerEvents() { const saveNMRiumUpdates = (e) => { const { data, type } = e.data; - if ( - e.origin != "https://nmriumdev.nmrxiv.org" && - e.origin != "https://nmrium.nmrxiv.org" - ) { - return; - } - if (type == "nmr-wrapper:error") { - this.spectraError = e.data; - this.updateLoadingStatus(false); - - return; - } - if (type == "nmr-wrapper:action-response") { - let actionType = e.data.type; - if (actionType == "exportSpectraViewerAsBlob") { - this.saveStudyPreview(data); - } - } - if (type == "nmr-wrapper:data-change") { - const state = data.state; - this.version = state.version; - let actionType = state.data.actionType; + if (data && data.source == "data") { if ( - actionType == "" || - (actionType == "INITIATE" && - this.dataset && - this.dataset.has_nmrium && - !this.reset) + e.origin != "https://nmriumdev.nmrxiv.org" && + e.origin != "https://nmrium.nmrxiv.org" ) { - this.infoLog("Spectra loaded successfully...", true); return; } - this.selectedSpectraData = state.data.spectra; - if ( - actionType == "ADD_MOLECULE" || - actionType == "DELETE_MOLECULE" || - state.data.molecules - ) { - this.currentMolecules = state.data.molecules; + if (type == "nmr-wrapper:error") { + this.spectraError = e.data; + this.updateLoadingStatus(false); + + return; } + if (type == "nmr-wrapper:action-response") { + let state = data.state; + this.version = state.version; + let actionType = state.data.actionType; + if (actionType == "exportSpectraViewerAsBlob") { + this.saveStudyPreview(data); + } + } + if (type == "nmr-wrapper:data-change") { + let state = data.state; + this.version = state.version; + let actionType = state.data.actionType; + // console.log(this.study.has_nmrium,actionType) + if (state.data.spectra.length > 0) { + if ( + actionType == "INITIATE" && + !this.study.has_nmrium + ) { + this.infoLog( + "Spectra loaded successfully...", + true + ); + this.selectedSpectraData = state.data; - if (this.study && this.dataset) { - if (this.dataset.dataset_photo_url == "") { - this.infoLog("Saving Preview"); - setTimeout( - function () { - this.exportPreview(); - }.bind(this), - 500 - ); + if (!this.study.has_nmrium) { + delete this.selectedSpectraData[ + "actionType" + ]; + this.selectedSpectraData.spectra.forEach( + (spec) => { + delete spec["data"]; + delete spec["info"]; + delete spec["meta"]; + delete spec["originalData"]; + delete spec["originalInfo"]; + } + ); + this.updateStudyNMRiumInfo(); + this.updateLoadingStatus(false); + } + return; + } else if ( + this.study.has_nmrium && + actionType != "INITIATE" + ) { + this.selectedSpectraData = state.data; + delete this.selectedSpectraData["actionType"]; + this.selectedSpectraData.spectra.forEach( + (spec) => { + delete spec["data"]; + delete spec["info"]; + delete spec["meta"]; + delete spec["originalData"]; + delete spec["originalInfo"]; + } + ); + this.updateStudyNMRiumInfo(); + this.updateLoadingStatus(false); + } else if ( + this.study.has_nmrium && + actionType == "INITIATE" + ) { + this.selectedSpectraData = state.data; + this.infoLog( + "Spectra loaded successfully...", + true + ); + this.updateLoadingStatus(false); + } } - this.updateDataSet(); } } }; @@ -453,115 +491,104 @@ export default { this.spectraError = null; this.currentMolecules = []; this.updateLoadingStatus(true); - let username = this.$page.props.team + let username = this.$page.props.team.owner ? this.$page.props.team.owner.username : this.project.owner.username; - let url = - this.url + - "/" + - username + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; if (iframe) { - let spectra = []; - let nmrium_info = null; - if (this.dataset && this.dataset.has_nmrium) { + if (this.study && this.study.has_nmrium) { this.infoLog("Loading Spectra from NMRium JSON.."); axios .get( - "/dashboard/datasets/" + - this.dataset.id + + "/dashboard/studies/" + + this.study.id + "/nmriumInfo" ) .then((response) => { this.updateLoadingStatus(false); - nmrium_info = JSON.parse(response.nmrium_info); - if (nmrium_info && nmrium_info["data"]["spectra"]) { - if ( - this.isString( - nmrium_info["data"]["spectra"] - ) - ) { - spectra = JSON.parse( - nmrium_info.data.spectra - ); - } else { - spectra = nmrium_info.data.spectra; - } - } - if (spectra && spectra.length <= 0) { - this.loadFromURL(url); - } else { - let nmriumVersion = 4; - if (nmrium_info && nmrium_info["version"]) { - nmriumVersion = nmrium_info["version"]; - } - let mols = []; - if (this.isString(nmrium_info.data.molecules)) { - mols = JSON.parse( - nmrium_info.data.molecules - ); - } else { - mols = nmrium_info.data.molecules; - } - if (mols && mols.length > 0) { - this.currentMolecules = mols; - mols.forEach((mol) => { - mol.molfile = "\n" + mol.molfile + "\n"; - }); - } - + let nmrium_info = response.data; + if (nmrium_info) { let data = { - data: { - spectra: spectra, - molecules: mols, - version: nmriumVersion, - }, + data: nmrium_info, type: "nmrium", }; iframe.postMessage( { type: `nmr-wrapper:load`, data }, "*" ); - this.selectedSpectraData = spectra; + } else { + this.loadFromURLs(null); } }); } else { - this.loadFromURL(url); + if (this.study.datasets.length > 0) { + let urls = []; + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug; + urls.push(url); + this.loadFromURLs(urls); + } } } }, - loadFromURL(url) { + loadFromURLs(urls) { this.infoLog("Loading Spectra from URL.."); - this.dataset.type = null; - this.selectedSpectraData = null; - this.reset = true; - let ownerUserName = this.$page.props.team - ? this.$page.props.team.owner.username - : this.project.owner.username; const iframe = window.frames.submissionNMRiumIframe; - if (!url) { - url = + if (!urls) { + urls = []; + let username = this.$page.props.team.owner + ? this.$page.props.team.owner.username + : this.project.owner.username; + let url = this.url + "/" + - ownerUserName + + username + "/datasets/" + this.project.slug + "/" + - this.study.slug + - "/" + - this.dataset.slug; + this.study.slug; + urls.push(url); } + let data = { - data: [url], + data: urls, type: "url", }; + iframe.postMessage({ type: `nmr-wrapper:load`, data: data }, "*"); }, + updateStudyNMRiumInfo() { + if (this.study != null && this.selectedSpectraData) { + this.updateLoadingStatus(true); + axios + .post( + "/dashboard/studies/" + this.study.id + "/nmriumInfo", + { + version: 4, + data: this.selectedSpectraData, + } + ) + .then((response) => { + this.infoLog("Spectra saved successfully", true); + this.updateLoadingStatus(false); + this.autoSaving = false; + this.study.has_nmrium = response.data.has_nmrium; + }) + .catch(() => { + this.updateLoadingStatus(false); + this.infoLog("Error saving spectra info"); + console.error( + "Error saving the nmrium info. Please contact us at {{mailFromAddress}} if the error persist." + ); + this.autoSaving = false; + }); + } + }, updateDataSet() { if (this.dataset != null && this.selectedSpectraData.length > 0) { this.updateLoadingStatus(true); diff --git a/resources/js/Shared/SpectraViewer.vue b/resources/js/Shared/SpectraViewer.vue index 0421573f..df692847 100644 --- a/resources/js/Shared/SpectraViewer.vue +++ b/resources/js/Shared/SpectraViewer.vue @@ -329,103 +329,115 @@ export default { this.spectraError = null; this.currentMolecules = []; this.updateLoadingStatus(true); - let url = - this.url + - "/" + - this.project.owner.username + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; + if (iframe) { - let spectra = []; - let nmrium_info = null; - if (this.dataset && this.dataset.has_nmrium) { - this.infoLog("Loading Spectra from NMRium JSON.."); - axios - .get("/datasets/" + this.dataset.id + "/nmriumInfo") - .then((response) => { - this.updateLoadingStatus(false); - nmrium_info = JSON.parse( - response.data.nmrium_info - ); - let nmriumVersion = 4; - if (nmrium_info && nmrium_info["version"]) { - nmriumVersion = nmrium_info["version"]; - } - if (nmrium_info && nmrium_info["spectra"]) { - if (this.isString(nmrium_info["spectra"])) { - spectra = JSON.parse( - nmrium_info.spectra - ); - } else { - spectra = nmrium_info.spectra; - } - } - if (spectra && spectra.length <= 0) { - this.loadFromURL(url); - } else { - let mols = []; - if (this.isString(nmrium_info.molecules)) { - mols = JSON.parse( - nmrium_info.molecules - ); - } else { - mols = nmrium_info.molecules; - } - if (mols && mols.length > 0) { - this.currentMolecules = mols; - mols.forEach((mol) => { - mol.molfile = - "\n" + mol.molfile + "\n"; - }); - } - let data = { - data: { - spectra: spectra, - molecules: mols, - version: nmriumVersion, - }, - type: "nmrium", - }; - iframe.postMessage( - { type: `nmr-wrapper:load`, data }, - "*" - ); - this.selectedSpectraData = spectra; - } - }); + let urls = []; + let username = + this.$page.props.team && this.$page.props.team.owner + ? this.$page.props.team.owner.username + : this.project.owner.username; + if (this.study.datasets) { + this.study.datasets.forEach((dataset) => { + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug + + "/" + + dataset.slug; + urls.push(url); + }); + this.loadFromURL(urls); } else { - this.loadFromURL(url); + if (this.dataset) { + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug + + "/" + + this.dataset.slug; + urls.push(url); + this.loadFromURL(urls); + } } + + // if (this.dataset && this.dataset.has_nmrium) { + // alert() + // this.infoLog("Loading Spectra from NMRium JSON.."); + // axios + // .get("/datasets/" + this.dataset.id + "/nmriumInfo") + // .then((response) => { + // this.updateLoadingStatus(false); + // nmrium_info = JSON.parse( + // response.data.nmrium_info + // ); + // let nmriumVersion = 4; + // if (nmrium_info && nmrium_info["version"]) { + // nmriumVersion = nmrium_info["version"]; + // } + // if (nmrium_info && nmrium_info["spectra"]) { + // if (this.isString(nmrium_info["spectra"])) { + // spectra = JSON.parse( + // nmrium_info.spectra + // ); + // } else { + // spectra = nmrium_info.spectra; + // } + // } + // if (spectra && spectra.length <= 0) { + // this.loadFromURL(url); + // } else { + // let mols = []; + // if (this.isString(nmrium_info.molecules)) { + // mols = JSON.parse( + // nmrium_info.molecules + // ); + // } else { + // mols = nmrium_info.molecules; + // } + // if (mols && mols.length > 0) { + // this.currentMolecules = mols; + // mols.forEach((mol) => { + // mol.molfile = + // "\n" + mol.molfile + "\n"; + // }); + // } + // let data = { + // data: { + // spectra: spectra, + // molecules: mols, + // version: nmriumVersion, + // }, + // type: "nmrium", + // }; + // iframe.postMessage( + // { type: `nmr-wrapper:load`, data }, + // "*" + // ); + // this.selectedSpectraData = spectra; + // } + // }); + // } else { + // this.loadFromURL(url); + // } } } }, - loadFromURL(url) { + loadFromURL(urls) { this.infoLog("Loading Spectra from URL.."); this.dataset.type = null; this.selectedSpectraData = null; this.reset = true; const iframe = window.frames.NMRiumIframe; - let ownerUserName = this.$page.props.team - ? this.$page.props.team.owner.username - : this.project.owner.username; - if (!url) { - url = - this.url + - "/" + - ownerUserName + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; - } let data = { - data: [url], + data: urls, type: "url", }; iframe.postMessage({ type: `nmr-wrapper:load`, data }, "*"); diff --git a/resources/js/Shared/StudyInfo.vue b/resources/js/Shared/StudyInfo.vue new file mode 100644 index 00000000..363a2c47 --- /dev/null +++ b/resources/js/Shared/StudyInfo.vue @@ -0,0 +1,133 @@ + + + diff --git a/resources/js/Shared/Submission.vue b/resources/js/Shared/Submission.vue index c2e16e4e..74216d52 100644 --- a/resources/js/Shared/Submission.vue +++ b/resources/js/Shared/Submission.vue @@ -2490,7 +2490,7 @@ export default { } else if (id == 2) { this.$nextTick(function () { if (this.$refs.spectraEditorREF) { - this.$refs.spectraEditorREF.registerEvents(); + // this.$refs.spectraEditorREF.registerEvents(); } }); } diff --git a/resources/js/Shared/Validation.vue b/resources/js/Shared/Validation.vue index dcd91d70..ada1120a 100644 --- a/resources/js/Shared/Validation.vue +++ b/resources/js/Shared/Validation.vue @@ -61,7 +61,7 @@ >
-
+
    - Studies + Samples

name('dashboard'); + Route::get('upload', [UploadController::class, 'upload'])->name('upload'); + Route::get('publish/{draft}', [UploadController::class, 'publish'])->name('publish'); + Route::group([ 'prefix' => 'dashboard', ], function () { @@ -164,6 +168,8 @@ ->name('dashboard.studies'); Route::get('studies/{study}/files', [StudyController::class, 'files']) ->name('dashboard.study.files'); + Route::get('studies/{study}/nmredata', [StudyController::class, 'annotations']) + ->name('dashboard.study.nmredata'); Route::get('studies/{study}/datasets', [StudyController::class, 'datasets']) ->name('dashboard.study.datasets'); Route::get('studies/{study}/settings', [StudyController::class, 'settings']) @@ -184,6 +190,13 @@ Route::delete('/studies/{study}/members/{user}', [StudyMemberController::class, 'removeMember']) ->name('study-members.destroy'); + Route::get('studies/{study}/nmriumVersions', [StudyController::class, 'nmriumVersions']) + ->name('dashboard.studies.nmriumVersions'); + Route::get('studies/{study}/nmriumInfo', [StudyController::class, 'fetchNMRium']) + ->name('dashboard.studies.nmrium'); + Route::post('studies/{study}/nmriumInfo', [StudyController::class, 'nmriumInfo']) + ->name('dashboard.studies.nmriumInfo'); + Route::post('studies/{study}/molecule', [StudyController::class, 'moleculeStore']) ->name('study-molecule.store'); Route::delete('studies/{study}/molecule/{molecule}', [StudyController::class, 'moleculeDetach']) @@ -208,6 +221,8 @@ ->name('dashboard.draft.info'); Route::get('drafts/{draft}/files', [DraftController::class, 'files']) ->name('dashboard.draft.files'); + Route::put('drafts/{draft}', [DraftController::class, 'update']) + ->name('dashboard.draft.update'); Route::delete('drafts/{draft}/files/{filesystemobject}', [DraftController::class, 'deleteFSO']) ->name('dashboard.draft.files.delete'); Route::get('drafts/{draft}/annotate', [DraftController::class, 'annotate']) @@ -300,6 +315,9 @@ Route::get('studies/{study}/toggleStarred', [StudyController::class, 'toggleStarred']) ->name('study.toggle-starred'); +Route::get('studies/{study}/nmriumInfo', [StudyController::class, 'fetchNMRium']) + ->name('dashboard.studies.nmrium'); + Route::get('projects/{project}/studies', [ProjectController::class, 'publicStudies']) ->name('project.studies'); From 224160971314a541f94270d835eddfe56c63e7c8 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 14:24:34 +0200 Subject: [PATCH 02/38] build: push image to Docker --- .../workflows/{build.yml => dev-build.yml} | 71 +++++++++++-------- 1 file changed, 41 insertions(+), 30 deletions(-) rename .github/workflows/{build.yml => dev-build.yml} (65%) diff --git a/.github/workflows/build.yml b/.github/workflows/dev-build.yml similarity index 65% rename from .github/workflows/build.yml rename to .github/workflows/dev-build.yml index 29e74086..38990b7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/dev-build.yml @@ -1,8 +1,12 @@ name : Deploy to Dev +# on: +# push: +# branches: [development] + on: push: - branches: [development] + branches: [issue-#877] env: PROJECT_ID: ${{ secrets.GKE_PROJECT }} @@ -11,9 +15,10 @@ env: DEPLOYMENT_NAME: nmrxiv-nmrxiv-app SCHEDULER_DEPLOYMENT_NAME: nmrxiv-scheduler WORKER_DEPLOYMENT_NAME: nmrxiv-worker - REPOSITORY_NAME: nmrxiv-dev - APP_IMAGE: nmrxiv-app - NGINX_IMAGE: nmrxiv-nginx + DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_HUB_USERNAME }} + DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_HUB_PASSWORD }} + REPOSITORY_NAME: nmrxiv + REPOSITORY_NAMESPACE: nfdi4chem jobs: php-unit-test: @@ -79,40 +84,46 @@ jobs: service_account_key: ${{ secrets.GKE_SA_KEY }} project_id: ${{ secrets.GKE_PROJECT }} - # Configure docker to use the gcloud command-line tool as a credential helper - - run: |- - gcloud auth configure-docker europe-west3-docker.pkg.dev - # Get the GKE credentials so we can deploy to the cluster + # Get the GKE credentials - uses: google-github-actions/get-gke-credentials@v0.3.0 with: cluster_name: ${{ env.GKE_CLUSTER }} location: ${{ env.GKE_ZONE }} credentials: ${{ secrets.GKE_SA_KEY }} - # Build the Docker image - - name: Build App Image - run: |- - docker build -f ./resources/ops/docker/app/app.dockerfile \ - --tag "europe-west3-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$APP_IMAGE:latest" \ - --build-arg GITHUB_SHA="$GITHUB_SHA" \ - --build-arg GITHUB_REF="$GITHUB_REF" \ - . - - name: Build Nginx Image - run: |- - docker build -f ./resources/ops/docker/nginx/nginx.dockerfile \ - --tag "europe-west3-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$NGINX_IMAGE:latest" \ - --build-arg GITHUB_SHA="$GITHUB_SHA" \ - --build-arg GITHUB_REF="$GITHUB_REF" \ - . - # Push the Docker image to Google Container Registry - - name: Publish App Image to GCR - run: |- - docker push "europe-west3-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$APP_IMAGE:latest" + - name: Log in to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} - - name: Publish Nginx Image to GCR - run: |- - docker push "europe-west3-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$NGINX_IMAGE:latest" + # Build and push the app Docker image + - name: Build and push App Docker image + uses: docker/build-push-action@v4 + with: + context: . + file: ./resources/ops/docker/app/app.dockerfile + push: true + build-args: | + RELEASE_VERSION=dev-app-latest + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:dev-app-latest + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + + # Build and push the nginx Docker image + - name: Build and push Nginx Docker image + uses: docker/build-push-action@v4 + with: + context: . + file: ./resources/ops/docker/app/app.dockerfile + push: true + build-args: | + RELEASE_VERSION=dev-nginx-latest + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:dev-nginx-latest + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + # Deploy the latest Docker image to the GKE cluster - name: Deploy run: |- kubectl rollout restart deployment/$DEPLOYMENT_NAME From 5ab3f7e66386c9900d14b6808895053d0633faa5 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 14:28:37 +0200 Subject: [PATCH 03/38] build: remove github ref --- .github/workflows/dev-build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 38990b7c..a2e57ca6 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -71,7 +71,6 @@ jobs: setup-build-publish-deploy: name: Build & deploy to development - if: github.ref == 'refs/heads/development' runs-on: ubuntu-latest needs: php-unit-test steps: From f1485892baa12b39f542a9f56c7d5335d2bb0a7f Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 18 Oct 2023 14:39:15 +0200 Subject: [PATCH 04/38] fix: ui updates --- resources/js/Pages/Project/Index.vue | 28 ++++++------------------- resources/js/Pages/Project/Show.vue | 31 +++++++--------------------- 2 files changed, 14 insertions(+), 45 deletions(-) diff --git a/resources/js/Pages/Project/Index.vue b/resources/js/Pages/Project/Index.vue index bf1e77b6..cfebf91c 100644 --- a/resources/js/Pages/Project/Index.vue +++ b/resources/js/Pages/Project/Index.vue @@ -170,7 +170,7 @@ class="flex-grow cursor-pointer" >
-
+

- - - - - {{ tag.name["en"] }} - + {{ tag.name["en"] }}

@@ -292,13 +277,12 @@ > {{ project.description }}
-
+
Last updated onUpdated on {{ formatDate(project.updated_at) }} -
-
+ · Created on diff --git a/resources/js/Pages/Project/Show.vue b/resources/js/Pages/Project/Show.vue index 947d16b3..c695bdf9 100644 --- a/resources/js/Pages/Project/Show.vue +++ b/resources/js/Pages/Project/Show.vue @@ -77,16 +77,6 @@ Edit
- - - - -
+
+ +
@@ -411,22 +407,11 @@

- - - - - {{ tag.name["en"] }} - + {{ tag.name["en"] }}

From d3f2e8fd64569ccab1841ce2b840cf609fe5b573 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 18 Oct 2023 14:51:37 +0200 Subject: [PATCH 05/38] fix: inertia migration update --- resources/js/Pages/Upload.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/Pages/Upload.vue b/resources/js/Pages/Upload.vue index f0fe7eec..d1037c6e 100644 --- a/resources/js/Pages/Upload.vue +++ b/resources/js/Pages/Upload.vue @@ -2101,7 +2101,7 @@ import AppLayout from "@/Layouts/AppLayout.vue"; import TeamProjects from "@/Pages/Project/Index.vue"; import Create from "@/Shared/CreateButton.vue"; import Onboarding from "@/App/Onboarding.vue"; -import { Link } from "@inertiajs/inertia-vue3"; +import { Link } from '@inertiajs/vue3' import { computed } from "vue"; import FileSystemBrowser from "./../Shared/FileSystemBrowser.vue"; import JetInputError from "@/Jetstream/InputError.vue"; From 3c82888ec37011d17bcb10b2e887b93a20ff7472 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 15:04:00 +0200 Subject: [PATCH 06/38] build: update nginx docker imahe build path --- .github/workflows/dev-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index a2e57ca6..80b90955 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -114,7 +114,7 @@ jobs: uses: docker/build-push-action@v4 with: context: . - file: ./resources/ops/docker/app/app.dockerfile + file: ./resources/ops/docker/app/nginx.dockerfile push: true build-args: | RELEASE_VERSION=dev-nginx-latest From f8d448a8a74e282672bc00130ef745e42cba6d4f Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 15:10:45 +0200 Subject: [PATCH 07/38] build: correct nginx image path --- .github/workflows/dev-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 80b90955..5558416e 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -114,7 +114,7 @@ jobs: uses: docker/build-push-action@v4 with: context: . - file: ./resources/ops/docker/app/nginx.dockerfile + file: ./resources/ops/docker/nginx/nginx.dockerfile push: true build-args: | RELEASE_VERSION=dev-nginx-latest From 6a37e8652a1d090f6f34da1135e5321479283323 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 15:19:53 +0200 Subject: [PATCH 08/38] fix: push images to Docker Hub --- .github/workflows/dev-build.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 5558416e..f81dbf89 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -1,12 +1,8 @@ name : Deploy to Dev -# on: -# push: -# branches: [development] - on: push: - branches: [issue-#877] + branches: [development] env: PROJECT_ID: ${{ secrets.GKE_PROJECT }} From 7981b1d22e0d1f03d515748aa7d8b1737db009c1 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 18 Oct 2023 15:43:27 +0200 Subject: [PATCH 09/38] fix: updated default message on nmrium --- resources/js/Shared/SpectraEditor.vue | 2 +- resources/js/Shared/SpectraViewer.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index 60f796ff..6c0f570b 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -379,7 +379,7 @@ export default { nmriumURL() { return this.$page.props.nmriumURL ? String(this.$page.props.nmriumURL + "&id=" + Math.random()) - : "https://nmriumdev.nmrxiv.org?workspace=embedded&id=" + + : "https://nmriumdev.nmrxiv.org?defaultEmptyMessage=''&workspace=embedded&id=" + Math.random(); }, diff --git a/resources/js/Shared/SpectraViewer.vue b/resources/js/Shared/SpectraViewer.vue index df692847..dc817537 100644 --- a/resources/js/Shared/SpectraViewer.vue +++ b/resources/js/Shared/SpectraViewer.vue @@ -319,7 +319,7 @@ export default { nmriumURL() { return this.$page.props.nmriumURL ? String(this.$page.props.nmriumURL + "?id=" + Math.random()) - : "http://nmriumdev.nmrxiv.org?id=" + Math.random(); + : "http://nmriumdev.nmrxiv.org?defaultEmptyMessage=loading&workspace=embedded&id=" + Math.random(); }, }, methods: { From aa960ad93f61c01725aabb9eccb9f7960967d463 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Wed, 18 Oct 2023 15:52:08 +0200 Subject: [PATCH 10/38] build: seperate test and invoke on workflow call --- .env.ci.dev => .env.ci.test | 0 .github/workflows/dev-build.yml | 47 +---------------------------- .github/workflows/test.yml | 52 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 46 deletions(-) rename .env.ci.dev => .env.ci.test (100%) create mode 100644 .github/workflows/test.yml diff --git a/.env.ci.dev b/.env.ci.test similarity index 100% rename from .env.ci.dev rename to .env.ci.test diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index f81dbf89..ec89c760 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -18,52 +18,7 @@ env: jobs: php-unit-test: - name: Run test - runs-on: ubuntu-latest - container: - image: kirschbaumdevelopment/laravel-test-runner:8.2 - - services: - postgres: - image: postgres:13 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: nmrxiv - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - - name: Install composer dependencies - run: | - composer install --ignore-platform-reqs - - name: Prepare Laravel Application - run: | - php -r "file_exists('.env') || copy('.env.ci.dev', '.env');" - - echo AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID_DEV }} >> .env - echo AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }} >> .env - echo MEILISEARCH_KEY=${{ secrets.MEILISEARCH_KEY_DEV }} >> .env - echo MEILISEARCH_PUBLICKEY=${{ secrets.MEILISEARCH_PUBLICKEY_DEV }} >> .env - echo TWITTER_CLIENT_ID=${{ secrets.TWITTER_CLIENT_ID_DEV }} >> .env - echo TWITTER_CLIENT_SECRET=${{ secrets.TWITTER_CLIENT_SECRET_DEV }} >> .env - echo GITHUB_CLIENT_ID=${{ secrets.CLIENT_ID_GITHUB_DEV }} >> .env - echo GITHUB_CLIENT_SECRET=${{ secrets.CLIENT_SECRET_GITHUB_DEV }} >> .env - - php artisan key:generate - php artisan migrate --seed - - name: Install front-end dependencies - run: | - npm install - npm run build - - name: Run Test - run: php artisan test --parallel - + uses: NFDI4Chem/nmrxiv/.github/workflows/test.yml@development setup-build-publish-deploy: name: Build & deploy to development diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..62fdc3d0 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,52 @@ +name : Test + +on: + workflow_call: + +jobs: + php-unit-test: + name: Run test + runs-on: ubuntu-latest + container: + image: kirschbaumdevelopment/laravel-test-runner:8.2 + + services: + postgres: + image: postgres:13 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: nmrxiv + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Install composer dependencies + run: | + composer install --ignore-platform-reqs + - name: Prepare Laravel Application + run: | + php -r "file_exists('.env') || copy('.env.ci.test', '.env');" + + echo AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID_DEV }} >> .env + echo AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }} >> .env + echo MEILISEARCH_KEY=${{ secrets.MEILISEARCH_KEY_DEV }} >> .env + echo MEILISEARCH_PUBLICKEY=${{ secrets.MEILISEARCH_PUBLICKEY_DEV }} >> .env + echo TWITTER_CLIENT_ID=${{ secrets.TWITTER_CLIENT_ID_DEV }} >> .env + echo TWITTER_CLIENT_SECRET=${{ secrets.TWITTER_CLIENT_SECRET_DEV }} >> .env + echo GITHUB_CLIENT_ID=${{ secrets.CLIENT_ID_GITHUB_DEV }} >> .env + echo GITHUB_CLIENT_SECRET=${{ secrets.CLIENT_SECRET_GITHUB_DEV }} >> .env + + php artisan key:generate + php artisan migrate --seed + - name: Install front-end dependencies + run: | + npm install + npm run build + - name: Run Test + run: php artisan test --parallel \ No newline at end of file From ee6c9b014679c373e01fa754d4a5afd9682e1aa6 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 18 Oct 2023 15:59:34 +0200 Subject: [PATCH 11/38] fix: updated spectra viewer --- resources/js/Shared/SpectraViewer.vue | 184 ++++++++++++++------------ routes/web.php | 3 + 2 files changed, 101 insertions(+), 86 deletions(-) diff --git a/resources/js/Shared/SpectraViewer.vue b/resources/js/Shared/SpectraViewer.vue index 0421573f..dc817537 100644 --- a/resources/js/Shared/SpectraViewer.vue +++ b/resources/js/Shared/SpectraViewer.vue @@ -319,7 +319,7 @@ export default { nmriumURL() { return this.$page.props.nmriumURL ? String(this.$page.props.nmriumURL + "?id=" + Math.random()) - : "http://nmriumdev.nmrxiv.org?id=" + Math.random(); + : "http://nmriumdev.nmrxiv.org?defaultEmptyMessage=loading&workspace=embedded&id=" + Math.random(); }, }, methods: { @@ -329,103 +329,115 @@ export default { this.spectraError = null; this.currentMolecules = []; this.updateLoadingStatus(true); - let url = - this.url + - "/" + - this.project.owner.username + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; + if (iframe) { - let spectra = []; - let nmrium_info = null; - if (this.dataset && this.dataset.has_nmrium) { - this.infoLog("Loading Spectra from NMRium JSON.."); - axios - .get("/datasets/" + this.dataset.id + "/nmriumInfo") - .then((response) => { - this.updateLoadingStatus(false); - nmrium_info = JSON.parse( - response.data.nmrium_info - ); - let nmriumVersion = 4; - if (nmrium_info && nmrium_info["version"]) { - nmriumVersion = nmrium_info["version"]; - } - if (nmrium_info && nmrium_info["spectra"]) { - if (this.isString(nmrium_info["spectra"])) { - spectra = JSON.parse( - nmrium_info.spectra - ); - } else { - spectra = nmrium_info.spectra; - } - } - if (spectra && spectra.length <= 0) { - this.loadFromURL(url); - } else { - let mols = []; - if (this.isString(nmrium_info.molecules)) { - mols = JSON.parse( - nmrium_info.molecules - ); - } else { - mols = nmrium_info.molecules; - } - if (mols && mols.length > 0) { - this.currentMolecules = mols; - mols.forEach((mol) => { - mol.molfile = - "\n" + mol.molfile + "\n"; - }); - } - let data = { - data: { - spectra: spectra, - molecules: mols, - version: nmriumVersion, - }, - type: "nmrium", - }; - iframe.postMessage( - { type: `nmr-wrapper:load`, data }, - "*" - ); - this.selectedSpectraData = spectra; - } - }); + let urls = []; + let username = + this.$page.props.team && this.$page.props.team.owner + ? this.$page.props.team.owner.username + : this.project.owner.username; + if (this.study.datasets) { + this.study.datasets.forEach((dataset) => { + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug + + "/" + + dataset.slug; + urls.push(url); + }); + this.loadFromURL(urls); } else { - this.loadFromURL(url); + if (this.dataset) { + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug + + "/" + + this.dataset.slug; + urls.push(url); + this.loadFromURL(urls); + } } + + // if (this.dataset && this.dataset.has_nmrium) { + // alert() + // this.infoLog("Loading Spectra from NMRium JSON.."); + // axios + // .get("/datasets/" + this.dataset.id + "/nmriumInfo") + // .then((response) => { + // this.updateLoadingStatus(false); + // nmrium_info = JSON.parse( + // response.data.nmrium_info + // ); + // let nmriumVersion = 4; + // if (nmrium_info && nmrium_info["version"]) { + // nmriumVersion = nmrium_info["version"]; + // } + // if (nmrium_info && nmrium_info["spectra"]) { + // if (this.isString(nmrium_info["spectra"])) { + // spectra = JSON.parse( + // nmrium_info.spectra + // ); + // } else { + // spectra = nmrium_info.spectra; + // } + // } + // if (spectra && spectra.length <= 0) { + // this.loadFromURL(url); + // } else { + // let mols = []; + // if (this.isString(nmrium_info.molecules)) { + // mols = JSON.parse( + // nmrium_info.molecules + // ); + // } else { + // mols = nmrium_info.molecules; + // } + // if (mols && mols.length > 0) { + // this.currentMolecules = mols; + // mols.forEach((mol) => { + // mol.molfile = + // "\n" + mol.molfile + "\n"; + // }); + // } + // let data = { + // data: { + // spectra: spectra, + // molecules: mols, + // version: nmriumVersion, + // }, + // type: "nmrium", + // }; + // iframe.postMessage( + // { type: `nmr-wrapper:load`, data }, + // "*" + // ); + // this.selectedSpectraData = spectra; + // } + // }); + // } else { + // this.loadFromURL(url); + // } } } }, - loadFromURL(url) { + loadFromURL(urls) { this.infoLog("Loading Spectra from URL.."); this.dataset.type = null; this.selectedSpectraData = null; this.reset = true; const iframe = window.frames.NMRiumIframe; - let ownerUserName = this.$page.props.team - ? this.$page.props.team.owner.username - : this.project.owner.username; - if (!url) { - url = - this.url + - "/" + - ownerUserName + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; - } let data = { - data: [url], + data: urls, type: "url", }; iframe.postMessage({ type: `nmr-wrapper:load`, data }, "*"); diff --git a/routes/web.php b/routes/web.php index 50c8fbed..ac3160f6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -303,6 +303,9 @@ Route::get('studies/{study}/toggleStarred', [StudyController::class, 'toggleStarred']) ->name('study.toggle-starred'); +Route::get('studies/{study}/nmriumInfo', [StudyController::class, 'fetchNMRium']) + ->name('dashboard.studies.nmrium'); + Route::get('projects/{project}/studies', [ProjectController::class, 'publicStudies']) ->name('project.studies'); From afe16e388a2e20a3332c0e18c04021cbb6af650c Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Wed, 18 Oct 2023 16:40:33 +0200 Subject: [PATCH 12/38] fix: updated spectra viewer and public study page --- resources/js/Pages/Public/Project/Study.vue | 104 +++++++++++++++++++- resources/js/Shared/SpectraViewer.vue | 3 +- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/resources/js/Pages/Public/Project/Study.vue b/resources/js/Pages/Public/Project/Study.vue index 9fdf36a6..73daea40 100644 --- a/resources/js/Pages/Public/Project/Study.vue +++ b/resources/js/Pages/Public/Project/Study.vue @@ -299,7 +299,7 @@
-
+
+ +
+ + +
+
diff --git a/resources/js/Shared/SpectraViewer.vue b/resources/js/Shared/SpectraViewer.vue index dc817537..d0114cd0 100644 --- a/resources/js/Shared/SpectraViewer.vue +++ b/resources/js/Shared/SpectraViewer.vue @@ -319,7 +319,8 @@ export default { nmriumURL() { return this.$page.props.nmriumURL ? String(this.$page.props.nmriumURL + "?id=" + Math.random()) - : "http://nmriumdev.nmrxiv.org?defaultEmptyMessage=loading&workspace=embedded&id=" + Math.random(); + : "http://nmriumdev.nmrxiv.org?defaultEmptyMessage=loading&workspace=embedded&id=" + + Math.random(); }, }, methods: { From ff42756ec03d826c6aa64f10d76d5239dffa6a3d Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 19 Oct 2023 09:47:12 +0200 Subject: [PATCH 13/38] fix: avoiding unnecessary processing of folders --- app/Http/Controllers/DraftController.php | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 38a315f1..6f026ab6 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -433,22 +433,26 @@ public function processFolder($folders) { foreach ($folders as $folder) { if ($folder->type == 'directory') { - if ($this->isBruker($folder)) { - $this->saveInstrumentType($folder, 'bruker'); - $this->saveModelType($folder->parent); - } elseif ($this->isVarian($folder)) { - $this->saveInstrumentType($folder, 'varian'); - $this->saveModelType($folder->parent); - } else { - $this->processFolder($folder->children); + if ($folder->instrument_type != null) { + if ($this->isBruker($folder)) { + $this->saveInstrumentType($folder, 'bruker'); + $this->saveModelType($folder->parent); + } elseif ($this->isVarian($folder)) { + $this->saveInstrumentType($folder, 'varian'); + $this->saveModelType($folder->parent); + } else { + $this->processFolder($folder->children); + } } } else { - if ($this->isJOEL($folder)) { - $this->saveInstrumentType($folder, 'joel'); - $this->saveModelType($folder->parent); - } elseif ($this->isJcampDX($folder)) { - $this->saveInstrumentType($folder, 'jcamp'); - $this->saveModelType($folder->parent); + if ($folder->instrument_type != null) { + if ($this->isJOEL($folder)) { + $this->saveInstrumentType($folder, 'joel'); + $this->saveModelType($folder->parent); + } elseif ($this->isJcampDX($folder)) { + $this->saveInstrumentType($folder, 'jcamp'); + $this->saveModelType($folder->parent); + } } } } From a80539878d496b952d6092a99f872950a8b2796e Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 10:43:57 +0200 Subject: [PATCH 14/38] build: test php unit test --- .github/workflows/dev-build.yml | 49 ++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index ec89c760..59ca0a60 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -17,8 +17,55 @@ env: REPOSITORY_NAMESPACE: nfdi4chem jobs: + # php-unit-test: + # uses: NFDI4Chem/nmrxiv/.github/workflows/test.yml@development + php-unit-test: - uses: NFDI4Chem/nmrxiv/.github/workflows/test.yml@development + name: Run test + runs-on: ubuntu-latest + container: + image: kirschbaumdevelopment/laravel-test-runner:8.2 + + services: + postgres: + image: postgres:13 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: nmrxiv + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Install composer dependencies + run: | + composer install --ignore-platform-reqs + - name: Prepare Laravel Application + run: | + php -r "file_exists('.env') || copy('.env.ci.test', '.env');" + + echo AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID_DEV }} >> .env + echo AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY_DEV }} >> .env + echo MEILISEARCH_KEY=${{ secrets.MEILISEARCH_KEY_DEV }} >> .env + echo MEILISEARCH_PUBLICKEY=${{ secrets.MEILISEARCH_PUBLICKEY_DEV }} >> .env + echo TWITTER_CLIENT_ID=${{ secrets.TWITTER_CLIENT_ID_DEV }} >> .env + echo TWITTER_CLIENT_SECRET=${{ secrets.TWITTER_CLIENT_SECRET_DEV }} >> .env + echo GITHUB_CLIENT_ID=${{ secrets.CLIENT_ID_GITHUB_DEV }} >> .env + echo GITHUB_CLIENT_SECRET=${{ secrets.CLIENT_SECRET_GITHUB_DEV }} >> .env + + php artisan key:generate + php artisan migrate --seed + - name: Install front-end dependencies + run: | + npm install + npm run build + - name: Run Test + run: php artisan test --parallel setup-build-publish-deploy: name: Build & deploy to development From aa20bccaaaf5ac01b9b04025c11de96cc454986f Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 19 Oct 2023 10:49:06 +0200 Subject: [PATCH 15/38] fix: migrated spectra editor to support latest study based nmrium json save --- app/Http/Controllers/DownloadController.php | 3 + app/Http/Controllers/DraftController.php | 9 +- app/Http/Controllers/StudyController.php | 83 ++++++ app/Models/Dataset.php | 5 +- app/Models/Study.php | 6 + app/Models/Validation.php | 4 +- .../2023_08_25_111326_update_nmrium_table.php | 32 ++ resources/js/Shared/SpectraEditor.vue | 273 ++++++++++-------- resources/js/Shared/Submission.vue | 5 +- routes/web.php | 7 + 10 files changed, 296 insertions(+), 131 deletions(-) create mode 100644 database/migrations/2023_08_25_111326_update_nmrium_table.php diff --git a/app/Http/Controllers/DownloadController.php b/app/Http/Controllers/DownloadController.php index cd16a119..06031a8b 100644 --- a/app/Http/Controllers/DownloadController.php +++ b/app/Http/Controllers/DownloadController.php @@ -20,6 +20,9 @@ public function downloadSet(Request $request, $username, $project, $study = null if (str_contains($dataset, '.zip')) { $dataset = str_replace('.zip', '', $dataset); } + if (str_contains($study, '.zip')) { + $study = str_replace('.zip', '', $study); + } $user = User::where('username', $username)->firstOrFail(); if ($project) { $project = Project::where([['slug', $project], ['owner_id', $user->id]])->firstOrFail(); diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 6f026ab6..3431127f 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -246,6 +246,7 @@ public function process(Request $request, Draft $draft) ['draft_id', $draft->id], ['status', '<>', 'missing'], ['model_type', 'study'], + ['is_processed', false], ]) ->orderBy('type') ->get(); @@ -284,6 +285,7 @@ public function process(Request $request, Draft $draft) $study->sample()->save($sample); $folder->study_id = $study->id; + $folder->is_processed = true; $folder->save(); } @@ -319,6 +321,7 @@ public function process(Request $request, Draft $draft) $ds->save(); $sChild->dataset_id = $ds->id; + $sChild->is_processed = true; $sChild->save(); } } @@ -359,6 +362,7 @@ public function process(Request $request, Draft $draft) $study->sample()->save($sample); $folder->study_id = $study->id; + $folder->is_processed = true; $folder->save(); $ds = Dataset::where([ @@ -383,6 +387,7 @@ public function process(Request $request, Draft $draft) ]); $folder->dataset_id = $ds->id; + $folder->is_processed = true; $folder->save(); } } @@ -433,7 +438,7 @@ public function processFolder($folders) { foreach ($folders as $folder) { if ($folder->type == 'directory') { - if ($folder->instrument_type != null) { + if ($folder->instrument_type == null) { if ($this->isBruker($folder)) { $this->saveInstrumentType($folder, 'bruker'); $this->saveModelType($folder->parent); @@ -445,7 +450,7 @@ public function processFolder($folders) } } } else { - if ($folder->instrument_type != null) { + if ($folder->instrument_type == null) { if ($this->isJOEL($folder)) { $this->saveInstrumentType($folder, 'joel'); $this->saveModelType($folder->parent); diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index 1d42e2bb..6289329f 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -7,6 +7,7 @@ use App\Actions\Study\UpdateStudy; use App\Models\FileSystemObject; use App\Models\Molecule; +use App\Models\NMRium; use App\Models\Sample; use App\Models\Study; use Auth; @@ -135,6 +136,69 @@ public function moleculeStore(Request $request, Study $study) return $sample->molecules; } + public function fetchNMRium(Request $request, Study $study) + { + if ($study) { + $nmrium = $study->nmrium; + if ($nmrium) { + return json_decode($nmrium->nmrium_info); + } else { + return null; + } + } + } + + public function nmriumVersions(Request $request, Study $study) + { + if ($study) { + $nmrium = $study->nmrium; + + if ($nmrium) { + return $nmrium->versions()->orderBy('created_at', 'DESC')->get()->map(function ($version) { + $user = User::find($version->user_id); + + return [ + 'updated_at' => $version->updated_at, + 'user' => [ + 'name' => $user->first_name.' '.$user->last_name, + 'profile_photo_url' => $user->profile_photo_url, + ], + ]; + }); + } + } + } + + public function nmriumInfo(Request $request, Study $study) + { + if ($study) { + $user = Auth::user(); + $data = $request->all(); + $version = $request->get('version'); + // $spectra = $request->get('spectra'); + // $molecules = $request->get('molecules'); + + $nmriumInfo = $data; + // $molecularInfo = $molecules; + $nmrium = $study->nmrium; + + if ($nmrium) { + $nmrium->nmrium_info = $nmriumInfo; + $study->has_nmrium = true; + $nmrium->save(); + } else { + $nmrium = NMRium::create([ + 'nmrium_info' => json_encode($nmriumInfo), + ]); + $study->nmrium()->save($nmrium); + $study->has_nmrium = true; + } + $study->save(); + + return $study->fresh(); + } + } + public function moleculeDetach(Request $request, Study $study, Molecule $molecule) { if ($molecule) { @@ -180,6 +244,25 @@ public function files(Request $request, Study $study) ]); } + public function annotations(Request $request, Study $study) + { + if (! Gate::forUser($request->user())->check('viewStudy', $study)) { + throw new AuthorizationException; + } + + $studyFSObject = FileSystemObject::with('children') + ->where([ + ['study_id', $study->id], + ['level', $study->fsObject->level], + ]) + ->orderBy('type') + ->first(); + + return $studyFSObject->children->filter(function ($child) { + return $child->instrument_type == 'nmredata'; + })->values(); + } + public function file(Request $request, $code, Study $study, $filename) { $file = FileSystemObject::with('project', 'study') diff --git a/app/Models/Dataset.php b/app/Models/Dataset.php index 7a00dcfa..5090dfc6 100644 --- a/app/Models/Dataset.php +++ b/app/Models/Dataset.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphOne; use OwenIt\Auditing\Contracts\Auditable; use Storage; @@ -111,9 +112,9 @@ public function team() return $this->belongsTo(Team::class, 'Team_id'); } - public function nmrium() + public function nmrium(): MorphOne { - return $this->hasOne(NMRium::class); + return $this->morphOne(NMRium::class, 'nmriumable'); } public function fsObject() diff --git a/app/Models/Study.php b/app/Models/Study.php index 6676ba9a..d25001a7 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphOne; use Laravel\Scout\Searchable; use Maize\Markable\Markable; use Maize\Markable\Models\Bookmark; @@ -163,6 +164,11 @@ public function studyInvitations() return $this->hasMany(StudyInvitation::class); } + public function nmrium(): MorphOne + { + return $this->morphOne(NMRium::class, 'nmriumable'); + } + /** * Get the user study role * diff --git a/app/Models/Validation.php b/app/Models/Validation.php index 4d0e1715..a439e08e 100644 --- a/app/Models/Validation.php +++ b/app/Models/Validation.php @@ -180,9 +180,9 @@ public function process() $values = [ 'files' => $dataset->fsObject ? $dataset->fsObject->instrument_type : null, - 'nmrium_info' => $dataset->has_nmrium ? $dataset->has_nmrium : null, + 'nmrium_info' => ($study->has_nmrium || $dataset->has_nmrium) ? $dataset->has_nmrium : null, 'assay' => $dataset->assay, - 'assignments' => $dataset->has_nmrium ? $dataset->has_nmrium : null, + 'assignments' => ($study->has_nmrium || $dataset->has_nmrium) ? $dataset->has_nmrium : null, ]; $dataset_rules = $rules['dataset']; diff --git a/database/migrations/2023_08_25_111326_update_nmrium_table.php b/database/migrations/2023_08_25_111326_update_nmrium_table.php new file mode 100644 index 00000000..b690e4a9 --- /dev/null +++ b/database/migrations/2023_08_25_111326_update_nmrium_table.php @@ -0,0 +1,32 @@ +renameColumn('dataset_id', 'nmriumable_id'); + $table->string('nmriumable_type')->default('App\Models\Dataset'); + }); + + Schema::table('studies', function (Blueprint $table) { + $table->boolean('has_nmrium')->nullable()->default(0); + $table->boolean('has_nmredata')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index fca0e7cf..6c0f570b 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -10,7 +10,7 @@ >Learn more Reset @@ -75,7 +75,7 @@ :src="nmriumURL" @load="loadSpectra()" > -
+
@@ -348,6 +348,12 @@ export default { this.loadSpectra(); }, }, + study: { + immediate: true, + handler() { + this.loadSpectra(); + }, + }, }, setup() { const versionsElement = ref(null); @@ -372,8 +378,9 @@ export default { }, nmriumURL() { return this.$page.props.nmriumURL - ? String(this.$page.props.nmriumURL + "?id=" + Math.random()) - : "http://nmriumdev.nmrxiv.org?id=" + Math.random(); + ? String(this.$page.props.nmriumURL + "&id=" + Math.random()) + : "https://nmriumdev.nmrxiv.org?defaultEmptyMessage=''&workspace=embedded&id=" + + Math.random(); }, mailFromAddress() { @@ -384,58 +391,89 @@ export default { registerEvents() { const saveNMRiumUpdates = (e) => { const { data, type } = e.data; - if ( - e.origin != "https://nmriumdev.nmrxiv.org" && - e.origin != "https://nmrium.nmrxiv.org" - ) { - return; - } - if (type == "nmr-wrapper:error") { - this.spectraError = e.data; - this.updateLoadingStatus(false); - - return; - } - if (type == "nmr-wrapper:action-response") { - let actionType = e.data.type; - if (actionType == "exportSpectraViewerAsBlob") { - this.saveStudyPreview(data); - } - } - if (type == "nmr-wrapper:data-change") { - const state = data.state; - this.version = state.version; - let actionType = state.data.actionType; + if (data && data.source == "data") { if ( - actionType == "" || - (actionType == "INITIATE" && - this.dataset && - this.dataset.has_nmrium && - !this.reset) + e.origin != "https://nmriumdev.nmrxiv.org" && + e.origin != "https://nmrium.nmrxiv.org" ) { - this.infoLog("Spectra loaded successfully...", true); return; } - this.selectedSpectraData = state.data.spectra; - if ( - actionType == "ADD_MOLECULE" || - actionType == "DELETE_MOLECULE" || - state.data.molecules - ) { - this.currentMolecules = state.data.molecules; + if (type == "nmr-wrapper:error") { + this.spectraError = e.data; + this.updateLoadingStatus(false); + + return; } + if (type == "nmr-wrapper:action-response") { + let state = data.state; + this.version = state.version; + let actionType = state.data.actionType; + if (actionType == "exportSpectraViewerAsBlob") { + this.saveStudyPreview(data); + } + } + if (type == "nmr-wrapper:data-change") { + let state = data.state; + this.version = state.version; + let actionType = state.data.actionType; + // console.log(this.study.has_nmrium,actionType) + if (state.data.spectra.length > 0) { + if ( + actionType == "INITIATE" && + !this.study.has_nmrium + ) { + this.infoLog( + "Spectra loaded successfully...", + true + ); + this.selectedSpectraData = state.data; - if (this.study && this.dataset) { - if (this.dataset.dataset_photo_url == "") { - this.infoLog("Saving Preview"); - setTimeout( - function () { - this.exportPreview(); - }.bind(this), - 500 - ); + if (!this.study.has_nmrium) { + delete this.selectedSpectraData[ + "actionType" + ]; + this.selectedSpectraData.spectra.forEach( + (spec) => { + delete spec["data"]; + delete spec["info"]; + delete spec["meta"]; + delete spec["originalData"]; + delete spec["originalInfo"]; + } + ); + this.updateStudyNMRiumInfo(); + this.updateLoadingStatus(false); + } + return; + } else if ( + this.study.has_nmrium && + actionType != "INITIATE" + ) { + this.selectedSpectraData = state.data; + delete this.selectedSpectraData["actionType"]; + this.selectedSpectraData.spectra.forEach( + (spec) => { + delete spec["data"]; + delete spec["info"]; + delete spec["meta"]; + delete spec["originalData"]; + delete spec["originalInfo"]; + } + ); + this.updateStudyNMRiumInfo(); + this.updateLoadingStatus(false); + } else if ( + this.study.has_nmrium && + actionType == "INITIATE" + ) { + this.selectedSpectraData = state.data; + this.infoLog( + "Spectra loaded successfully...", + true + ); + this.updateLoadingStatus(false); + } } - this.updateDataSet(); } } }; @@ -453,115 +491,104 @@ export default { this.spectraError = null; this.currentMolecules = []; this.updateLoadingStatus(true); - let username = this.$page.props.team + let username = this.$page.props.team.owner ? this.$page.props.team.owner.username : this.project.owner.username; - let url = - this.url + - "/" + - username + - "/datasets/" + - this.project.slug + - "/" + - this.study.slug + - "/" + - this.dataset.slug; if (iframe) { - let spectra = []; - let nmrium_info = null; - if (this.dataset && this.dataset.has_nmrium) { + if (this.study && this.study.has_nmrium) { this.infoLog("Loading Spectra from NMRium JSON.."); axios .get( - "/dashboard/datasets/" + - this.dataset.id + + "/dashboard/studies/" + + this.study.id + "/nmriumInfo" ) .then((response) => { this.updateLoadingStatus(false); - nmrium_info = JSON.parse(response.nmrium_info); - if (nmrium_info && nmrium_info["data"]["spectra"]) { - if ( - this.isString( - nmrium_info["data"]["spectra"] - ) - ) { - spectra = JSON.parse( - nmrium_info.data.spectra - ); - } else { - spectra = nmrium_info.data.spectra; - } - } - if (spectra && spectra.length <= 0) { - this.loadFromURL(url); - } else { - let nmriumVersion = 4; - if (nmrium_info && nmrium_info["version"]) { - nmriumVersion = nmrium_info["version"]; - } - let mols = []; - if (this.isString(nmrium_info.data.molecules)) { - mols = JSON.parse( - nmrium_info.data.molecules - ); - } else { - mols = nmrium_info.data.molecules; - } - if (mols && mols.length > 0) { - this.currentMolecules = mols; - mols.forEach((mol) => { - mol.molfile = "\n" + mol.molfile + "\n"; - }); - } - + let nmrium_info = response.data; + if (nmrium_info) { let data = { - data: { - spectra: spectra, - molecules: mols, - version: nmriumVersion, - }, + data: nmrium_info, type: "nmrium", }; iframe.postMessage( { type: `nmr-wrapper:load`, data }, "*" ); - this.selectedSpectraData = spectra; + } else { + this.loadFromURLs(null); } }); } else { - this.loadFromURL(url); + if (this.study.datasets.length > 0) { + let urls = []; + let url = + this.url + + "/" + + username + + "/datasets/" + + this.project.slug + + "/" + + this.study.slug; + urls.push(url); + this.loadFromURLs(urls); + } } } }, - loadFromURL(url) { + loadFromURLs(urls) { this.infoLog("Loading Spectra from URL.."); - this.dataset.type = null; - this.selectedSpectraData = null; - this.reset = true; - let ownerUserName = this.$page.props.team - ? this.$page.props.team.owner.username - : this.project.owner.username; const iframe = window.frames.submissionNMRiumIframe; - if (!url) { - url = + if (!urls) { + urls = []; + let username = this.$page.props.team.owner + ? this.$page.props.team.owner.username + : this.project.owner.username; + let url = this.url + "/" + - ownerUserName + + username + "/datasets/" + this.project.slug + "/" + - this.study.slug + - "/" + - this.dataset.slug; + this.study.slug; + urls.push(url); } + let data = { - data: [url], + data: urls, type: "url", }; + iframe.postMessage({ type: `nmr-wrapper:load`, data: data }, "*"); }, + updateStudyNMRiumInfo() { + if (this.study != null && this.selectedSpectraData) { + this.updateLoadingStatus(true); + axios + .post( + "/dashboard/studies/" + this.study.id + "/nmriumInfo", + { + version: 4, + data: this.selectedSpectraData, + } + ) + .then((response) => { + this.infoLog("Spectra saved successfully", true); + this.updateLoadingStatus(false); + this.autoSaving = false; + this.study.has_nmrium = response.data.has_nmrium; + }) + .catch(() => { + this.updateLoadingStatus(false); + this.infoLog("Error saving spectra info"); + console.error( + "Error saving the nmrium info. Please contact us at {{mailFromAddress}} if the error persist." + ); + this.autoSaving = false; + }); + } + }, updateDataSet() { if (this.dataset != null && this.selectedSpectraData.length > 0) { this.updateLoadingStatus(true); diff --git a/resources/js/Shared/Submission.vue b/resources/js/Shared/Submission.vue index b926df4f..9f978f9d 100644 --- a/resources/js/Shared/Submission.vue +++ b/resources/js/Shared/Submission.vue @@ -553,6 +553,7 @@ ) " :class="[ + study.has_nmrium || ds.has_nmrium ? 'bg-green-100 text-gray-800' : 'bg-gray-100 text-gray-800', @@ -817,7 +818,7 @@
-
+
diff --git a/routes/web.php b/routes/web.php index ac3160f6..cb655380 100644 --- a/routes/web.php +++ b/routes/web.php @@ -187,6 +187,13 @@ Route::delete('/studies/{study}/members/{user}', [StudyMemberController::class, 'removeMember']) ->name('study-members.destroy'); + Route::get('studies/{study}/nmriumVersions', [StudyController::class, 'nmriumVersions']) + ->name('dashboard.studies.nmriumVersions'); + Route::get('studies/{study}/nmriumInfo', [StudyController::class, 'fetchNMRium']) + ->name('dashboard.studies.nmrium'); + Route::post('studies/{study}/nmriumInfo', [StudyController::class, 'nmriumInfo']) + ->name('dashboard.studies.nmriumInfo'); + Route::post('studies/{study}/molecule', [StudyController::class, 'moleculeStore']) ->name('study-molecule.store'); Route::delete('studies/{study}/molecule/{molecule}', [StudyController::class, 'moleculeDetach']) From d326ed4701925e8fa524037a6ca769013ace3ade Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 10:55:54 +0200 Subject: [PATCH 16/38] build: rename workflow --- .github/workflows/dev-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 59ca0a60..417aba59 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -1,4 +1,4 @@ -name : Deploy to Dev +name : Setup, Build and Publish to Dev on: push: @@ -88,6 +88,7 @@ jobs: location: ${{ env.GKE_ZONE }} credentials: ${{ secrets.GKE_SA_KEY }} + # Login to Docker - name: Log in to Docker Hub uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a with: From 40bc0d745801c80f57b69659ac205f40871ee34d Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 11:47:24 +0200 Subject: [PATCH 17/38] build: docs deploy --- .github/workflows/deploy-docs.yml | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/deploy-docs.yml diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 00000000..61bf18ba --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,33 @@ +name: Docs Deployment - GitHub pages +on: + workflow_dispatch: {} + push: + branches: + - development +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-node@v3 + with: + node-version: 16 + cache: npm + - run: npm ci + - name: Build + run: npm run docs:build + - uses: actions/configure-pages@v2 + - uses: actions/upload-pages-artifact@v1 + with: + path: docs/.vitepress/dist + - name: Deploy + id: deployment + uses: actions/deploy-pages@v2.0.2 \ No newline at end of file From 27d2addf64dd67a034c798c119ffbbd19fb2a3ae Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 11:50:59 +0200 Subject: [PATCH 18/38] build: add environment --- .github/workflows/dev-build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 417aba59..d8a889b7 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -15,6 +15,7 @@ env: DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_HUB_PASSWORD }} REPOSITORY_NAME: nmrxiv REPOSITORY_NAMESPACE: nfdi4chem + DEV_URL: https://dev.nmrxiv.org jobs: # php-unit-test: @@ -71,6 +72,9 @@ jobs: name: Build & deploy to development runs-on: ubuntu-latest needs: php-unit-test + environment: + name: Dev + url: ${{ env.DEV_URL }} steps: - name: Checkout uses: actions/checkout@v2 From 598f57138ff32f02b854e69719ef2be5edc3c3b5 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 11:58:09 +0200 Subject: [PATCH 19/38] docs: update basepath and add search --- docs/.vitepress/config.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs index cda4fd53..c237c964 100644 --- a/docs/.vitepress/config.mjs +++ b/docs/.vitepress/config.mjs @@ -5,8 +5,13 @@ export default defineConfig({ title: "nmrXiv", description: "FAIR, consensus-driven NMR data repository and computational platform", ignoreDeadLinks: true, + base: '/nmrxiv/', themeConfig: { + search: { + provider: 'local' + }, + logo: { light: "/logo.svg", dark: "/logo-dark.svg", From c2c0cc57f7fa1a700bf64f8eb71a45fc39084cf2 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 19 Oct 2023 13:14:51 +0200 Subject: [PATCH 20/38] fix: moving full path to relative paths --- resources/js/Shared/SpectraEditor.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index 6c0f570b..b7264076 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -523,7 +523,6 @@ export default { if (this.study.datasets.length > 0) { let urls = []; let url = - this.url + "/" + username + "/datasets/" + @@ -545,7 +544,6 @@ export default { ? this.$page.props.team.owner.username : this.project.owner.username; let url = - this.url + "/" + username + "/datasets/" + From cbac9e7a45ef1f0e4ac92db25d1c2cdedccbd4fa Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 13:36:26 +0200 Subject: [PATCH 21/38] docs: correct identatiom in the index page --- docs/index.md | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/docs/index.md b/docs/index.md index f9c97964..c13e7758 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,31 +1,25 @@ -______________________________________________________________________ - -# https://vitepress.dev/reference/default-theme-home-page - +--- layout: home hero: -name: "nmrXiv" -text: "Open, FAIR and Consensus-Driven NMR spectroscopy data repository and analysis platform" -tagline: "" -actions: -\- theme: brand -text: Get started -link: /introduction/intro.md -\- theme: alt -text: Submission Guides -link: /submission-guides/data-lifecycle.md -\- theme: alt -text: Developer Guides -link: /developer-guides/architecture.md + name: "nmrXiv" + text: "Open, FAIR and Consensus-Driven NMR spectroscopy data repository and analysis platform" + tagline: "" + actions: + - theme: brand + text: Get started + link: /introduction/intro.md + - theme: alt + text: Submission Guides + link: /submission-guides/data-lifecycle.md + - theme: alt + text: Developer Guides + link: /developer-guides/architecture.md features: - -- title: Demo Version - details: Try our demo version to test or preview the features. -- title: Submission Guides - details: Want to submit data? Read the submission guide. -- title: Contribution Guides - details: Want to contribute? Read the contribution guide. - -______________________________________________________________________ + - title: Demo Version + details: Try our demo version to test or preview the features. + - title: Submission Guides + details: Want to submit data? Read the submission guide. + - title: Contribution Guides + details: Want to contribute? Read the contribution guide. \ No newline at end of file From 139da2534380055aa60e54838b9e9f51b57e61e0 Mon Sep 17 00:00:00 2001 From: NishaSharma14 Date: Thu, 19 Oct 2023 13:47:53 +0200 Subject: [PATCH 22/38] fix: exclude nmrium and versions tables and take backup only in production --- app/Console/Kernel.php | 4 +++- config/database.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a87a6c6a..db205e22 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -27,7 +27,9 @@ protected function schedule(Schedule $schedule) $schedule->command('nmrxiv:delete-projects')->daily(); $schedule->command('nmrxiv:delete-citations')->weekly(); $schedule->command('nmrxiv:delete-authors')->weekly(); - $schedule->command('nmrxiv:backup-postgres-dump')->daily(); + if(App::environment('production')){ + $schedule->command('nmrxiv:backup-postgres-dump')->daily(); + } } /** diff --git a/config/database.php b/config/database.php index 5136f8ec..4bef901a 100644 --- a/config/database.php +++ b/config/database.php @@ -79,6 +79,7 @@ 'dump' => [ 'use_single_transaction', 'timeout' => 620 * 100, // 51 minute timeout + 'exclude_tables' => ['nmrium','versions'] ], ], From 401f9b20bd488756c72b5803df268ed58e33eaab Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 19 Oct 2023 14:02:24 +0200 Subject: [PATCH 23/38] fix: url path update --- resources/js/Shared/SpectraEditor.vue | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index b7264076..8b7ed3ca 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -374,7 +374,9 @@ export default { }, computed: { url() { - return String(this.$page.props.url); + return String(this.$page.props.url) + ? String(this.$page.props.url) + : "https://dev.nmrxiv.org"; }, nmriumURL() { return this.$page.props.nmriumURL @@ -382,7 +384,6 @@ export default { : "https://nmriumdev.nmrxiv.org?defaultEmptyMessage=''&workspace=embedded&id=" + Math.random(); }, - mailFromAddress() { return String(this.$page.props.mailFromAddress); }, @@ -520,9 +521,10 @@ export default { } }); } else { + let urls = []; if (this.study.datasets.length > 0) { - let urls = []; let url = + this.url + "/" + username + "/datasets/" + @@ -530,8 +532,8 @@ export default { "/" + this.study.slug; urls.push(url); - this.loadFromURLs(urls); } + this.loadFromURLs(urls); } } }, @@ -544,6 +546,7 @@ export default { ? this.$page.props.team.owner.username : this.project.owner.username; let url = + this.url + "/" + username + "/datasets/" + @@ -552,7 +555,6 @@ export default { this.study.slug; urls.push(url); } - let data = { data: urls, type: "url", From bad18afc55f55a631cbcdb7ed52acbaef313d63a Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 19 Oct 2023 16:17:44 +0200 Subject: [PATCH 24/38] fix: enabled nmredata detection and other minor ui changes --- app/Http/Controllers/DraftController.php | 78 +++++++++++++++++------- resources/js/Shared/SpectraEditor.vue | 4 +- resources/js/Shared/Submission.vue | 14 ++--- 3 files changed, 64 insertions(+), 32 deletions(-) diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 3431127f..df0f088d 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -96,6 +96,14 @@ public function files(Request $request, Draft $draft) ]); } + public function update(Request $request, Draft $draft) + { + $draft->name = $request->get('name'); + $draft->save(); + + return $draft; + } + public function deleteFSO(Request $request, Draft $draft, FileSystemObject $filesystemobject) { $fsoIds = $this->getChildrenIds($filesystemobject, []); @@ -131,7 +139,7 @@ public function complete(Request $request, Draft $draft) // ProcessDraft::dispatch($draft); return response()->json([ - 'project' => Project::with(['studies.datasets', 'owner'])->where('draft_id', $draft->id)->first(), + 'project' => Project::with(['studies.datasets', 'owner', 'citations', 'authors'])->where('draft_id', $draft->id)->first(), 'validation' => $validation, ]); } @@ -246,7 +254,6 @@ public function process(Request $request, Draft $draft) ['draft_id', $draft->id], ['status', '<>', 'missing'], ['model_type', 'study'], - ['is_processed', false], ]) ->orderBy('type') ->get(); @@ -285,14 +292,13 @@ public function process(Request $request, Draft $draft) $study->sample()->save($sample); $folder->study_id = $study->id; - $folder->is_processed = true; $folder->save(); } $sChildren = $folder->children; foreach ($sChildren as $sChild) { - if ($sChild->instrument_type != null) { + if ($sChild->instrument_type != null && $sChild->instrument_type != 'nmredata') { // associate all children with the study_id, project_id, dataset_id // create samples // create assays @@ -403,7 +409,7 @@ public function process(Request $request, Draft $draft) } return response()->json([ - 'project' => $project->load(['owner']), + 'project' => $project->load(['owner', 'citations', 'authors']), 'studies' => $studies, ]); }); @@ -438,31 +444,40 @@ public function processFolder($folders) { foreach ($folders as $folder) { if ($folder->type == 'directory') { - if ($folder->instrument_type == null) { - if ($this->isBruker($folder)) { - $this->saveInstrumentType($folder, 'bruker'); - $this->saveModelType($folder->parent); - } elseif ($this->isVarian($folder)) { - $this->saveInstrumentType($folder, 'varian'); - $this->saveModelType($folder->parent); - } else { - $this->processFolder($folder->children); - } + if ($this->isBruker($folder)) { + $this->saveInstrumentType($folder, 'bruker'); + $this->saveModelType($folder->parent); + } elseif ($this->isVarian($folder)) { + $this->saveInstrumentType($folder, 'varian'); + $this->saveModelType($folder->parent); + } else { + $this->processFolder($folder->children); } } else { - if ($folder->instrument_type == null) { - if ($this->isJOEL($folder)) { - $this->saveInstrumentType($folder, 'joel'); - $this->saveModelType($folder->parent); - } elseif ($this->isJcampDX($folder)) { - $this->saveInstrumentType($folder, 'jcamp'); - $this->saveModelType($folder->parent); - } + if ($this->isJOEL($folder)) { + $this->saveInstrumentType($folder, 'joel'); + $this->saveModelType($folder->parent); + } elseif ($this->isJcampDX($folder)) { + $this->saveInstrumentType($folder, 'jcamp'); + $this->saveModelType($folder->parent); + } elseif ($this->isNMReData($folder)) { + $this->saveInstrumentType($folder, 'nmredata'); + $this->saveAnnotationsDetected($folder->parent); } } } } + public function saveAnnotationsDetected($folder) + { + $study = $folder->study; + + if ($study) { + $study->has_nmredata = true; + $study->save(); + } + } + public function saveModelType($folder) { if ($folder) { @@ -526,6 +541,23 @@ public function isJcampDX($folder) return false; } + public function isNMReData($folder) + { + $fileTypes = ['nmredata']; + $names = [$folder->name]; + $extensions = array_map(fn ($s) => substr("$s", (strrpos($s, '.') + 1)), $names); + $isNMReData = false; + if (array_intersect($fileTypes, $extensions) == $fileTypes) { + $isNMReData = true; + } + + if ($isNMReData) { + return true; + } + + return false; + } + public function isJOEL($folder) { $fileTypes = ['jdf']; diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index 8b7ed3ca..679db030 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -1,7 +1,7 @@ diff --git a/resources/js/Shared/StudyInfo.vue b/resources/js/Shared/StudyInfo.vue index 363a2c47..ea2bfd3d 100644 --- a/resources/js/Shared/StudyInfo.vue +++ b/resources/js/Shared/StudyInfo.vue @@ -26,7 +26,9 @@ >#{{ study.identifier }} -
+
{{ study.name }}
@@ -40,7 +42,7 @@
-

- Here’s how your project compares to +

+ Here’s how your projectsamples meta-data compares to -
  • +
  • @@ -325,7 +326,7 @@ > Study title

    - Edit - + -->
    - Study description + Sample description

    - Edit - + -->
    diff --git a/routes/web.php b/routes/web.php index 6b20edf7..36000a60 100644 --- a/routes/web.php +++ b/routes/web.php @@ -100,6 +100,9 @@ Route::get('projects/status/{project}/queue', [ProjectController::class, 'status']) ->name('project.status'); + Route::get('projects/{project}/validation', [ProjectController::class, 'validationReport']) + ->name('project.validation'); + Route::post('users/notification/{user}/markAsRead', [UsersController::class, 'markNotificationAsRead']) ->name('users.markNotificationAsRead'); @@ -199,6 +202,8 @@ ->name('dashboard.studies.nmrium'); Route::post('studies/{study}/nmriumInfo', [StudyController::class, 'nmriumInfo']) ->name('dashboard.studies.nmriumInfo'); + Route::post('studies/{study}/preview', [StudyController::class, 'preview']) + ->name('dashboard.study.preview'); Route::post('studies/{study}/molecule', [StudyController::class, 'moleculeStore']) ->name('study-molecule.store'); From ec8e6eaa483f4caf5cff4c14b7dcea4cf7726621 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 26 Oct 2023 22:15:12 +0200 Subject: [PATCH 28/38] fix: more submission pipeline updates and added organism input details --- app/Actions/Study/UpdateStudy.php | 1 + app/Http/Controllers/DraftController.php | 21 +- app/Http/Controllers/StudyController.php | 4 +- app/Http/Middleware/HandleInertiaRequests.php | 1 + app/Models/Study.php | 1 + .../2023_10_26_183852_add_species_column.php | 34 + package-lock.json | 17 + package.json | 1 + resources/js/Pages/Publish.vue | 105 ++- resources/js/Pages/Upload.vue | 701 ++++++++++++------ resources/js/Shared/Depictor.vue | 134 ++++ resources/js/Shared/Depictor2D.vue | 103 +++ resources/js/Shared/Depictor3D.vue | 60 ++ resources/js/Shared/FileSystemBrowser.vue | 7 +- resources/js/Shared/SpectraEditor.vue | 1 + resources/js/Shared/StudyInfo.vue | 22 +- routes/web.php | 4 +- yarn.lock | 9 +- 18 files changed, 983 insertions(+), 243 deletions(-) create mode 100644 database/migrations/2023_10_26_183852_add_species_column.php create mode 100644 resources/js/Shared/Depictor.vue create mode 100644 resources/js/Shared/Depictor2D.vue create mode 100644 resources/js/Shared/Depictor3D.vue diff --git a/app/Actions/Study/UpdateStudy.php b/app/Actions/Study/UpdateStudy.php index 70248896..3c293c5d 100644 --- a/app/Actions/Study/UpdateStudy.php +++ b/app/Actions/Study/UpdateStudy.php @@ -35,6 +35,7 @@ public function update(Study $study, array $input) 'location' => array_key_exists('location', $input) ? $input['location'] : $study->location, 'url' => array_key_exists('url', $input) ? $input['url'] : $study->url, 'type' => array_key_exists('type', $input) ? $input['type'] : $study->type, + 'species' => array_key_exists('species', $input) ? $input['species'] : $study->species, 'access' => array_key_exists('access', $input) ? $input['access'] : 'restricted', 'access_type' => array_key_exists('access_type', $input) ? $input['access_type'] : 'viewer', 'is_public' => array_key_exists('is_public', $input) ? $input['is_public'] : $study->is_public, diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 3d12a79c..9e1efbe3 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -302,7 +302,7 @@ public function process(Request $request, Draft $draft) $sChildren = $folder->children; foreach ($sChildren as $sChild) { - if ($sChild->instrument_type != null && $sChild->instrument_type != 'nmredata') { + if ($sChild->instrument_type != null && $sChild->instrument_type != 'nmredata' && $sChild->instrument_type != 'mol') { // associate all children with the study_id, project_id, dataset_id // create samples // create assays @@ -469,6 +469,8 @@ public function processFolder($folders) } elseif ($this->isNMReData($folder)) { $this->saveInstrumentType($folder, 'nmredata'); $this->saveAnnotationsDetected($folder->parent); + } elseif ($this->isMolData($folder)) { + $this->saveInstrumentType($folder, 'mol'); } } } @@ -564,6 +566,23 @@ public function isNMReData($folder) return false; } + public function isMolData($folder) + { + $fileTypes = ['mol']; + $names = [$folder->name]; + $extensions = array_map(fn ($s) => substr("$s", (strrpos($s, '.') + 1)), $names); + $isMolData = false; + if (array_intersect($fileTypes, $extensions) == $fileTypes) { + $isMolData = true; + } + + if ($isMolData) { + return true; + } + + return false; + } + public function isJOEL($folder) { $fileTypes = ['jdf']; diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index 2f20c8f2..90da3adb 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -128,7 +128,7 @@ public function moleculeStore(Request $request, Study $study) 'FORMULA' => $request->get('formula') ? $request->get('formula') : '', 'INCHI_KEY' => $request->get('InChIKey') ? $request->get('InChIKey') : '', 'MOL' => $request->get('mol') ? $request->get('mol') : '', - 'CANONICAL_SMILES' => $request->get('cannonical_smiles') ? $request->get('cannonical_smiles') : '', + 'CANONICAL_SMILES' => $request->get('canonical_smiles') ? $request->get('canonical_smiles') : '', ]); $sample->molecules()->syncWithPivotValues([$molecule->id], ['percentage_composition' => $request->get('percentage')], false); } @@ -260,7 +260,7 @@ public function annotations(Request $request, Study $study) ->first(); return $studyFSObject->children->filter(function ($child) { - return $child->instrument_type == 'nmredata'; + return $child->instrument_type == 'nmredata' || $child->instrument_type == 'mol' || $child->instrument_type == 'sdf'; })->values(); } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 05b13eeb..850c13a9 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -78,6 +78,7 @@ public function share(Request $request) 'orcidSearchApi' => env('ORCID_ID_SEARCH_API'), 'orcidPersonApi' => env('ORCID_ID_PERSON_API'), 'orcidEmploymentApi' => env('ORCID_ID_EMPLOYMENT_API'), + 'CM_API' => env('CM_API'), ]); } } diff --git a/app/Models/Study.php b/app/Models/Study.php index d25001a7..f91e9b7b 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -47,6 +47,7 @@ class Study extends Model implements Auditable 'fs_id', 'study_photo_path', 'license_id', + 'species', ]; protected static $marks = [ diff --git a/database/migrations/2023_10_26_183852_add_species_column.php b/database/migrations/2023_10_26_183852_add_species_column.php new file mode 100644 index 00000000..47c15003 --- /dev/null +++ b/database/migrations/2023_10_26_183852_add_species_column.php @@ -0,0 +1,34 @@ +longText('species')->nullable(); + }); + Schema::table('projects', function (Blueprint $table) { + $table->longText('species')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('studies', function (Blueprint $table) { + $table->dropColumn('species'); + }); + Schema::table('projects', function (Blueprint $table) { + $table->dropColumn('species'); + }); + } +}; diff --git a/package-lock.json b/package-lock.json index ec688012..a5004db2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "marked": "^4.0.4", "medium-zoom": "^1.0.8", "mitt": "^3.0.0", + "ontology-elements": "^0.2.3", "openchemlib": "^7.4.3", "pluralize": "^8.0.0", "popper.js": "^1.16.1", @@ -4009,6 +4010,14 @@ "wrappy": "1" } }, + "node_modules/ontology-elements": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ontology-elements/-/ontology-elements-0.2.3.tgz", + "integrity": "sha512-7+VBiAveZ8ek3jeGIGOyZPd4y8D7cDWzDwO57+rBnuZXLDaaKIelZ1z/MV0BF/4ghzVl6IGhtkXiRL3LnSeEWA==", + "dependencies": { + "vue": "^3.2.47" + } + }, "node_modules/openchemlib": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/openchemlib/-/openchemlib-7.5.0.tgz", @@ -8734,6 +8743,14 @@ "wrappy": "1" } }, + "ontology-elements": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ontology-elements/-/ontology-elements-0.2.3.tgz", + "integrity": "sha512-7+VBiAveZ8ek3jeGIGOyZPd4y8D7cDWzDwO57+rBnuZXLDaaKIelZ1z/MV0BF/4ghzVl6IGhtkXiRL3LnSeEWA==", + "requires": { + "vue": "^3.2.47" + } + }, "openchemlib": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/openchemlib/-/openchemlib-7.5.0.tgz", diff --git a/package.json b/package.json index 4c8a5c36..8869cb8b 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "marked": "^4.0.4", "medium-zoom": "^1.0.8", "mitt": "^3.0.0", + "ontology-elements": "^0.2.3", "openchemlib": "^7.4.3", "pluralize": "^8.0.0", "popper.js": "^1.16.1", diff --git a/resources/js/Pages/Publish.vue b/resources/js/Pages/Publish.vue index c0861166..8cfecfcb 100644 --- a/resources/js/Pages/Publish.vue +++ b/resources/js/Pages/Publish.vue @@ -147,6 +147,95 @@ class="mt-2" />
    +
    +
    + + +
    +
    + +
    +
    + +
    +
    +
    +
    + + + + + + +
    +
    +
    +
    -1) { + this.publishForm.project.species.splice(index, 1); + } + }, getTarget(id) { var target = null; if (id) { diff --git a/resources/js/Pages/Upload.vue b/resources/js/Pages/Upload.vue index 4f2e12e6..15dcb018 100644 --- a/resources/js/Pages/Upload.vue +++ b/resources/js/Pages/Upload.vue @@ -356,6 +356,7 @@ :readonly="false" :draft="currentDraft" :height="'h-[calc(100vh-385px)]'" + @loading="filesLoading" >
    @@ -573,6 +576,7 @@
    + Samples Validation
    @@ -581,7 +585,7 @@ > Success @@ -598,6 +602,80 @@
    +
    +
    +
    +

    + Spectra + Metadata + Not + Found +

    +
    +

    + Looks + like + we're + missing + some + important + Spectra + metadata. + No + worries, + though + – + we've + got + your + back! + Would + you + like + us + to + automatically + import + the + missing + Spectra + information + and + kickstart + the + processing? +

    +
    +
    + +
    +
    +
    +
    @@ -609,14 +687,29 @@ validation " > - + + + + Refresh - + + + +
    +
    + +
    +
    + +
    +
    +
    +
    + + + + + + +
    +
    +
    @@ -1085,15 +1277,24 @@ class="mt-2 text-sm text-gray-700" >
    - + > + +
    +
    @@ -2063,6 +2268,7 @@ import ToolTip from "@/Shared/ToolTip.vue"; import ManageCitation from "@/Shared/ManageCitation.vue"; import Citation from "@/Shared/Citation.vue"; import AuthorCard from "@/Shared/AuthorCard.vue"; +import Depictor from "@/Shared/Depictor.vue"; import { XCircleIcon, ClipboardDocumentIcon, @@ -2080,6 +2286,7 @@ import { import SpectraEditor from "@/Shared/SpectraEditor.vue"; import ToggleButton from "@/Shared/ToggleButton.vue"; import Primer from "@/Shared/Primer.vue"; +import "ontology-elements/dist/index.js"; export default { components: { @@ -2117,6 +2324,7 @@ export default { StarIcon, CalendarIcon, Primer, + Depictor, }, props: ["draft_id"], setup() {}, @@ -2128,8 +2336,13 @@ export default { loadingStep: false, selectedStudy: null, + project: null, + studies: null, + displaySamplesSummaryInfo: true, + studySpecies: null, + drafts: [], draftForm: this.$inertia.form({ @@ -2166,6 +2379,7 @@ export default { description: "", error_message: null, tags: [], + species: [], tag: "", tags_array: [], }), @@ -2223,6 +2437,7 @@ export default { }), errors: null, + studiesToImport: [], }; }, @@ -2264,6 +2479,33 @@ export default { }, methods: { + updateSpecies(species) { + if (species && species != "") { + this.studyForm.species.push(species); + this.saveStudyDetails(); + this.studySpecies = ""; + } + }, + removeSpecies(index) { + if (index > -1) { + this.studyForm.species.splice(index, 1); + this.saveStudyDetails(); + } + }, + loadSmiles() { + this.errorMessage = ""; + if (this.smiles && this.smiles != "") { + try { + let mol = OCL.Molecule.fromSmiles(this.smiles); + this.editor.setSmiles(this.smiles); + } catch (e) { + this.errorMessage = "The entered SMILES is not valid."; + } + } + }, + filesLoading(e) { + this.loadingStep = e; + }, editData(e) { let i = 0; this.studies.forEach((s) => { @@ -2273,12 +2515,6 @@ export default { i = i + 1; }); }, - fetchProjectData() { - this.spectraLoadingStatus = false; - router.reload({ - only: ["project", "studies"], - }); - }, spectraLoading(e) { this.spectraLoadingStatus = e.status; this.spectraLoadingMessage = e.message; @@ -2324,7 +2560,52 @@ export default { }); this.hasStudies(this.$refs.fsbRef.file); - + this.fetchProjectDetails().then( + (response) => { + this.loadingStep = false; + this.project = response.data.project; + this.studies = response.data.studies; + if ( + this.project && + this.studies && + this.studies.length > 0 + ) { + this.loadingStep = false; + this.selectStep(2); + } else { + if (this.studies.length == 0) { + this.loadingStep = false; + } + } + }, + (error) => { + this.loadingStep = false; + Object.keys(error.response.data.errors).forEach((key) => { + error.response.data.errors[key] = + error.response.data.errors[key].join(", "); + }); + this.draftForm.errors = error.response.data.errors; + this.draftForm.error_message = error.response.data.message; + this.draftForm.hasErrors = true; + Object.keys(this.draftForm.errors).forEach((key) => { + if (!this.errorMessage) { + this.errorMessage = + "" + + key + + ": " + + this.draftForm.errors[key] + + "
    "; + } else { + this.errorMessage += + "" + + key + + ": " + + this.draftForm.errors[key] + + "
    "; + } + }); + } + ); if ( this.$refs.fsbRef.file && this.$refs.fsbRef.file.children.length > 0 && @@ -2336,70 +2617,6 @@ export default { this.draftForm.tags_array = this.draftForm.tags.map( (a) => a.text ); - axios - .post( - "/dashboard/drafts/" + - this.currentDraft.id + - "/process", - this.draftForm - ) - .then( - (response) => { - this.loadingStep = false; - this.project = response.data.project; - this.studies = response.data.studies; - if ( - this.project && - this.studies && - this.studies.length > 0 - ) { - // this.selectStudy(this.studies[0], 0); - // this.selectedDataset = - // this.selectedStudy.datasets[0]; - this.loadingStep = false; - this.selectStep(2); - } else { - if (this.studies.length == 0) { - this.loadingStep = false; - } - } - }, - (error) => { - this.loadingStep = false; - - Object.keys(error.response.data.errors).forEach( - (key) => { - error.response.data.errors[key] = - error.response.data.errors[key].join( - ", " - ); - } - ); - this.draftForm.errors = error.response.data.errors; - this.draftForm.error_message = - error.response.data.message; - this.draftForm.hasErrors = true; - Object.keys(this.draftForm.errors).forEach( - (key) => { - if (!this.errorMessage) { - this.errorMessage = - "" + - key + - ": " + - this.draftForm.errors[key] + - "
    "; - } else { - this.errorMessage += - "" + - key + - ": " + - this.draftForm.errors[key] + - "
    "; - } - } - ); - } - ); } else { if ( this.$refs.fsbRef.file.children.length > 0 && @@ -2419,6 +2636,12 @@ export default { } } }, + fetchProjectDetails() { + return axios.post( + "/dashboard/drafts/" + this.currentDraft.id + "/process", + this.draftForm + ); + }, loadLicenses() { if (this.$page.props.licenses) { this.licenses = this.$page.props.licenses; @@ -2429,62 +2652,54 @@ export default { }); } }, - saveMolecule(mol) { + saveMolecule(mol, study) { + if (!study) { + study = this.selectedStudy; + } if (!mol) { let mol = this.editor.getMolFile(); axios .post( - "https://www.cheminfo.org/webservices/inchi", - "molfile=" + mol - ) - .then((response) => { - let InChI = response.data.output.InChI; - let InChIKey = response.data.output.InChIKey; - let MF = this.editor - .getMolecule() - .getMolecularFormula().formula; - axios - .post( - "/dashboard/studies/" + - this.selectedStudy.id + - "/molecule", - { - InChI: InChI, - InChIKey: InChIKey, - percentage: this.percentage, - formula: MF, - mol: mol, - } - ) - .then((res) => { - this.selectedStudy.sample.molecules = res.data; - this.smiles = ""; - this.percentage = 0; - // this.editor.setSmiles(""); - }); - }); - } else { - axios - .post( - "/dashboard/studies/" + - this.selectedStudy.id + - "/molecule", - { - InChI: mol.inchi, - InChIKey: mol.inchikey, - percentage: 0, - mol: mol.standardized_mol, - canonical_smiles: mol.canonical_smiles, - } + "https://dev.api.naturalproducts.net/latest/chem/standardize", + mol ) .then((res) => { - this.selectedStudy.sample.molecules = res.data; - this.smiles = ""; - this.percentage = 0; - // this.editor.setSmiles(""); + this.associateMoleculeToStudy(res.data, study); }); + } else { + this.associateMoleculeToStudy(mol, study); } }, + editMolecule(mol) { + this.editor.setMolFile(mol.MOL); + this.percentage = parseInt(mol.pivot.percentage_composition); + axios + .delete( + "/dashboard/studies/" + + this.selectedStudy.id + + "/molecule/" + + mol.id + ) + .then((res) => { + this.selectedStudy.sample.molecules = res.data; + }); + }, + associateMoleculeToStudy(mol, study) { + axios + .post("/dashboard/studies/" + study.id + "/molecule", { + InChI: mol.inchi, + InChIKey: mol.inchikey, + percentage: 0, + mol: mol.standardized_mol, + canonical_smiles: mol.canonical_smiles, + }) + .then((res) => { + study.sample.molecules = res.data; + this.smiles = ""; + this.percentage = 0; + // this.editor.setSmiles(""); + }); + }, deleteMolecule(mol) { axios .delete( @@ -2500,16 +2715,6 @@ export default { this.editor.setSmiles(""); }); }, - getSVGString(molecule) { - if (molecule.MOL) { - let mol = OCL.Molecule.fromMolfile( - "\n " + molecule.MOL.replaceAll('"', "") - ); - return mol.toSVG(200, 200); - } else { - console.log(molecule); - } - }, showSamplesSummary() { this.displaySamplesSummaryInfo = true; this.selectedStudy = null; @@ -2519,6 +2724,7 @@ export default { this.selectedStudy = study; this.studyForm.name = this.selectedStudy.name; this.studyForm.description = this.selectedStudy.description; + this.studyForm.species = JSON.parse(this.selectedStudy.species); let tags = []; this.selectedStudy.tags.forEach((t) => { tags.push({ @@ -2543,10 +2749,26 @@ export default { 1 ); }); + if (this.studyForm.description == "") { + if (study.has_nmrium) { + this.autoGenerateDescription(); + } + } + if ( + this.selectedStudy && + this.selectedStudy.sample.molecules.length == 0 + ) { + this.autoImportMolecularData(this.selectedStudy); + } + if (!datasetIndex) { + this.selectedDSIndex = 0; + } else { + this.selectedDSIndex = datasetIndex; + } + }, + autoImportMolecularData(study) { axios - .get( - "/dashboard/studies/" + this.selectedStudy.id + "/nmredata" - ) + .get("/dashboard/studies/" + study.id + "/annotations") .then((response) => { let nmredataFiles = response.data; nmredataFiles.forEach((file) => { @@ -2561,7 +2783,7 @@ export default { username + "/studies" + "/" + - this.selectedStudy.id + + study.id + "/file/" + file.slug; axios.get(url).then((response) => { @@ -2574,31 +2796,20 @@ export default { .then((res) => { let STANDARD_INCHI = res.data.inchi; let molExists = false; - this.selectedStudy.sample.molecules.forEach( - (mol) => { - if ( - mol.STANDARD_INCHI == - STANDARD_INCHI - ) { - molExists = true; - } + study.sample.molecules.forEach((mol) => { + if ( + mol.STANDARD_INCHI == STANDARD_INCHI + ) { + molExists = true; } - ); + }); if (!molExists) { - this.saveMolecule(res.data); + this.saveMolecule(res.data, study); } }); }); - - // save molecule if doesnt exist }); }); - - if (!datasetIndex) { - this.selectedDSIndex = 0; - } else { - this.selectedDSIndex = datasetIndex; - } }, toggleManageAuthor() { this.manageAuthorElement.toggleDialog(); @@ -2607,38 +2818,48 @@ export default { this.manageCitationElement.toggleDialog(); }, closeDraft() { - this.loadingStep = true; - axios - .post( - "/dashboard/drafts/" + this.currentDraft.id + "/complete", - {} - ) - .catch(() => { - this.loadingStep = false; - }) - .then((response) => { - this.project = response.data.project; - this.validation = this.parseJSON( - response.data.validation.report - ); - this.validationStatus = true; - this.validation.project.studies.forEach((study) => { - if (study.status == false) { - this.validationStatus = false; + if (this.validationStatus) { + this.loadingStep = true; + axios + .post( + "/dashboard/drafts/" + + this.currentDraft.id + + "/complete", + {} + ) + .catch(() => { + this.loadingStep = false; + }) + .then((response) => { + this.project = response.data.project; + this.validation = this.parseJSON( + response.data.validation.report + ); + this.validationStatus = true; + this.validation.project.studies.forEach((study) => { + console.log(study); + if (study.status == false) { + this.validationStatus = false; + } + }); + if (this.project) { + // this.loadingStep = false; + // this.loadLicenses(); + // this.selectStep(3); + // this.publishForm.project.name = this.draftForm.name; + // this.publishForm.project.description = + // this.draftForm.description; + // this.publishForm.project.tags = this.draftForm.tags; + // this.trackProject(); + window.location = + "/publish/" + this.currentDraft.id; } }); - if (this.project) { - // this.loadingStep = false; - // this.loadLicenses(); - // this.selectStep(3); - // this.publishForm.project.name = this.draftForm.name; - // this.publishForm.project.description = - // this.draftForm.description; - // this.publishForm.project.tags = this.draftForm.tags; - // this.trackProject(); - window.location = "/publish/" + this.currentDraft.id; - } - }); + } else { + alert( + "Samples validation failed: Please provide all meta data to proceed" + ); + } }, publish() { if (this.publishForm.conditions && this.publishForm.terms) { @@ -2752,6 +2973,7 @@ export default { // this.$refs.spectraEditorREF.registerEvents(); // } this.fetchValidations(); + this.updateAutoImportList(); }); } }, @@ -2760,7 +2982,12 @@ export default { .get("/projects/" + this.project.id + "/validation") .then((response) => { this.validation = response.data.report; - // console.log(this.validation) + this.validationStatus = true; + this.validation.project.studies.forEach((study) => { + if (study.status == false) { + this.validationStatus = false; + } + }); }); }, hidePrimer() { @@ -2828,23 +3055,25 @@ export default { }); }); this.studyForm.description = desc; + this.saveStudyDetails(); } }); }, - autoImport() { - this.spectraLoadingStatus = true; + updateAutoImportList() { this.studiesToImport = []; this.studies.forEach((study) => { if (!study.has_nmrium) { this.studiesToImport.push({ projectSlug: this.project.slug, - studySlug: study.slug, - studyID: study.id, - studyDownloadUrl: study.download_url, + study: study, status: false, }); } }); + }, + autoImport() { + this.spectraLoadingStatus = true; + this.updateAutoImportList(); if (this.studiesToImport.length > 0) { this.fetchNMRium(); } else { @@ -2855,14 +3084,15 @@ export default { } }, fetchNMRium() { - let studyDetails = this.studiesToImport.filter( - (f) => f.status == false - )[0]; + let studyDetails = + this.importPendingSamples.length > 0 + ? this.importPendingSamples[0] + : null; if (studyDetails) { this.spectraLoadingStatus = true; let url = null; - if (studyDetails.studyDownloadUrl) { - url = studyDetails.studyDownloadUrl; + if (studyDetails.study.download_url) { + url = studyDetails.study.download_url; } else { // let ownerUserName = // this.$page.props.team && this.$page.props.team.owner @@ -2880,10 +3110,17 @@ export default { "/datasets/" + this.project.slug + "/" + - studyDetails.studySlug; + studyDetails.study.slug; } this.spectraLoadingMessage = - "Parsing: " + studyDetails.studySlug + "
    " + url; + "
    Pending: " + + this.importPendingSamples.length + + "/" + + this.studies.length + + "
    Processing: " + + studyDetails.study.slug + + "
    Spectra URL: " + + url; axios .post("https://nodejsdev.nmrxiv.org/spectra-parser", { urls: [url], @@ -2902,7 +3139,7 @@ export default { axios .post( "/dashboard/studies/" + - studyDetails.studyID + + studyDetails.study.id + "/nmriumInfo", { data: parsedSpectra, @@ -2912,31 +3149,43 @@ export default { .then((res) => { this.loadingStep = false; this.studiesToImport.filter( - (f) => f.studyID == studyDetails.studyID + (f) => f.study.id == studyDetails.study.id )[0].status = true; + this.autoImportMolecularData( + studyDetails.study + ); this.fetchNMRium(); }) .catch((err) => { this.loadingStep = false; this.studiesToImport.filter( - (f) => f.studyID == studyDetails.studyID + (f) => f.studyID == studyDetails.study.id )[0].status = true; this.fetchNMRium(); }); }) - .catch((error) => { + .catch(() => { this.loadingStep = false; this.studiesToImport.filter( - (f) => f.studyID == studyDetails.studyID + (f) => f.studyID == studyDetails.study.id )[0].status = true; this.fetchNMRium(); }); } else { - this.fetchProjectData(); + this.fetchProjectDetails().then((response) => { + this.loadingStep = false; + this.project = response.data.project; + this.studies = response.data.studies; + this.fetchValidations(); + this.spectraLoadingStatus = false; + }); } }, }, computed: { + importPendingSamples() { + return this.studiesToImport.filter((f) => f.status == false); + }, url() { return String(this.$page.props.url) ? String(this.$page.props.url) diff --git a/resources/js/Shared/Depictor.vue b/resources/js/Shared/Depictor.vue new file mode 100644 index 00000000..7154c707 --- /dev/null +++ b/resources/js/Shared/Depictor.vue @@ -0,0 +1,134 @@ + + diff --git a/resources/js/Shared/Depictor2D.vue b/resources/js/Shared/Depictor2D.vue new file mode 100644 index 00000000..d45f2a3c --- /dev/null +++ b/resources/js/Shared/Depictor2D.vue @@ -0,0 +1,103 @@ + + diff --git a/resources/js/Shared/Depictor3D.vue b/resources/js/Shared/Depictor3D.vue new file mode 100644 index 00000000..9c7fc585 --- /dev/null +++ b/resources/js/Shared/Depictor3D.vue @@ -0,0 +1,60 @@ + + diff --git a/resources/js/Shared/FileSystemBrowser.vue b/resources/js/Shared/FileSystemBrowser.vue index 994a458f..5a2aa114 100644 --- a/resources/js/Shared/FileSystemBrowser.vue +++ b/resources/js/Shared/FileSystemBrowser.vue @@ -536,6 +536,9 @@ export default { ToolTip, }, props: ["draft", "readonly", "height"], + + emits: ["loading"], + data() { return { status: "", @@ -599,8 +602,6 @@ export default { }, updateBusyStatus(status) { this.busy = status; - // console.log("raising") - // this.$emit("loading", this.busy); }, loadFiles() { this.updateBusyStatus(true); @@ -610,11 +611,13 @@ export default { this.$page.props.selectedFileSystemObject = this.file; this.$page.props.selectedFolder = "/"; this.updateBusyStatus(true); + this.$emit("loading", false); this.loading = false; }); }, annotate() { this.updateBusyStatus(true); + this.$emit("loading", true); this.loading = true; this.status = "PROCESSING UPLOADED FILES"; axios diff --git a/resources/js/Shared/SpectraEditor.vue b/resources/js/Shared/SpectraEditor.vue index 209a3b01..997b18c9 100644 --- a/resources/js/Shared/SpectraEditor.vue +++ b/resources/js/Shared/SpectraEditor.vue @@ -355,6 +355,7 @@ export default { }, }, }, + emits: ["loading"], setup() { const versionsElement = ref(null); return { diff --git a/resources/js/Shared/StudyInfo.vue b/resources/js/Shared/StudyInfo.vue index ea2bfd3d..da55305d 100644 --- a/resources/js/Shared/StudyInfo.vue +++ b/resources/js/Shared/StudyInfo.vue @@ -3,17 +3,21 @@ v-if="study" class="flex flex-col border rounded-lg shadow-lg transition ease-in-out delay-150 duration-300 overflow-hidden" > -
    +
    • -
      + + +
    @@ -33,7 +37,7 @@
    -
    +
    -
    +
    --> diff --git a/resources/js/Shared/StudyInfo.vue b/resources/js/Shared/StudyInfo.vue index da55305d..317613ba 100644 --- a/resources/js/Shared/StudyInfo.vue +++ b/resources/js/Shared/StudyInfo.vue @@ -3,7 +3,7 @@ v-if="study" class="flex flex-col border rounded-lg shadow-lg transition ease-in-out delay-150 duration-300 overflow-hidden" > -
    +
    • h(App, props) }) .use(plugin) .component("Children", Children) - .component("vue-simple-context-menu", VueSimpleContextMenu) .mixin({ methods: { route } }) .mixin(helpers) .use(InstantSearch) diff --git a/yarn.lock b/yarn.lock index 65042056..ba78d2a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -247,11 +247,6 @@ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@imengyu/vue3-context-menu@^1.0.9": - version "1.1.2" - resolved "https://registry.npmjs.org/@imengyu/vue3-context-menu/-/vue3-context-menu-1.1.2.tgz" - integrity sha512-uh1tT14F5ImkyPyqYbblJORAfkEbM/qlEgqqzVZ4Thf+NDb1ElgeiGtusyjsxN2zSLVcbED9KogbbSnueV8ZrQ== - "@inertiajs/core@1.0.12": version "1.0.12" resolved "https://registry.npmjs.org/@inertiajs/core/-/core-1.0.12.tgz" @@ -1030,9 +1025,9 @@ camelcase-css@^2.0.1: integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426: - version "1.0.30001431" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz" - integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ== + version "1.0.30001558" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz" + integrity sha512-/Et7DwLqpjS47JPEcz6VnxU9PwcIdVi0ciLXRWBQdj1XFye68pSQYpV0QtPTfUKWuOaEig+/Vez2l74eDc1tPQ== chalk@^2.4.1: version "2.4.2" From cb5610bb21eec7d7b264b5dbda271d0addda9c1a Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Sat, 4 Nov 2023 18:02:10 +0100 Subject: [PATCH 30/38] fix: minor formatting updates --- app/Actions/Project/AssignIdentifier.php | 30 +++++----- app/Http/Controllers/DraftController.php | 9 +-- app/Http/Controllers/ProjectController.php | 4 +- app/Jobs/ArchiveStudy.php | 15 +++-- app/Jobs/ProcessSubmission.php | 69 +++++++++++----------- app/Models/Draft.php | 2 +- app/Models/HasDOI.php | 10 ++-- 7 files changed, 70 insertions(+), 69 deletions(-) diff --git a/app/Actions/Project/AssignIdentifier.php b/app/Actions/Project/AssignIdentifier.php index 9b52caea..7cdfa231 100644 --- a/app/Actions/Project/AssignIdentifier.php +++ b/app/Actions/Project/AssignIdentifier.php @@ -31,13 +31,13 @@ public function assign($model) { $project = null; $studies = null; - if ($model instanceof Project){ + if ($model instanceof Project) { $project = $model; - }elseif(is_array($model)){ + } elseif (is_array($model)) { $studies = $model; } - if($project){ + if ($project) { $projectIdentifier = $project->identifier ? $project->identifier : null; if ($projectIdentifier == null) { @@ -54,9 +54,9 @@ public function assign($model) $studies = $project->studies; } - if($studies){ + if ($studies) { foreach ($studies as $study) { - if($study instanceof Study){ + if ($study instanceof Study) { $studyIdentifier = $study->identifier ? $study->identifier : null; if ($studyIdentifier == null) { $studyTicker = Ticker::whereType('study')->first(); @@ -67,22 +67,22 @@ public function assign($model) } $study->save(); $study->generateDOI($this->doiService); - + $sample = $study->sample; $sampleIdentifier = $sample->identifier ? $sample->identifier : null; - + if ($sampleIdentifier == null) { $sampleTicker = Ticker::whereType('sample')->first(); $sampleIdentifier = $sampleTicker->index + 1; $sample->identifier = $sampleIdentifier; $sample->save(); - + $sampleTicker->index = $sampleIdentifier; $sampleTicker->save(); } - + $molecules = $sample->molecules; - + foreach ($molecules as $molecule) { $moleculeIdentifier = $molecule->identifier ? $molecule->identifier : null; if ($moleculeIdentifier == null) { @@ -90,25 +90,25 @@ public function assign($model) $moleculeIdentifier = $moleculeTicker->index + 1; $molecule->identifier = $moleculeIdentifier; $molecule->save(); - + $moleculeTicker->index = $moleculeIdentifier; $moleculeTicker->save(); } } - + $datasets = $study->datasets; foreach ($datasets as $dataset) { $dsIdentifier = $dataset->identifier ? $dataset->identifier : null; - + if ($dsIdentifier == null) { $dsTicker = Ticker::whereType('dataset')->first(); $dsIdentifier = $dsTicker->index + 1; $dataset->identifier = $dsIdentifier; - + $dsTicker->index = $dsIdentifier; $dsTicker->save(); } - + $dataset->save(); $dataset->generateDOI($this->doiService); } diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 4932dc98..82e6c238 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -100,14 +100,15 @@ public function files(Request $request, Draft $draft) public function update(Request $request, Draft $draft) { $project_enabled = $request->has('project_enabled') ? $request->get('project_enabled') : $draft->project_enabled; - if($project_enabled == 1){ - $project_enabled = TRUE; - }else{ - $project_enabled = FALSE; + if ($project_enabled == 1) { + $project_enabled = true; + } else { + $project_enabled = false; } $draft->name = $request->get('name') ? $request->get('name') : $draft->name; $draft->project_enabled = $project_enabled; $draft->save(); + return $draft; } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index aab15d53..7786b231 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -290,6 +290,7 @@ public function publish(Request $request, Project $project) $validation = $validation->fresh(); if ($validation['report']['project']['status']) { ProcessSubmission::dispatch($project); + return response()->json([ 'project' => $project, 'validation' => $validation, @@ -315,13 +316,14 @@ public function publish(Request $request, Project $project) $status = true; foreach ($validation['report']['project']['studies'] as $study) { - if(!$study['status']){ + if (! $study['status']) { $status = false; } } // add license check if ($status) { ProcessSubmission::dispatch($project); + return response()->json([ 'project' => $project, 'validation' => $validation, diff --git a/app/Jobs/ArchiveStudy.php b/app/Jobs/ArchiveStudy.php index a10cc281..6509b435 100644 --- a/app/Jobs/ArchiveStudy.php +++ b/app/Jobs/ArchiveStudy.php @@ -10,10 +10,9 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; use ZipStream; -use Illuminate\Support\Facades\Http; - class ArchiveStudy implements ShouldBeUnique, ShouldQueue { @@ -44,7 +43,7 @@ public function handle(): void $project = $this->project; if ($project) { foreach ($project->studies as $study) { - $study->internal_status = "processing"; + $study->internal_status = 'processing'; $study->save(); $archiveDownloadURL = $study->download_url; if (! $archiveDownloadURL) { @@ -120,10 +119,10 @@ public function handle(): void // unset($spectra["originalData"]); // unset($spectra["originalInfo"]); // } - + // $version = $parsedSpectra['version']; // unset($parsedSpectra["version"]); - + // // associate // $nmriumJSON = array( // "data" => $parsedSpectra, @@ -169,11 +168,11 @@ public function handle(): void // } // } // // add molecules - $study->internal_status = "complete"; + $study->internal_status = 'complete'; $study->save(); } - }else{ - $study->internal_status = "complete"; + } else { + $study->internal_status = 'complete'; $study->save(); } } diff --git a/app/Jobs/ProcessSubmission.php b/app/Jobs/ProcessSubmission.php index 5477246f..33c38c18 100644 --- a/app/Jobs/ProcessSubmission.php +++ b/app/Jobs/ProcessSubmission.php @@ -2,19 +2,19 @@ namespace App\Jobs; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldBeUnique; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -use App\Models\Project; use App\Actions\Project\AssignIdentifier; use App\Actions\Project\PublishProject; use App\Actions\Study\PublishStudy; use App\Models\FileSystemObject; +use App\Models\Project; use App\Notifications\DraftProcessedNotification; use Carbon\Carbon; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeUnique; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Storage; @@ -22,7 +22,7 @@ class ProcessSubmission implements ShouldQueue, ShouldBeUnique { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - /** + /** * The project instance. * * @var \App\Models\Project @@ -45,72 +45,71 @@ public function __construct(Project $project) public function handle(AssignIdentifier $assigner, PublishProject $projectPublisher, PublishStudy $studyPublisher) { $project = $this->project; - + $project->status = 'processing'; $project->save(); - $draft = $project->draft; - if($draft->project_enabled){ + if ($draft->project_enabled) { $logs = 'Moving files in progress'; if ($project) { if ($draft) { $environment = env('APP_ENV', 'local'); - + $projectPath = preg_replace( '~//+~', '/', $environment.'/'.$project->uuid ); - + $projectFSObjects = FileSystemObject::with('children') ->where([ ['draft_id', $draft->id], ['level', 0], ]) ->get(); - + foreach ($projectFSObjects as $FSObject) { $this->moveFolder($FSObject, $draft, $projectPath); } - + $logs = $logs.'
      Moving files complete
      Deleteing draft'; - + $draft->delete(); } - + $process_logs = json_decode($project->process_logs, true); - + $process_log = [Carbon::now()->timestamp => $logs]; - + if (! is_null($process_logs)) { array_push($process_logs, $process_log); } else { $process_logs = []; array_push($process_logs, $process_log); } - + $project->process_logs = $process_logs; - + $project->draft_id = null; - + $project->status = 'complete'; - + $project->save(); - + $assigner->assign($project->fresh()); - + $release_date = Carbon::parse($project->release_date); - + if ($release_date->isToday()) { $projectPublisher->publish($project); } - + Notification::send($project->owner, new DraftProcessedNotification($project)); } - }else{ + } else { $logs = 'Moving files in progress'; if ($project) { @@ -129,7 +128,7 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis $studyFSObjects = FileSystemObject::with('children') ->where([ ['draft_id', $draft->id], - ['study_id', $study->id] + ['study_id', $study->id], ]) ->get(); @@ -138,11 +137,11 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis } $logs = $logs.'
      Moving files complete
      Deleteing draft'; - + $process_logs = json_decode($study->process_logs, true); - + $process_log = [Carbon::now()->timestamp => $logs]; - + if (! is_null($process_logs)) { array_push($process_logs, $process_log); } else { @@ -156,9 +155,9 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis $study->save(); } } - $assigner->assign($_studies); + $assigner->assign($_studies); $release_date = Carbon::parse($project->release_date); - + if ($release_date->isToday()) { foreach ($_studies as $study) { $studyPublisher->publish($study); @@ -167,7 +166,7 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis $project->delete(); $draft->delete(); - + // Notification::send($project->owner, new DraftProcessedNotification($project)); } } diff --git a/app/Models/Draft.php b/app/Models/Draft.php index 541fcdc7..ae86995b 100644 --- a/app/Models/Draft.php +++ b/app/Models/Draft.php @@ -23,7 +23,7 @@ class Draft extends Model 'team_id', 'settings', 'info', - 'project_enabled' + 'project_enabled', ]; public function files() diff --git a/app/Models/HasDOI.php b/app/Models/HasDOI.php index 5f3ae68c..bcd5ce81 100644 --- a/app/Models/HasDOI.php +++ b/app/Models/HasDOI.php @@ -42,15 +42,15 @@ public function generateDOI($doiService) } elseif ($this instanceof Study) { $users = $this->allUsers(); $citations = []; - if($this->project){ + if ($this->project) { $authors = $this->project->authors ? $this->project->authors : []; $projectIdentifier = $this->getIdentifier($this->project, 'identifier'); $suffix = 'P'.$projectIdentifier.'.'.'S'.$identifier; $citations = $this->project->citation ? $this->project->citation : []; - }else{ + } else { $suffix = 'S'.$identifier; } - + $url = $url.'S'.$identifier; $resourceType = 'Study'; @@ -66,12 +66,12 @@ public function generateDOI($doiService) $users = $this->study->allUsers(); $studyIdentifier = $this->getIdentifier($this->study, 'identifier'); $citations = []; - if($this->project){ + if ($this->project) { $authors = $this->project->authors ? $this->project->authors : []; $projectIdentifier = $this->getIdentifier($this->project, 'identifier'); $suffix = 'P'.$projectIdentifier.'.'.'S'.$studyIdentifier.'.'.'D'.$identifier; $citations = $this->project->citation ? $this->project->citation : []; - }else{ + } else { $suffix = 'S'.$studyIdentifier.'.'.'D'.$identifier; } $url = $url.'D'.$identifier; From 001cc15d32ab31559b9f5180795d156ad5b002b4 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Mon, 6 Nov 2023 10:57:12 +0100 Subject: [PATCH 31/38] fix: more bug fixes and exceptions handling --- app/Actions/Project/AssignIdentifier.php | 3 +- app/Console/Commands/AssignDOIs.php | 19 +- .../Schemas/Bioschema/BiochemaController.php | 55 +-- .../Controllers/ApplicationController.php | 4 +- app/Http/Controllers/DraftController.php | 20 +- app/Http/Controllers/ProjectController.php | 18 +- app/Http/Controllers/StudyController.php | 13 + app/Jobs/ProcessSubmission.php | 2 +- app/Models/HasDOI.php | 4 +- app/Models/Project.php | 9 +- app/Models/Study.php | 4 +- config/validations.php | 1 - resources/js/Layouts/AppLayout.vue | 7 + resources/js/Pages/Dashboard.vue | 4 +- resources/js/Pages/Project/Index.vue | 2 +- resources/js/Pages/Public/Datasets.vue | 2 +- resources/js/Pages/Public/Project/Files.vue | 127 +------ resources/js/Pages/Public/Project/Layout.vue | 2 +- .../Project/{Studies.vue => Samples.vue} | 0 resources/js/Pages/Public/Project/Study.vue | 14 +- resources/js/Pages/Public/Projects.vue | 2 +- resources/js/Pages/Public/Studies.vue | 332 ++++++++++++++++++ resources/js/Pages/Publish.vue | 104 +++++- resources/js/Pages/Study/Files.vue | 1 - resources/js/Pages/Upload.vue | 233 ++++++------ resources/js/Shared/FileSystemBrowser.vue | 29 +- resources/js/Shared/StudyCardPublic.vue | 95 +---- resources/js/Shared/StudySearch.vue | 39 ++ routes/web.php | 4 +- 29 files changed, 749 insertions(+), 400 deletions(-) rename resources/js/Pages/Public/Project/{Studies.vue => Samples.vue} (100%) create mode 100644 resources/js/Pages/Public/Studies.vue create mode 100644 resources/js/Shared/StudySearch.vue diff --git a/app/Actions/Project/AssignIdentifier.php b/app/Actions/Project/AssignIdentifier.php index 7cdfa231..eb4f74ce 100644 --- a/app/Actions/Project/AssignIdentifier.php +++ b/app/Actions/Project/AssignIdentifier.php @@ -6,6 +6,7 @@ use App\Models\Study; use App\Models\Ticker; use App\Services\DOI\DOIService; +use Illuminate\Support\Collection; class AssignIdentifier { @@ -33,7 +34,7 @@ public function assign($model) $studies = null; if ($model instanceof Project) { $project = $model; - } elseif (is_array($model)) { + } elseif ($model instanceof Collection) { $studies = $model; } diff --git a/app/Console/Commands/AssignDOIs.php b/app/Console/Commands/AssignDOIs.php index 46585d00..085ff6b1 100644 --- a/app/Console/Commands/AssignDOIs.php +++ b/app/Console/Commands/AssignDOIs.php @@ -2,8 +2,9 @@ namespace App\Console\Commands; +use App\Actions\Project\AssignIdentifier; use App\Models\Project; -use App\Services\DOI\DOIService; +use App\Models\Study; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; @@ -28,9 +29,9 @@ class AssignDOIs extends Command * * @return int */ - public function handle(DOIService $doiService) + public function handle(AssignIdentifier $assigner) { - return DB::transaction(function () use ($doiService) { + return DB::transaction(function () use ($assigner) { $projects = Project::where([ ['is_public', true], ['doi', null], @@ -38,7 +39,17 @@ public function handle(DOIService $doiService) foreach ($projects as $project) { $projectDOI = $project->doi ? $project->doi : null; - $project->generateDOI($doiService); + $assigner->assign($project); + } + + $studies = Study::where([ + ['is_public', true], + ['doi', null], + ])->get(); + + foreach ($studies as $study) { + $studyDOI = $study->doi ? $study->doi : null; + $assigner->assign(collect([$study])); } }); } diff --git a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php index d3a1454a..956aaefb 100644 --- a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php +++ b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php @@ -12,6 +12,7 @@ use App\Models\User; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Http; use Spatie\SchemaOrg\Schema; /** @@ -231,26 +232,25 @@ public function getMolecules($sample) foreach ($sample->molecules as &$molecule) { $inchiKey = $molecule->INCHI_KEY; $pubchemLink = 'https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/inchikey/'.$inchiKey.'/property/IUPACName/JSON'; - $json = file_get_contents($pubchemLink); - $jsonDecode = json_decode($json, true); - $cid = $jsonDecode['PropertyTable']['Properties'][0]['CID']; - $iupacName = $jsonDecode['PropertyTable']['Properties'][0]['IUPACName']; - - $moleculeSchema = Schema::MolecularEntity(); - $moleculeSchema['@id'] = $inchiKey; - $moleculeSchema['dct:conformsTo'] = $this->conformsTo(['https://bioschemas.org/profiles/MolecularEntity/0.5-RELEASE']); - $moleculeSchema['identifier'] = $inchiKey; - $moleculeSchema->name($molecule->CAS_NUMBER); - $moleculeSchema->url('https://pubchem.ncbi.nlm.nih.gov/compound/'.$cid); - $moleculeSchema->inChI('InChI='.$molecule->STANDARD_INCHI); - $moleculeSchema->inChIKey($inchiKey); - $moleculeSchema->iupacName($iupacName); - $moleculeSchema->molecularFormula($molecule->FORMULA); - $moleculeSchema->molecularWeight($molecule->MOLECULAR_WEIGHT); - $moleculeSchema->smiles([$molecule->SMILES, $molecule->SMILES_CHIRAL, $molecule->CANONICAL_SMILES]); - $moleculeSchema->hasRepresentation($molecule->MOL); - $moleculeSchema->description('Percentage composition: '.$molecule->pivot->percentage_composition.'%'); - array_push($molecules, $moleculeSchema); + $json = json_decode(Http::get($pubchemLink)->body(), true); + // $cid = $json['PropertyTable']['Properties'][0]['CID']; + // $iupacName = $json['PropertyTable']['Properties'][0]['IUPACName']; + + // $moleculeSchema = Schema::MolecularEntity(); + // $moleculeSchema['@id'] = $inchiKey; + // $moleculeSchema['dct:conformsTo'] = $this->conformsTo(['https://bioschemas.org/profiles/MolecularEntity/0.5-RELEASE']); + // $moleculeSchema['identifier'] = $inchiKey; + // $moleculeSchema->name($molecule->CAS_NUMBER); + // $moleculeSchema->url('https://pubchem.ncbi.nlm.nih.gov/compound/'.$cid); + // $moleculeSchema->inChI('InChI='.$molecule->STANDARD_INCHI); + // $moleculeSchema->inChIKey($inchiKey); + // $moleculeSchema->iupacName($iupacName); + // $moleculeSchema->molecularFormula($molecule->FORMULA); + // $moleculeSchema->molecularWeight($molecule->MOLECULAR_WEIGHT); + // $moleculeSchema->smiles([$molecule->SMILES, $molecule->SMILES_CHIRAL, $molecule->CANONICAL_SMILES]); + // $moleculeSchema->hasRepresentation($molecule->MOL); + // $moleculeSchema->description('Percentage composition: '.$molecule->pivot->percentage_composition.'%'); + // array_push($molecules, $moleculeSchema); } return $molecules; @@ -290,9 +290,18 @@ public function getSample($study) */ public function getNMRiumInfo($dataset) { - $nmrium = NMRium::where([['dataset_id', $dataset->id]])->firstOrFail(); - $info = json_decode($nmrium->nmrium_info)->spectra[0]->info; - + $nmrium = $dataset->nmrium; + if (! $nmrium) { + $study = $dataset->study; + $studyNMRiumInfo = json_decode($study->nmrium->nmrium_info); + foreach ($studyNMRiumInfo->data->spectra as $spectra) { + $fileSource = $spectra->sourceSelector->files[0]; + $fileName = pathinfo($fileSource); + if ($fileName['basename'] == $dataset->fsObject->name) { + $info = $spectra->info; + } + } + } $solvent = $info->solvent; $nucleus = $info->nucleus; if (is_string($nucleus)) { diff --git a/app/Http/Controllers/ApplicationController.php b/app/Http/Controllers/ApplicationController.php index a1acedd6..18c994a6 100644 --- a/app/Http/Controllers/ApplicationController.php +++ b/app/Http/Controllers/ApplicationController.php @@ -52,8 +52,8 @@ public function resolve(Request $request, $identifier) 'tab' => $tab, ]); break; - case 'studies': - return Inertia::render('Public/Project/Studies', [ + case 'samples': + return Inertia::render('Public/Project/Samples', [ 'project' => (new ProjectResource($project))->lite(false, []), 'tab' => $tab, ]); diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 82e6c238..9fd0bdcb 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -155,16 +155,16 @@ public function process(Request $request, Draft $draft) $input = $request->all(); $project = Project::where('draft_id', $draft->id)->first(); - // if ($project) { - // $rule = Rule::unique('projects')->where('owner_id', $input['owner_id'])->ignore($project->id); - // } else { - // $rule = Rule::unique('projects')->where('owner_id', $input['owner_id']); - // } - - // $validation = $request->validate([ - // 'name' => ['required', 'string', 'max:255', Rule::unique('drafts') - // ->where('owner_id', $input['owner_id'])->ignore($draft->id), $rule, ], - // ]); + if ($project) { + $rule = Rule::unique('projects')->where('owner_id', $input['owner_id'])->ignore($project->id); + } else { + $rule = Rule::unique('projects')->where('owner_id', $input['owner_id']); + } + + $validation = $request->validate([ + 'name' => ['required', 'string', 'max:255', Rule::unique('drafts') + ->where('owner_id', $input['owner_id'])->ignore($draft->id), $rule, ], + ]); $draftFolders = FileSystemObject::with('children') ->where([ diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 7786b231..6799316c 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -43,15 +43,14 @@ public function publicProjectView(Request $request, $owner, $slug) } $tab = $request->get('tab'); - if ($tab == 'info') { return Inertia::render('Public/Project/Show', [ 'project' => (new ProjectResource($project))->lite(false, ['users', 'authors', 'citations']), 'tab' => $tab, ]); - } elseif ($tab == 'studies') { + } elseif ($tab == 'samples') { return Inertia::render('Public/Project/Studies', [ - 'project' => (new ProjectResource($project))->lite(false, []), + 'project' => (new ProjectResource($project))->lite(false, ['studies']), 'tab' => $tab, ]); } elseif ($tab == 'files') { @@ -108,7 +107,9 @@ public function toggleStarred(Request $request, Project $project) public function status(Request $request, Project $project) { - return response()->json(['status' => $project->status, 'logs' => $project->process_logs]); + if ($project) { + return response()->json(['status' => $project->status, 'logs' => $project->process_logs]); + } } public function show(Request $request, Project $project, GetLicense $getLicense) @@ -281,14 +282,14 @@ public function publish(Request $request, Project $project) if ($project) { $enableProjectMode = $request->get('enableProjectMode'); if ($enableProjectMode) { - $project->release_date = $request->get('releaseDate'); - $project->status = 'queued'; - $project->save(); - $validation = $project->validation; $validation->process(); $validation = $validation->fresh(); if ($validation['report']['project']['status']) { + $project->release_date = $request->get('releaseDate'); + $project->status = 'queued'; + $project->save(); + ProcessSubmission::dispatch($project); return response()->json([ @@ -298,6 +299,7 @@ public function publish(Request $request, Project $project) } else { return response()->json([ 'errors' => 'Validation failing. Please provide all the required data and try again. If the problem persists, please contact us.', + 'validation' => $validation, ], 422); } } else { diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index c432949f..781d7c6c 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -5,6 +5,7 @@ use App\Actions\License\GetLicense; use App\Actions\Study\CreateNewStudy; use App\Actions\Study\UpdateStudy; +use App\Http\Resources\StudyResource; use App\Models\FileSystemObject; use App\Models\Molecule; use App\Models\NMRium; @@ -26,6 +27,18 @@ class StudyController extends Controller { + public function publicStudiesView(Request $request) + { + // $datasets = Cache::rememberForever('datasets', function () { + $studies = StudyResource::collection(Study::with('datasets')->where([['is_public', true], ['is_archived', false]])->filter($request->only('search', 'sort', 'mode'))->paginate(12)->withQueryString()); + // }); + + return Inertia::render('Public/Studies', [ + 'filters' => $request->all('search', 'sort', 'mode'), + 'studies' => $studies, + ]); + } + public function store(Request $request, CreateNewStudy $creator) { $study = $creator->create($request->all()); diff --git a/app/Jobs/ProcessSubmission.php b/app/Jobs/ProcessSubmission.php index 33c38c18..ad9052df 100644 --- a/app/Jobs/ProcessSubmission.php +++ b/app/Jobs/ProcessSubmission.php @@ -114,11 +114,11 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis if ($project) { $_studies = $project->studies; - if ($draft) { $environment = env('APP_ENV', 'local'); foreach ($_studies as $study) { + // $study->users()->sync($project->user()->getDictionary()); $studyPath = preg_replace( '~//+~', '/', diff --git a/app/Models/HasDOI.php b/app/Models/HasDOI.php index bcd5ce81..be580ff7 100644 --- a/app/Models/HasDOI.php +++ b/app/Models/HasDOI.php @@ -142,7 +142,7 @@ public function generateDOI($doiService) ]; $attributes = [ - 'creators' => $creators, + 'creators' => count($creators) > 0 ? $creators : $contributors, 'titles' => [ [ 'title' => $this->name, @@ -163,6 +163,8 @@ public function generateDOI($doiService) 'schemaVersion' => 'http://datacite.org/schema/kernel-4', ]; + // dd($attributes); + $doiResponse = $doiService->createDOI($suffix, $attributes); $this->doi = $doiResponse['data']['id']; $this->datacite_schema = $doiResponse; diff --git a/app/Models/Project.php b/app/Models/Project.php index f90620da..97c946d6 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -83,11 +83,12 @@ public function getIsPublishedAttribute() { if ($this->is_public) { return true; - } else { - if ($this->release_date) { - return ! Carbon::now()->startOfDay()->gte($this->release_date); - } } + // else { + // if ($this->release_date) { + // return ! Carbon::now()->startOfDay()->gte($this->release_date); + // } + // } return false; } diff --git a/app/Models/Study.php b/app/Models/Study.php index f91e9b7b..e528d192 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -77,7 +77,7 @@ public function getIsPublishedAttribute() if ($this->release_date) { return ! Carbon::now()->startOfDay()->gte($this->release_date); } else { - return $this->project->is_published; + return $this->project ? $this->project->is_published : false; } } @@ -228,7 +228,7 @@ public function owner() */ public function allUsers() { - return $this->project->users->merge($this->users); + return $this->project ? $this->project->users->merge($this->users) : $this->users->merge([$this->owner]); } /** diff --git a/config/validations.php b/config/validations.php index 10fc602f..167b0686 100644 --- a/config/validations.php +++ b/config/validations.php @@ -15,7 +15,6 @@ 'citations' => 'array|min:1', 'authors' => 'required|array|min:1', 'license' => 'required', - 'image' => 'required', ], 'study' => [ 'title' => 'required', diff --git a/resources/js/Layouts/AppLayout.vue b/resources/js/Layouts/AppLayout.vue index fc2b811f..6ee9878e 100644 --- a/resources/js/Layouts/AppLayout.vue +++ b/resources/js/Layouts/AppLayout.vue @@ -768,6 +768,13 @@ const navigation = [ icon: Squares2X2Icon, bg: "bg-white", }, + // { + // auth: false, + // name: "Spectra", + // href: "/spectra", + // icon: Squares2X2Icon, + // bg: "bg-white", + // }, { auth: true, name: "Dashboard", diff --git a/resources/js/Pages/Dashboard.vue b/resources/js/Pages/Dashboard.vue index f4cd0191..d7924134 100644 --- a/resources/js/Pages/Dashboard.vue +++ b/resources/js/Pages/Dashboard.vue @@ -71,11 +71,11 @@ />

      - No datasets + No Projects or Samples

      - Get started by uploading a dataset. + Get started by uploading your data.

      nmrXiv is organized around projects. Projects can - contain as many studies as you wish and each study + contain as many samples as you wish and each sample receives its very own URL. To learn more, check out our documentation.
      diff --git a/resources/js/Pages/Public/Datasets.vue b/resources/js/Pages/Public/Datasets.vue index 7e217a26..114575d3 100644 --- a/resources/js/Pages/Public/Datasets.vue +++ b/resources/js/Pages/Public/Datasets.vue @@ -12,7 +12,7 @@

      Explore, analyze, and share raw spectra and - assignements. Learn more about + assignments. Learn more about -

      - -
      -
      - -
        -
      • -
        - - - - -
        -

        - {{ file.name }} -

        -

        - {{ file.size }} -

        -
      • -
      -
      -
      -
      - - - -
      -
      -
      +
      +
      @@ -180,7 +74,7 @@ diff --git a/resources/js/Pages/Publish.vue b/resources/js/Pages/Publish.vue index 3aad22ce..237579c0 100644 --- a/resources/js/Pages/Publish.vue +++ b/resources/js/Pages/Publish.vue @@ -30,7 +30,7 @@
    -
    +
    +
    +
    +
    +
    +

    + {{ status }} +

    +
    + + Go to Dashboard + +
    +
    +
    +
    + Whats next? +
    +

    + Please allow some time to process your + submission. You will recieve an email once your + submission is processed. Upon processing will + also receive an email with citation details and + other helpful information to share your + datasets. +

    +
    +
    +
    +
    @@ -744,6 +790,7 @@ export default { validationStatus: true, errors: null, projectSpecies: "", + status: "draft", }; }, @@ -777,7 +824,10 @@ export default { }); this.publishForm.project.tags = tags; this.license = this.project.license; - + this.status = + this.project.status && this.project.status != "" + ? this.project.status + : "draft"; this.publishForm.project.species = JSON.parse(this.project.species) ? JSON.parse(this.project.species) : []; @@ -791,22 +841,24 @@ export default { }); }, updateProject() { - this.loadingStep = true; - axios - .put(route("dashboard.project.update", this.project.id), { - name: this.publishForm.project.name, - description: this.publishForm.project.description, - tags: this.publishForm.project.tags, - tags_array: this.publishForm.project.tags - ? this.publishForm.project.tags.map((a) => a.text) - : [], - license_id: this.license ? this.license.id : null, - species: this.publishForm.project.species, - release_date: this.publishForm.releaseDate, - }) - .then((res) => { - console.log("success"); - }); + if (this.publishForm.enableProjectMode) { + this.loadingStep = true; + axios + .put(route("dashboard.project.update", this.project.id), { + name: this.publishForm.project.name, + description: this.publishForm.project.description, + tags: this.publishForm.project.tags, + tags_array: this.publishForm.project.tags + ? this.publishForm.project.tags.map((a) => a.text) + : [], + license_id: this.license ? this.license.id : null, + species: this.publishForm.project.species, + release_date: this.publishForm.releaseDate, + }) + .then((res) => { + console.log("success"); + }); + } }, updateSpecies(species) { if (species && species != "") { @@ -879,10 +931,24 @@ export default { }) .then((response) => { this.status = response.data.project.status; - this.trackProject(); + // this.trackProject(); }); } }, + // trackProject() { + // axios + // .get("/projects/status/" + this.project.id + "/queue") + // .then((response) => { + // this.status = response.data.status; + // if (this.status != "complete") { + // setTimeout(() => this.trackProject(), 10000); + // } else { + // return this.$inertia.visit( + // this.route("dashboard.projects", [this.project.id]) + // ); + // } + // }); + // }, }, computed: { url() { diff --git a/resources/js/Pages/Study/Files.vue b/resources/js/Pages/Study/Files.vue index e80c6306..2c726c45 100644 --- a/resources/js/Pages/Study/Files.vue +++ b/resources/js/Pages/Study/Files.vue @@ -500,7 +500,6 @@ export default { file.loading = false; }); } - this.$emit("reloadnmrium"); }, loadMol() { this.svgString = null; diff --git a/resources/js/Pages/Upload.vue b/resources/js/Pages/Upload.vue index 2cf572fc..d6c9572d 100644 --- a/resources/js/Pages/Upload.vue +++ b/resources/js/Pages/Upload.vue @@ -25,6 +25,10 @@ > {{ currentDraft.name }}

    + Submit data to nmrXiv
  • @@ -336,10 +340,7 @@
    -
    +
    -

    - - - - {{ study.name }} -

    -
    - -
    - {{ - ds.name - }} +
    ({{ - ds.type - }}){{ + ds.name + }} + ({{ + ds.type + }}) +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    - +
    @@ -644,16 +659,24 @@ class="flex-shrink-0" >
    { - this.loadingStep = false; - }) - .then((response) => { - this.project = response.data.project; - this.validation = this.parseJSON( - response.data.validation.report - ); - this.validationStatus = true; - this.validation.project.studies.forEach((study) => { - console.log(study); - if (study.status == false) { - this.validationStatus = false; + this.fetchValidations().then(() => { + if (this.validationStatus) { + this.loadingStep = true; + axios + .post( + "/dashboard/drafts/" + + this.currentDraft.id + + "/complete", + {} + ) + .catch(() => { + this.loadingStep = false; + }) + .then((response) => { + this.project = response.data.project; + this.validation = this.parseJSON( + response.data.validation.report + ); + this.validationStatus = true; + this.validation.project.studies.forEach((study) => { + if (study.status == false) { + this.validationStatus = false; + } + }); + if (this.project) { + window.location = + "/publish/" + this.currentDraft.id; } }); - if (this.project) { - // this.loadingStep = false; - // this.loadLicenses(); - // this.selectStep(3); - // this.publishForm.project.name = this.draftForm.name; - // this.publishForm.project.description = - // this.draftForm.description; - // this.publishForm.project.tags = this.draftForm.tags; - // this.trackProject(); - window.location = - "/publish/" + this.currentDraft.id; - } - }); - } else { - alert( - "Samples validation failed: Please provide all meta data to proceed" - ); - } + } else { + this.showSamplesSummary(); + alert( + "Samples validation failed: Please provide all meta data to proceed" + ); + } + }); }, publish() { if (this.publishForm.conditions && this.publishForm.terms) { @@ -3045,6 +3063,7 @@ export default { let tags = []; this.file = null; this.draftForm.tags = []; + this.draftForm.owner_id = this.$page.props.user.id; if (this.currentDraft.tags) { this.currentDraft.tags.forEach((t) => { tags.push({ @@ -3108,7 +3127,7 @@ export default { }, 30000); }, fetchValidations() { - axios + return axios .get("/projects/" + this.project.id + "/validation") .then((response) => { this.validation = response.data.report; diff --git a/resources/js/Shared/FileSystemBrowser.vue b/resources/js/Shared/FileSystemBrowser.vue index 7ae8780e..b889faaa 100644 --- a/resources/js/Shared/FileSystemBrowser.vue +++ b/resources/js/Shared/FileSystemBrowser.vue @@ -12,6 +12,7 @@
    @@ -342,7 +343,8 @@ {{ $page.props.selectedFileSystemObject.name }} { - this.file = response.data.file; - this.file.has_children = true; - this.$page.props.selectedFileSystemObject = this.file; - this.$page.props.selectedFolder = "/"; - this.updateBusyStatus(true); - this.$emit("loading", false); - this.loading = false; - }); + if (this.draft) { + axios.get(this.url).then((response) => { + this.file = response.data.file; + this.file.has_children = true; + this.$page.props.selectedFileSystemObject = this.file; + this.$page.props.selectedFolder = "/"; + this.updateBusyStatus(true); + this.$emit("loading", false); + this.loading = false; + }); + } else { + this.file = this.$page.props.selectedFileSystemObject; + } }, annotate() { this.updateBusyStatus(true); diff --git a/resources/js/Shared/StudyCardPublic.vue b/resources/js/Shared/StudyCardPublic.vue index 18670146..5900cf50 100644 --- a/resources/js/Shared/StudyCardPublic.vue +++ b/resources/js/Shared/StudyCardPublic.vue @@ -3,83 +3,25 @@ v-if="study" class="flex flex-col border rounded-lg shadow-lg transition ease-in-out delay-150 duration-300 overflow-hidden" > -
    - - - - - -
    - - - - +
    +
    +
    + +
    + +
    + + + diff --git a/routes/web.php b/routes/web.php index 6e4b9362..bd1b46b9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -341,5 +341,5 @@ Route::get('datasets/{owner}/{slug}', [DatasetController::class, 'publicDatasetView']) ->name('public.dataset'); -Route::get('spectra', [DatasetController::class, 'publicDatasetsView']) - ->name('public.datasets'); +Route::get('spectra', [StudyController::class, 'publicStudiesView']) + ->name('public.spectra'); From 3d59b06253781aac4949d635b3878c1c77ef390a Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Tue, 7 Nov 2023 10:11:09 +0100 Subject: [PATCH 32/38] fix: more bug fixes and updates --- app/Http/Controllers/DraftController.php | 10 +-- app/Http/Controllers/StudyController.php | 46 +++++++++++-- app/Jobs/ProcessSubmission.php | 7 ++ resources/js/Pages/Public/Studies.vue | 12 ++-- resources/js/Pages/Publish.vue | 6 +- resources/js/Pages/Upload.vue | 1 + resources/js/Shared/StudyCardPublic.vue | 86 +++++++++++++----------- 7 files changed, 112 insertions(+), 56 deletions(-) diff --git a/app/Http/Controllers/DraftController.php b/app/Http/Controllers/DraftController.php index 9fd0bdcb..674943c7 100644 --- a/app/Http/Controllers/DraftController.php +++ b/app/Http/Controllers/DraftController.php @@ -482,11 +482,13 @@ public function processFolder($folders) public function saveAnnotationsDetected($folder) { - $study = $folder->study; + if ($folder) { + $study = $folder->study; - if ($study) { - $study->has_nmredata = true; - $study->save(); + if ($study) { + $study->has_nmredata = true; + $study->save(); + } } } diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index 781d7c6c..74a7bcf3 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -185,14 +185,16 @@ public function nmriumVersions(Request $request, Study $study) public function nmriumInfo(Request $request, Study $study) { + + // $version = $request->get('version'); + // $spectra = $request->get('spectra'); + // $molecules = $nmriumInfo['data']['molecules']; + // $molecularInfo = $molecules; + if ($study) { $user = Auth::user(); $data = $request->all(); - // $version = $request->get('version'); - // $spectra = $request->get('spectra'); $nmriumInfo = $data; - // $molecules = $nmriumInfo['data']['molecules']; - // $molecularInfo = $molecules; $nmrium = $study->nmrium; if ($nmrium) { $nmrium->nmrium_info = $nmriumInfo; @@ -207,6 +209,42 @@ public function nmriumInfo(Request $request, Study $study) } $study->save(); + $_nmriumJSON = $nmriumInfo; + foreach ($study->datasets as $dataset) { + $fsObject = $dataset->fsObject; + $level = -($fsObject->level + 1); + echo $fsObject->path; + $path = implode('/', array_slice(explode('/', $fsObject->path), $level)); + foreach ($nmriumInfo['data']['spectra'] as $spectra) { + unset($_nmriumJSON['data']['spectra']); + $files = $spectra['sourceSelector']['files']; + $pathsMatch = true; + if ($files) { + foreach ($files as $file) { + if (! str_contains($file, $path)) { + $pathsMatch = false; + } + } + } + if ($pathsMatch) { + $_nmriumJSON['data']['spectra'] = [$spectra]; + $_nmrium = $dataset->nmrium; + if ($_nmrium) { + $_nmrium->nmrium_info = $_nmriumJSON; + $dataset->has_nmrium = true; + $_nmrium->save(); + } else { + $_nmrium = NMRium::create([ + 'nmrium_info' => json_encode($_nmriumJSON), + ]); + $dataset->nmrium()->save($_nmrium); + $dataset->has_nmrium = true; + } + $dataset->save(); + } + } + } + return $study->fresh(); } } diff --git a/app/Jobs/ProcessSubmission.php b/app/Jobs/ProcessSubmission.php index ad9052df..2385a760 100644 --- a/app/Jobs/ProcessSubmission.php +++ b/app/Jobs/ProcessSubmission.php @@ -151,6 +151,13 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis $study->process_logs = $process_logs; $study->draft_id = null; $study->project_id = null; + + foreach ($study->datasets as $dataset) { + $dataset->draft_id = null; + $dataset->project_id = null; + $dataset->save(); + } + $study->status = 'complete'; $study->save(); } diff --git a/resources/js/Pages/Public/Studies.vue b/resources/js/Pages/Public/Studies.vue index ab420d39..c282540e 100644 --- a/resources/js/Pages/Public/Studies.vue +++ b/resources/js/Pages/Public/Studies.vue @@ -149,10 +149,10 @@ class="mt-4 mx-auto max-w-md grid gap-8 sm:max-w-lg lg:grid-cols-4 lg:max-w-7xl" > - + >
    @@ -165,10 +165,10 @@ class="divide-y border rounded-md divide-gray-200" > - + >
    @@ -212,7 +212,7 @@ import AppLayout from "@/Layouts/AppLayout.vue"; import { Link } from "@inertiajs/vue3"; import StudySearch from "@/Shared/StudySearch.vue"; -import StudyCard from "@/Shared/StudyCard.vue"; +import StudyPublicCard from "@/Shared/StudyCardPublic.vue"; import { ref } from "vue"; import throttle from "lodash/throttle"; import pickBy from "lodash/pickBy"; @@ -266,7 +266,7 @@ export default { ChevronDownIcon, QueueListIcon, Squares2X2Icon, - StudyCard, + StudyPublicCard, }, props: { studies: { diff --git a/resources/js/Pages/Publish.vue b/resources/js/Pages/Publish.vue index 237579c0..2a7bfc1e 100644 --- a/resources/js/Pages/Publish.vue +++ b/resources/js/Pages/Publish.vue @@ -669,9 +669,9 @@

    Please allow some time to process your submission. You will recieve an email once your - submission is processed. Upon processing will - also receive an email with citation details and - other helpful information to share your + submission is processed. Upon publishing you + will also receive an email with citation details + and other helpful information to share your datasets.

    diff --git a/resources/js/Pages/Upload.vue b/resources/js/Pages/Upload.vue index d6c9572d..512b3518 100644 --- a/resources/js/Pages/Upload.vue +++ b/resources/js/Pages/Upload.vue @@ -2654,6 +2654,7 @@ export default { ) .then((response) => { this.currentDraft = response.data; + this.draftForm.name = this.currentDraft.name; }); }, getTarget(id) { diff --git a/resources/js/Shared/StudyCardPublic.vue b/resources/js/Shared/StudyCardPublic.vue index 5900cf50..2a72aa95 100644 --- a/resources/js/Shared/StudyCardPublic.vue +++ b/resources/js/Shared/StudyCardPublic.vue @@ -3,59 +3,67 @@ v-if="study" class="flex flex-col border rounded-lg shadow-lg transition ease-in-out delay-150 duration-300 overflow-hidden" > -
    -
      -
    • -
      +
      +
        +
      • - - - -
      -
    • -
    -
    -
    -
    - #{{ study.identifier }} - -
    -

    - {{ study.name }} -

    -
    -
    -
    + + + +
    + + +
    +
    +
    +
    + #{{ study.identifier }} +
    +

    Public

    -
    +

    Private

    -
    +
    + +
    +

    + {{ study.name }} +

    +
    +
    +
    Last updated on {{ formatDate(study.updated_at) }}
    - -
    +
    +
    @@ -65,7 +73,7 @@ import { LockOpenIcon } from "@heroicons/vue/24/solid"; import { PencilIcon } from "@heroicons/vue/24/solid"; import { EnvelopeIcon } from "@heroicons/vue/24/solid"; import { Link } from "@inertiajs/vue3"; -import Depictor from "@/Shared/Depictor.vue"; +import Depictor2D from "@/Shared/Depictor2D.vue"; export default { components: { LockClosedIcon, @@ -73,7 +81,7 @@ export default { EnvelopeIcon, PencilIcon, Link, - Depictor, + Depictor2D, }, props: ["study", "project"], setup() {}, From 7939179e4e0203ff04d58be7b6ba0168a8638723 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Tue, 7 Nov 2023 17:01:00 +0100 Subject: [PATCH 33/38] fix: more updates, bug fixes and refactoring --- app/Console/Commands/ArchiveData.php | 44 +++++ app/Http/Resources/ProjectResource.php | 1 + app/Http/Resources/StudyResource.php | 2 + app/Jobs/ArchiveProject.php | 155 ++++++++++++++++++ app/Jobs/ProcessSubmission.php | 3 + ...023_11_07_125717_update_projects_table.php | 29 ++++ resources/js/Pages/Public/Studies.vue | 17 +- resources/js/Shared/ProjectCard.vue | 52 ++---- resources/js/Shared/SpectraViewer.vue | 139 ++++------------ resources/js/Shared/StudyCard.vue | 83 +++++----- 10 files changed, 329 insertions(+), 196 deletions(-) create mode 100644 app/Console/Commands/ArchiveData.php create mode 100644 app/Jobs/ArchiveProject.php create mode 100644 database/migrations/2023_11_07_125717_update_projects_table.php diff --git a/app/Console/Commands/ArchiveData.php b/app/Console/Commands/ArchiveData.php new file mode 100644 index 00000000..85f9168f --- /dev/null +++ b/app/Console/Commands/ArchiveData.php @@ -0,0 +1,44 @@ +get(); + + foreach ($projects as $project) { + ArchiveProject::dispatch($project); + } + }); + } +} diff --git a/app/Http/Resources/ProjectResource.php b/app/Http/Resources/ProjectResource.php index b6de80fa..1253e4be 100644 --- a/app/Http/Resources/ProjectResource.php +++ b/app/Http/Resources/ProjectResource.php @@ -44,6 +44,7 @@ public function toArray($request) 'tags' => $this->tags, 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, + 'download_url' => $this->download_url, 'stats' => [ 'likes' => $this->likesCount(), ], diff --git a/app/Http/Resources/StudyResource.php b/app/Http/Resources/StudyResource.php index 228b7bb8..570b4485 100644 --- a/app/Http/Resources/StudyResource.php +++ b/app/Http/Resources/StudyResource.php @@ -42,6 +42,8 @@ public function toArray($request) 'public_url' => $this->public_url ? $this->public_url : null, 'updated_at' => $this->updated_at, 'study_preview_urls' => $this->study_preview_urls, + 'download_url' => $this->download_url, + 'has_nmrium' => $this->has_nmrium, $this->mergeWhen(! $this->lite, function () { return [ $this->mergeWhen( diff --git a/app/Jobs/ArchiveProject.php b/app/Jobs/ArchiveProject.php new file mode 100644 index 00000000..2833ffa9 --- /dev/null +++ b/app/Jobs/ArchiveProject.php @@ -0,0 +1,155 @@ +project = $project; + } + + /** + * Execute the job. + */ + public function handle(): void + { + $project = $this->project; + if ($project) { + $archiveDownloadURL = $project->download_url; + if($project->internal_status != 'processing' || $project->internal_status != 'completed'){ + $project->internal_status = 'processing'; + $project->save(); + + if ($archiveDownloadURL == null) { + $fsObject = $project->fsObject; + + if(!$fsObject){ + $fsObject = new FileSystemObject(); + $fsObject->type = 'directory'; + $fsObject->name = $project->slug; + $environment = env('APP_ENV', 'local'); + $fsObject->path = $environment.'/'.$project->uuid; + $fsObject->key = $project->uuid; + $fsObject->status = "present"; + $fsObject->relative_url = '/'.$project->uuid; + } + + if ($fsObject && $fsObject->status != 'missing') { + $path = $fsObject->path; + $s3Client = $this->storageClient(); + $bucket = config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.bucket'); + $s3keys = []; + $environment = env('APP_ENV', 'local'); + if ($fsObject->type == 'file') { + if (Storage::has($path)) { + array_push($s3keys, substr($fsObject->path, 1)); + } + } else { + $command = $s3Client->getCommand('ListObjects'); + $command['Bucket'] = $bucket; + if ($path[0] == '/') { + $command['Prefix'] = ltrim($path, $path[0]).'/'; + } else { + $command['Prefix'] = $path.'/'; + } + $result = $s3Client->execute($command); + if ($result['Contents']) { + foreach ($result['Contents'] as $file) { + array_push($s3keys, $file['Key']); + } + } + } + + $s3Client->registerStreamWrapper(); + + $zipFilePath = $environment.'/archive/'.$project->uuid.'/'.$fsObject->name.'.zip'; + + $archiveDestination = fopen('s3://'.$bucket.'/'.$zipFilePath, 'w'); + + $zip = new ZipStream\ZipStream( + outputStream: $archiveDestination, + defaultEnableZeroHeader: true, + sendHttpHeaders: false, + ); + + foreach ($s3keys as $key) { + $s3path = 's3://'.$bucket.'/'.$key; + if ($streamRead = fopen($s3path, 'r')) { + $sPath = explode($fsObject->relative_url, $key)[1]; + if ($sPath != '') { + $sPath = $fsObject->key.'/'.explode($fsObject->relative_url, $key)[1]; + } else { + $sPath = $fsObject->key; + } + $zip->addFileFromStream($sPath, $streamRead); + } else { + exit('Could not open stream for reading'); + } + } + $zip->finish(); + fclose($archiveDestination); + + Storage::setVisibility($zipFilePath, 'public'); + $url = Storage::url($zipFilePath); + $project->download_url = $url; + $project->internal_status = 'complete'; + $project->save(); + } + } else { + $project->internal_status = 'complete'; + $project->save(); + } + } + + } + } + + /** + * Get the S3 storage client instance. + * + * @return \Aws\S3\S3Client + */ + protected function storageClient() + { + $config = [ + 'region' => config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.region'), + 'version' => 'latest', + 'use_path_style_endpoint' => true, + 'url' => config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.endpoint'), + 'endpoint' => config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.endpoint'), + 'credentials' => [ + 'key' => config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.key'), + 'secret' => config('filesystems.disks.'.env('FILESYSTEM_DRIVER').'.secret'), + ], + ]; + + return S3Client::factory($config); + } +} \ No newline at end of file diff --git a/app/Jobs/ProcessSubmission.php b/app/Jobs/ProcessSubmission.php index 2385a760..c507ee27 100644 --- a/app/Jobs/ProcessSubmission.php +++ b/app/Jobs/ProcessSubmission.php @@ -3,6 +3,7 @@ namespace App\Jobs; use App\Actions\Project\AssignIdentifier; +use App\Jobs\ArchiveProject; use App\Actions\Project\PublishProject; use App\Actions\Study\PublishStudy; use App\Models\FileSystemObject; @@ -106,6 +107,8 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis if ($release_date->isToday()) { $projectPublisher->publish($project); } + + ArchiveProject::dispatch($project); Notification::send($project->owner, new DraftProcessedNotification($project)); } diff --git a/database/migrations/2023_11_07_125717_update_projects_table.php b/database/migrations/2023_11_07_125717_update_projects_table.php new file mode 100644 index 00000000..ac585233 --- /dev/null +++ b/database/migrations/2023_11_07_125717_update_projects_table.php @@ -0,0 +1,29 @@ +longText('download_url')->nullable(); + $table->string('status')->default('draft')->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('projects', function (Blueprint $table) { + $table->dropColumn('download_url'); + }); + } +}; diff --git a/resources/js/Pages/Public/Studies.vue b/resources/js/Pages/Public/Studies.vue index c282540e..c72d787d 100644 --- a/resources/js/Pages/Public/Studies.vue +++ b/resources/js/Pages/Public/Studies.vue @@ -157,19 +157,18 @@
    -
    -
      - +
      +
        +
        - +
    diff --git a/resources/js/Shared/ProjectCard.vue b/resources/js/Shared/ProjectCard.vue index 9148d2b8..db054595 100644 --- a/resources/js/Shared/ProjectCard.vue +++ b/resources/js/Shared/ProjectCard.vue @@ -62,7 +62,6 @@ class="text-gray-500" >#{{ project.identifier }}
    - {{}} {{ project.license .title @@ -185,7 +184,6 @@
    -
  • - - + >
  • @@ -68,9 +68,40 @@ -->
    - #{{ study.identifier }} +
    + #{{ study.identifier }} +
    +
    + + + + + + + + +

    Public

    +
    +
    + +

    Private

    +
    +
    +
    -
    -
    - - - - - - - - -

    Public

    -
    -
    - -

    Private

    -
    -
    -
    +
    Last updated on {{ formatDate(study.updated_at) }}
    @@ -139,7 +136,7 @@ import { PencilIcon } from "@heroicons/vue/24/solid"; import { EnvelopeIcon } from "@heroicons/vue/24/solid"; import { Link } from "@inertiajs/vue3"; import { StarIcon } from "@heroicons/vue/24/solid"; -import Depictor from "@/Shared/Depictor.vue"; +import Depictor2D from "@/Shared/Depictor2D.vue"; export default { components: { LockClosedIcon, @@ -148,7 +145,7 @@ export default { PencilIcon, StarIcon, Link, - Depictor, + Depictor2D, }, props: ["study"], setup() {}, From 3c0639b3286f93ed38df4a08209e5b5b37e7945f Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Tue, 7 Nov 2023 17:06:29 +0100 Subject: [PATCH 34/38] fix: bioschemas bug fix and formatting --- app/Console/Commands/ArchiveData.php | 6 ++-- .../Schemas/Bioschema/BiochemaController.php | 8 +++-- app/Jobs/ArchiveProject.php | 31 +++++++++---------- app/Jobs/ProcessSubmission.php | 3 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/Console/Commands/ArchiveData.php b/app/Console/Commands/ArchiveData.php index 85f9168f..2b664a1e 100644 --- a/app/Console/Commands/ArchiveData.php +++ b/app/Console/Commands/ArchiveData.php @@ -2,12 +2,10 @@ namespace App\Console\Commands; +use App\Jobs\ArchiveProject; +use App\Models\Project; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -use App\Models\Project; -use App\Models\Study; -use App\Jobs\ArchiveProject; -use App\Jobs\ArchiveStudy; class ArchiveData extends Command { diff --git a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php index 956aaefb..16b1876a 100644 --- a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php +++ b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php @@ -293,14 +293,18 @@ public function getNMRiumInfo($dataset) $nmrium = $dataset->nmrium; if (! $nmrium) { $study = $dataset->study; - $studyNMRiumInfo = json_decode($study->nmrium->nmrium_info); - foreach ($studyNMRiumInfo->data->spectra as $spectra) { + $NMRiumInfo = json_decode($study->nmrium->nmrium_info); + foreach ($NMRiumInfo->data->spectra as $spectra) { $fileSource = $spectra->sourceSelector->files[0]; $fileName = pathinfo($fileSource); if ($fileName['basename'] == $dataset->fsObject->name) { $info = $spectra->info; } } + } else { + $NMRiumInfo = json_decode($nmrium->nmrium_info); + $spectra = $NMRiumInfo->data->spectra[0]; + $info = $spectra->info; } $solvent = $info->solvent; $nucleus = $info->nucleus; diff --git a/app/Jobs/ArchiveProject.php b/app/Jobs/ArchiveProject.php index 2833ffa9..e21a744d 100644 --- a/app/Jobs/ArchiveProject.php +++ b/app/Jobs/ArchiveProject.php @@ -2,15 +2,14 @@ namespace App\Jobs; -use App\Models\Project; use App\Models\FileSystemObject; +use App\Models\Project; use Aws\S3\S3Client; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; use ZipStream; @@ -43,24 +42,24 @@ public function handle(): void $project = $this->project; if ($project) { $archiveDownloadURL = $project->download_url; - if($project->internal_status != 'processing' || $project->internal_status != 'completed'){ + if ($project->internal_status != 'processing' || $project->internal_status != 'completed') { $project->internal_status = 'processing'; $project->save(); - + if ($archiveDownloadURL == null) { $fsObject = $project->fsObject; - - if(!$fsObject){ + + if (! $fsObject) { $fsObject = new FileSystemObject(); $fsObject->type = 'directory'; $fsObject->name = $project->slug; $environment = env('APP_ENV', 'local'); $fsObject->path = $environment.'/'.$project->uuid; $fsObject->key = $project->uuid; - $fsObject->status = "present"; + $fsObject->status = 'present'; $fsObject->relative_url = '/'.$project->uuid; } - + if ($fsObject && $fsObject->status != 'missing') { $path = $fsObject->path; $s3Client = $this->storageClient(); @@ -86,19 +85,19 @@ public function handle(): void } } } - + $s3Client->registerStreamWrapper(); - + $zipFilePath = $environment.'/archive/'.$project->uuid.'/'.$fsObject->name.'.zip'; - + $archiveDestination = fopen('s3://'.$bucket.'/'.$zipFilePath, 'w'); - + $zip = new ZipStream\ZipStream( outputStream: $archiveDestination, defaultEnableZeroHeader: true, sendHttpHeaders: false, ); - + foreach ($s3keys as $key) { $s3path = 's3://'.$bucket.'/'.$key; if ($streamRead = fopen($s3path, 'r')) { @@ -115,7 +114,7 @@ public function handle(): void } $zip->finish(); fclose($archiveDestination); - + Storage::setVisibility($zipFilePath, 'public'); $url = Storage::url($zipFilePath); $project->download_url = $url; @@ -127,7 +126,7 @@ public function handle(): void $project->save(); } } - + } } @@ -152,4 +151,4 @@ protected function storageClient() return S3Client::factory($config); } -} \ No newline at end of file +} diff --git a/app/Jobs/ProcessSubmission.php b/app/Jobs/ProcessSubmission.php index c507ee27..1e8d19ea 100644 --- a/app/Jobs/ProcessSubmission.php +++ b/app/Jobs/ProcessSubmission.php @@ -3,7 +3,6 @@ namespace App\Jobs; use App\Actions\Project\AssignIdentifier; -use App\Jobs\ArchiveProject; use App\Actions\Project\PublishProject; use App\Actions\Study\PublishStudy; use App\Models\FileSystemObject; @@ -107,7 +106,7 @@ public function handle(AssignIdentifier $assigner, PublishProject $projectPublis if ($release_date->isToday()) { $projectPublisher->publish($project); } - + ArchiveProject::dispatch($project); Notification::send($project->owner, new DraftProcessedNotification($project)); From 2eed0edd24b0ee62c08f74ddd5d9c31bc4218347 Mon Sep 17 00:00:00 2001 From: Venkata Chandra Sekhar Nainala Date: Thu, 9 Nov 2023 02:18:06 +0100 Subject: [PATCH 35/38] feat: various bug fixes, ui improvements, updated commands, php 8.2 migration and rdkit cartridge based postgresql --- app/Console/Commands/ArchiveData.php | 3 + app/Console/Commands/ExtractSpectra.php | 164 ++++++++++++++++ app/Console/Commands/ManageFiles.php | 2 +- app/Console/Commands/SanitizeMolecules.php | 51 +++++ app/Console/Commands/SanitizeProjects.php | 30 ++- .../Schemas/Bioschema/BiochemaController.php | 134 ++++++------- app/Http/Controllers/StudyController.php | 14 +- app/Http/Resources/ProjectResource.php | 1 + app/Jobs/ArchiveStudy.php | 3 +- composer.json | 2 +- composer.lock | 51 +++-- .../2022_09_16_115525_create_nmrium_table.php | 8 +- docker-compose.yml | 9 +- docker/8.2/Dockerfile | 63 +++++++ docker/8.2/php.ini | 7 + docker/8.2/start-container | 17 ++ docker/8.2/supervisord.conf | 14 ++ docker/8.3/Dockerfile | 64 +++++++ docker/8.3/php.ini | 7 + docker/8.3/start-container | 17 ++ docker/8.3/supervisord.conf | 14 ++ resources/js/Layouts/AppLayout.vue | 8 +- resources/js/Pages/Announcement/Index.vue | 4 +- resources/js/Pages/Auth/Register.vue | 20 +- .../Console/Users/Partials/UserProfile.vue | 2 +- .../Partials/UpdateProfileInformationForm.vue | 18 +- resources/js/Pages/Project/Index.vue | 4 +- .../js/Pages/Project/Partials/Details.vue | 12 +- resources/js/Pages/Project/Settings.vue | 2 +- resources/js/Pages/Project/Show.vue | 42 ++--- resources/js/Pages/Public/Datasets.vue | 32 ++-- resources/js/Pages/Public/Project/Dataset.vue | 4 +- resources/js/Pages/Public/Project/Files.vue | 2 +- resources/js/Pages/Public/Project/Layout.vue | 27 +-- resources/js/Pages/Public/Project/License.vue | 2 +- resources/js/Pages/Public/Project/Samples.vue | 10 +- resources/js/Pages/Public/Project/Show.vue | 72 +++---- resources/js/Pages/Public/Project/Study.vue | 6 +- resources/js/Pages/Public/Projects.vue | 38 ++-- resources/js/Pages/Public/Studies.vue | 34 ++-- resources/js/Pages/Publish.vue | 86 ++++----- resources/js/Pages/Study/About.vue | 3 +- resources/js/Pages/Study/Datasets.vue | 6 +- resources/js/Pages/Study/Index.vue | 12 +- resources/js/Pages/Study/Layout.vue | 12 +- resources/js/Pages/Study/Partials/Details.vue | 16 +- resources/js/Pages/Upload.vue | 178 +++++++++--------- resources/js/Shared/Children.vue | 49 +++-- resources/js/Shared/Citation.vue | 12 +- resources/js/Shared/Depictor.vue | 18 +- resources/js/Shared/Depictor2D.vue | 18 +- resources/js/Shared/Depictor3D.vue | 16 +- resources/js/Shared/FileDetails.vue | 24 ++- resources/js/Shared/FileSystemBrowser.vue | 50 +++-- resources/js/Shared/ManageAuthor.vue | 78 ++++---- resources/js/Shared/ManageCitation.vue | 54 +++--- resources/js/Shared/Notification.vue | 4 +- resources/js/Shared/Pagination.vue | 6 +- resources/js/Shared/ProjectCard.vue | 4 +- resources/js/Shared/SelectOrcidId.vue | 2 +- resources/js/Shared/SpectraEditor.vue | 32 ++-- resources/js/Shared/SpectraViewer.vue | 21 +-- resources/js/Shared/StudyCard.vue | 2 +- resources/js/Shared/StudyCardPublic.vue | 11 +- resources/js/Shared/StudyInfo.vue | 4 +- resources/js/Shared/Submission.vue | 37 ++-- resources/js/Shared/Validation.vue | 44 ++--- 67 files changed, 1160 insertions(+), 653 deletions(-) create mode 100644 app/Console/Commands/ExtractSpectra.php create mode 100644 app/Console/Commands/SanitizeMolecules.php create mode 100644 docker/8.2/Dockerfile create mode 100644 docker/8.2/php.ini create mode 100644 docker/8.2/start-container create mode 100644 docker/8.2/supervisord.conf create mode 100644 docker/8.3/Dockerfile create mode 100644 docker/8.3/php.ini create mode 100644 docker/8.3/start-container create mode 100644 docker/8.3/supervisord.conf diff --git a/app/Console/Commands/ArchiveData.php b/app/Console/Commands/ArchiveData.php index 2b664a1e..1c093235 100644 --- a/app/Console/Commands/ArchiveData.php +++ b/app/Console/Commands/ArchiveData.php @@ -3,6 +3,7 @@ namespace App\Console\Commands; use App\Jobs\ArchiveProject; +use App\Jobs\ArchiveStudy; use App\Models\Project; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; @@ -35,7 +36,9 @@ public function handle() ])->get(); foreach ($projects as $project) { + // echo($project->identifier); ArchiveProject::dispatch($project); + ArchiveStudy::dispatch($project); } }); } diff --git a/app/Console/Commands/ExtractSpectra.php b/app/Console/Commands/ExtractSpectra.php new file mode 100644 index 00000000..9baba458 --- /dev/null +++ b/app/Console/Commands/ExtractSpectra.php @@ -0,0 +1,164 @@ +get(); + + foreach ($projects as $project) { + echo $project->identifier; + echo "\r\n"; + $studies = $project->studies; + foreach ($studies as $study) { + echo $study->identifier; + echo "\r\n"; + try { + if (! $study->has_nmrium) { + DB::transaction(function () use ($study) { + $download_url = $study->download_url; + if ($download_url) { + $nmrium_ = $this->processSpectra($download_url); + $parsedSpectra = $nmrium_['data']; + foreach ($parsedSpectra['spectra'] as $spectra) { + unset($spectra['data']); + unset($spectra['meta']); + unset($spectra['originalData']); + unset($spectra['originalInfo']); + } + + $version = $parsedSpectra['version']; + unset($parsedSpectra['version']); + + $nmriumJSON = [ + 'data' => $parsedSpectra, + 'version' => $version, + ]; + + $nmrium = $study->nmrium; + + if ($nmrium) { + $nmrium->nmrium_info = json_encode($nmriumJSON, JSON_UNESCAPED_UNICODE); + $nmrium->save(); + } else { + $nmrium = NMRium::create([ + 'nmrium_info' => json_encode($nmriumJSON, JSON_UNESCAPED_UNICODE), + ]); + $study->nmrium()->save($nmrium); + $study->has_nmrium = true; + $study->save(); + } + } + }); + } else { + $nmriumInfo = json_decode($study->nmrium['nmrium_info'], true); + if (count($nmriumInfo['data']['spectra']) == 0) { + echo '--MISSING SPECTRA INFO (NMRIUM JSON)--'; + echo "\r\n"; + } + } + } catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), "\n"; + } + + foreach ($study->datasets as $dataset) { + echo $dataset->identifier; + echo "\r\n"; + // if(!$dataset->has_nmrium){ + $nmriumInfo = json_decode($study->nmrium['nmrium_info'], true); + $_nmriumJSON = $nmriumInfo; + $fsObject = $dataset->fsObject; + $level = -($fsObject->level); + // echo $fsObject->path; + // echo("\r\n"); + // echo $study->name; + // echo("\r\n"); + $path = $study->name.'/'.$dataset->name; + foreach ($nmriumInfo['data']['spectra'] as $spectra) { + unset($_nmriumJSON['data']['spectra']); + $files = $spectra['sourceSelector']['files']; + // echo($path); + // echo("\r\n"); + $pathsMatch = true; + if ($files) { + foreach ($files as $file) { + echo $file; + echo "\r\n"; + if (! str_contains($file, $path)) { + $pathsMatch = false; + } + } + } + // echo($pathsMatch); + // echo("\r\n"); + if ($pathsMatch) { + $_nmriumJSON['data']['spectra'] = [$spectra]; + // dd($_nmriumJSON); + $_nmrium = $dataset->nmrium; + if ($_nmrium) { + $_nmrium->nmrium_info = json_encode($_nmriumJSON, JSON_UNESCAPED_UNICODE); + $dataset->has_nmrium = true; + $_nmrium->save(); + } else { + $_nmrium = NMRium::create([ + 'nmrium_info' => json_encode($_nmriumJSON, JSON_UNESCAPED_UNICODE), + ]); + $dataset->nmrium()->save($_nmrium); + $dataset->has_nmrium = true; + } + $experimentDetailsExists = array_key_exists('experiment', $spectra['info']); + if ($experimentDetailsExists) { + $experiment = $spectra['info']['experiment']; + $nucleus = $spectra['info']['nucleus']; + if (is_array($nucleus)) { + $nucleus = implode('-', $nucleus); + } + $dataset->type = $experiment.','.$nucleus; + } + $dataset->save(); + } + } + // } + } + } + } + } + + public function processSpectra($url) + { + $response = Http::timeout(300)->post('https://nodejsdev.nmrxiv.org/spectra-parser', [ + 'urls' => [$url], + 'snapshot' => false, + ]); + + return $response->json(); + } +} diff --git a/app/Console/Commands/ManageFiles.php b/app/Console/Commands/ManageFiles.php index a43e235b..c161514c 100644 --- a/app/Console/Commands/ManageFiles.php +++ b/app/Console/Commands/ManageFiles.php @@ -58,7 +58,7 @@ public function processFiles($path) $fsObject->save(); } } elseif ($item instanceof \League\Flysystem\DirectoryAttributes) { - echo $item->study_id; + // echo $item->study_id; } } } diff --git a/app/Console/Commands/SanitizeMolecules.php b/app/Console/Commands/SanitizeMolecules.php new file mode 100644 index 00000000..bbacd0d2 --- /dev/null +++ b/app/Console/Commands/SanitizeMolecules.php @@ -0,0 +1,51 @@ +get(); + + foreach ($molecules as $molecule) { + echo $molecule->id; + echo "\r\n"; + $molecule->MOL = ' + '.$molecule->MOL; + $standardisedMOL = $this->standardizeMolecule($molecule->MOL); + $molecule->CANONICAL_SMILES = $standardisedMOL['canonical_smiles']; + $molecule->STANDARD_INCHI = $standardisedMOL['inchi']; + $molecule->INCHI_KEY = $standardisedMOL['inchikey']; + $molecule->save(); + } + } + + protected function standardizeMolecule($mol) + { + $response = Http::post('https://dev.api.naturalproducts.net/latest/chem/standardize', $mol); + + return $response->json(); + } +} diff --git a/app/Console/Commands/SanitizeProjects.php b/app/Console/Commands/SanitizeProjects.php index 40cb5ecb..cf1c6b6f 100644 --- a/app/Console/Commands/SanitizeProjects.php +++ b/app/Console/Commands/SanitizeProjects.php @@ -57,8 +57,9 @@ public function cleanProjects() ['draft_id', null], ])->get(); - return DB::transaction(function () use ($projects) { - foreach ($projects as $project) { + foreach ($projects as $project) { + return DB::transaction(function () use ($project) { + $user_id = $project->owner->id; $team_id = $project->team_id; $id = Str::uuid(); @@ -107,8 +108,9 @@ public function cleanProjects() $dataset->save(); } } - } - }); + }); + + } } public function cleanDrafts() @@ -307,10 +309,20 @@ public function localise() public function updateFilesStatus() { - return DB::transaction(function () { - $fsObjects = FileSystemObject::all(); + $drafts = Draft::where('is_deleted', true)->get(); + foreach ($drafts as $draft) { + echo $draft->id; + echo "\r\n"; + echo 'Deleting associated files'; + FileSystemObject::where('draft_id', $draft->id)->delete(); + echo 'Deleting draft'; + echo "\r\n"; + Draft::where('id', $draft->id)->delete(); + } - foreach ($fsObjects as $fsObject) { + $fsObjects = FileSystemObject::whereNull('status')->get(); + foreach ($fsObjects as $fsObject) { + DB::transaction(function () use ($fsObject) { if ($fsObject->path) { $exists = Storage::disk(env('FILESYSTEM_DRIVER'))->exists($fsObject->path); if (! $exists) { @@ -320,8 +332,8 @@ public function updateFilesStatus() } $fsObject->save(); } - } - }); + }); + } } public function updateFilePaths() diff --git a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php index 16b1876a..05d1fa34 100644 --- a/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php +++ b/app/Http/Controllers/API/Schemas/Bioschema/BiochemaController.php @@ -290,15 +290,18 @@ public function getSample($study) */ public function getNMRiumInfo($dataset) { + $info = null; $nmrium = $dataset->nmrium; if (! $nmrium) { $study = $dataset->study; - $NMRiumInfo = json_decode($study->nmrium->nmrium_info); - foreach ($NMRiumInfo->data->spectra as $spectra) { - $fileSource = $spectra->sourceSelector->files[0]; - $fileName = pathinfo($fileSource); - if ($fileName['basename'] == $dataset->fsObject->name) { - $info = $spectra->info; + if ($study->nmrium) { + $NMRiumInfo = json_decode($study->nmrium->nmrium_info); + foreach ($NMRiumInfo->data->spectra as $spectra) { + $fileSource = $spectra->sourceSelector->files[0]; + $fileName = pathinfo($fileSource); + if ($fileName['basename'] == $dataset->fsObject->name) { + $info = $spectra->info; + } } } } else { @@ -306,45 +309,47 @@ public function getNMRiumInfo($dataset) $spectra = $NMRiumInfo->data->spectra[0]; $info = $spectra->info; } - $solvent = $info->solvent; - $nucleus = $info->nucleus; - if (is_string($nucleus)) { - $nucleus = [$nucleus]; - } - $dimension = $info->dimension; - $probeName = $info->probeName; - $experiment = $info->experiment; - $temperature = $info->temperature; - $baseFrequency = $info->baseFrequency; - $fieldStrength = $info->fieldStrength; - $numberOfScans = $info->numberOfScans; - $pulseSequence = $info->pulseSequence; - $spectralWidth = $info->spectralWidth; - $numberOfPoints = $info->numberOfPoints; - $relaxationTime = $info->relaxationTime; - - $solventProperty = $this->getPropertyValue('NMR solvent', 'NMR:1000330', $solvent, null); - $nucleusProperty = $this->getPropertyValue('acquisition nucleus', 'NMR:1400083', $nucleus, null); - $dimensionProperty = $this->getPropertyValue('NMR spectrum by dimensionality', 'NMR:1000117', $dimension, null); - $probeNameProperty = $this->getPropertyValue('NMR probe', 'OBI:0000516', $probeName, null); - $experimentProperty = $this->getPropertyValue('pulsed nuclear magnetic resonance spectroscopy', 'CHMO:0000613', $experiment, null); - $temperatureProperty = $this->getPropertyValue('Temperature', 'NCIT:C25206', $temperature, 'https://ontobee.org/ontology/UO?iri=http://purl.obolibrary.org/obo/UO_0000012'); - $baseFrequencyProperty = $this->getPropertyValue('irradiation frequency', 'NMR:1400026', $baseFrequency, 'http://purl.obolibrary.org/obo/UO_0000325'); - $fieldStrengthProperty = $this->getPropertyValue('magnetic field strength', 'MR:1400253', $fieldStrength, 'http://purl.obolibrary.org/obo/UO_0000228'); - $numberOfScansProperty = $this->getPropertyValue('number of scans', 'NMR:1400087', $numberOfScans, 'scans'); - $pulseSequenceProperty = $this->getPropertyValue('nuclear magnetic resonance pulse sequence', 'CHMO:0001841', $pulseSequence, null); - $spectralWidthProperty = $this->getPropertyValue('Spectral Width', 'NCIT:C156496', $spectralWidth, null); //todo: add unit - $numberOfPointsProperty = $this->getPropertyValue('number of data points', 'NMR:1000176', $numberOfPoints, 'points'); - $relaxationTimeProperty = $this->getPropertyValue('relaxation time measurement', 'FIX:0000202', $relaxationTime, 'http://purl.obolibrary.org/obo/UO_0000010'); - - $keywords = [$solvent, $dimension.'D', $experiment]; - foreach ($nucleus as $e) { - array_push($keywords, $e); - } - $variables = [$solventProperty, $nucleusProperty, $dimensionProperty, $probeNameProperty, - $experimentProperty, $temperatureProperty, $baseFrequencyProperty, $fieldStrengthProperty, $numberOfScansProperty, $pulseSequenceProperty, $spectralWidthProperty, $numberOfPointsProperty, $relaxationTimeProperty, ]; + if ($info) { + $solvent = $info->solvent; + $nucleus = $info->nucleus; + if (is_string($nucleus)) { + $nucleus = [$nucleus]; + } + $dimension = $info->dimension; + $probeName = $info->probeName; + $experiment = $info->experiment; + $temperature = $info->temperature; + $baseFrequency = $info->baseFrequency; + $fieldStrength = $info->fieldStrength; + $numberOfScans = $info->numberOfScans; + $pulseSequence = $info->pulseSequence; + $spectralWidth = $info->spectralWidth; + $numberOfPoints = $info->numberOfPoints; + $relaxationTime = $info->relaxationTime; + + $solventProperty = $this->getPropertyValue('NMR solvent', 'NMR:1000330', $solvent, null); + $nucleusProperty = $this->getPropertyValue('acquisition nucleus', 'NMR:1400083', $nucleus, null); + $dimensionProperty = $this->getPropertyValue('NMR spectrum by dimensionality', 'NMR:1000117', $dimension, null); + $probeNameProperty = $this->getPropertyValue('NMR probe', 'OBI:0000516', $probeName, null); + $experimentProperty = $this->getPropertyValue('pulsed nuclear magnetic resonance spectroscopy', 'CHMO:0000613', $experiment, null); + $temperatureProperty = $this->getPropertyValue('Temperature', 'NCIT:C25206', $temperature, 'https://ontobee.org/ontology/UO?iri=http://purl.obolibrary.org/obo/UO_0000012'); + $baseFrequencyProperty = $this->getPropertyValue('irradiation frequency', 'NMR:1400026', $baseFrequency, 'http://purl.obolibrary.org/obo/UO_0000325'); + $fieldStrengthProperty = $this->getPropertyValue('magnetic field strength', 'MR:1400253', $fieldStrength, 'http://purl.obolibrary.org/obo/UO_0000228'); + $numberOfScansProperty = $this->getPropertyValue('number of scans', 'NMR:1400087', $numberOfScans, 'scans'); + $pulseSequenceProperty = $this->getPropertyValue('nuclear magnetic resonance pulse sequence', 'CHMO:0001841', $pulseSequence, null); + $spectralWidthProperty = $this->getPropertyValue('Spectral Width', 'NCIT:C156496', $spectralWidth, null); //todo: add unit + $numberOfPointsProperty = $this->getPropertyValue('number of data points', 'NMR:1000176', $numberOfPoints, 'points'); + $relaxationTimeProperty = $this->getPropertyValue('relaxation time measurement', 'FIX:0000202', $relaxationTime, 'http://purl.obolibrary.org/obo/UO_0000010'); + + $keywords = [$solvent, $dimension.'D', $experiment]; + foreach ($nucleus as $e) { + array_push($keywords, $e); + } + $variables = [$solventProperty, $nucleusProperty, $dimensionProperty, $probeNameProperty, + $experimentProperty, $temperatureProperty, $baseFrequencyProperty, $fieldStrengthProperty, $numberOfScansProperty, $pulseSequenceProperty, $spectralWidthProperty, $numberOfPointsProperty, $relaxationTimeProperty, ]; - return [$keywords, $variables, $experiment]; + return [$keywords, $variables, $experiment]; + } } /** @@ -441,25 +446,28 @@ public function preparePublisher() */ public function datasetLite($dataset) { - $prefix = $dataset->study->project->name.':'.$dataset->study->name.'.'; - $datasetSchema = Schema::Dataset(); - $datasetSchema['@id'] = $dataset->doi; - $datasetSchema['dct:conformsTo'] = $this->conformsTo(['https://bioschemas.org/profiles/Dataset/1.0-RELEASE', 'https://isa-specs.readthedocs.io/en/latest/isamodel.html#assay']); - $datasetSchema->name($prefix.$this->getNMRiumInfo($dataset)[2]); - $datasetSchema->description($dataset->description); - $datasetSchema->keywords($this->getNMRiumInfo($dataset)[0]); - $datasetSchema->license($dataset->study->license->url); - $datasetSchema->url(env('APP_URL').'/'.explode(':', $dataset->identifier ? $dataset->identifier : ':')[1]); - $datasetSchema->dateCreated($dataset->created_at); - $datasetSchema->dateModified($dataset->updated_at); - $datasetSchema->datePublished($dataset->release_date); - $datasetSchema->distribution($this->getDistribution($dataset)); - $datasetSchema->includedInDataCatalog($this->DataCatalogLite()); - $datasetSchema->measurementTechnique(env('MEASUREMENT_TECHNIQUE')); - $datasetSchema->variableMeasured($this->getNMRiumInfo($dataset)[1]); - $datasetSchema->isAccessibleForFree(true); - - return $datasetSchema; + $nmriumInfo = $this->getNMRiumInfo($dataset); + if ($nmriumInfo) { + $prefix = $dataset->study->project->name.':'.$dataset->study->name.'.'; + $datasetSchema = Schema::Dataset(); + $datasetSchema['@id'] = $dataset->doi; + $datasetSchema['dct:conformsTo'] = $this->conformsTo(['https://bioschemas.org/profiles/Dataset/1.0-RELEASE', 'https://isa-specs.readthedocs.io/en/latest/isamodel.html#assay']); + $datasetSchema->name($prefix.$nmriumInfo[2]); + $datasetSchema->description($dataset->description); + $datasetSchema->keywords($nmriumInfo[0]); + $datasetSchema->license($dataset->study->license->url); + $datasetSchema->url(env('APP_URL').'/'.explode(':', $dataset->identifier ? $dataset->identifier : ':')[1]); + $datasetSchema->dateCreated($dataset->created_at); + $datasetSchema->dateModified($dataset->updated_at); + $datasetSchema->datePublished($dataset->release_date); + $datasetSchema->distribution($this->getDistribution($dataset)); + $datasetSchema->includedInDataCatalog($this->DataCatalogLite()); + $datasetSchema->measurementTechnique(env('MEASUREMENT_TECHNIQUE')); + $datasetSchema->variableMeasured($nmriumInfo[1]); + $datasetSchema->isAccessibleForFree(true); + + return $datasetSchema; + } } public function dataset($dataset) diff --git a/app/Http/Controllers/StudyController.php b/app/Http/Controllers/StudyController.php index 74a7bcf3..8253e010 100644 --- a/app/Http/Controllers/StudyController.php +++ b/app/Http/Controllers/StudyController.php @@ -185,12 +185,10 @@ public function nmriumVersions(Request $request, Study $study) public function nmriumInfo(Request $request, Study $study) { - // $version = $request->get('version'); // $spectra = $request->get('spectra'); // $molecules = $nmriumInfo['data']['molecules']; // $molecularInfo = $molecules; - if ($study) { $user = Auth::user(); $data = $request->all(); @@ -208,12 +206,11 @@ public function nmriumInfo(Request $request, Study $study) $study->has_nmrium = true; } $study->save(); - $_nmriumJSON = $nmriumInfo; foreach ($study->datasets as $dataset) { $fsObject = $dataset->fsObject; $level = -($fsObject->level + 1); - echo $fsObject->path; + // echo $fsObject->path; $path = implode('/', array_slice(explode('/', $fsObject->path), $level)); foreach ($nmriumInfo['data']['spectra'] as $spectra) { unset($_nmriumJSON['data']['spectra']); @@ -240,6 +237,15 @@ public function nmriumInfo(Request $request, Study $study) $dataset->nmrium()->save($_nmrium); $dataset->has_nmrium = true; } + $experimentDetailsExists = array_key_exists('experiment', $spectra['info']); + if ($experimentDetailsExists) { + $experiment = $spectra['info']['experiment']; + $nucleus = $spectra['info']['nucleus']; + if (is_array($nucleus)) { + $nucleus = implode('-', $nucleus); + } + $dataset->type = $experiment.','.$nucleus; + } $dataset->save(); } } diff --git a/app/Http/Resources/ProjectResource.php b/app/Http/Resources/ProjectResource.php index 1253e4be..20be35f2 100644 --- a/app/Http/Resources/ProjectResource.php +++ b/app/Http/Resources/ProjectResource.php @@ -45,6 +45,7 @@ public function toArray($request) 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, 'download_url' => $this->download_url, + 'species' => json_decode($this->species), 'stats' => [ 'likes' => $this->likesCount(), ], diff --git a/app/Jobs/ArchiveStudy.php b/app/Jobs/ArchiveStudy.php index 6509b435..5a649f72 100644 --- a/app/Jobs/ArchiveStudy.php +++ b/app/Jobs/ArchiveStudy.php @@ -5,7 +5,6 @@ use App\Models\Project; use Aws\S3\S3Client; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; @@ -14,7 +13,7 @@ use Illuminate\Support\Facades\Storage; use ZipStream; -class ArchiveStudy implements ShouldBeUnique, ShouldQueue +class ArchiveStudy implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; diff --git a/composer.json b/composer.json index fb0c6f4b..3597070d 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "mpociot/versionable": "^4.3", "nfdi4chem/orcid": "master", "owen-it/laravel-auditing": "^13.5.1", - "predis/predis": "^1.1", + "predis/predis": "^2.2", "spatie/laravel-backup": "^8.3", "spatie/laravel-cookie-consent": "^3.2.1", "spatie/laravel-permission": "^5.1", diff --git a/composer.lock b/composer.lock index da79c8ac..9833064d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "44acb107fe3def96f802323935b13250", + "content-hash": "dcdcdd02f0b800159dd5575022b9e523", "packages": [ { "name": "aws/aws-crt-php", @@ -4928,27 +4928,28 @@ }, { "name": "predis/predis", - "version": "v1.1.10", + "version": "v2.2.2", "source": { "type": "git", "url": "https://github.com/predis/predis.git", - "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e" + "reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/predis/predis/zipball/a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e", - "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e", + "url": "https://api.github.com/repos/predis/predis/zipball/b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1", + "reference": "b1d3255ed9ad4d7254f9f9bba386c99f4bb983d1", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "friendsofphp/php-cs-fixer": "^3.3", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ~9.4.4" }, "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + "ext-relay": "Faster connection with in-memory caching (>=0.6.2)" }, "type": "library", "autoload": { @@ -4961,19 +4962,13 @@ "MIT" ], "authors": [ - { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net", - "role": "Creator & Maintainer" - }, { "name": "Till Krüss", "homepage": "https://till.im", "role": "Maintainer" } ], - "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "description": "A flexible and feature-complete Redis client for PHP.", "homepage": "http://github.com/predis/predis", "keywords": [ "nosql", @@ -4982,7 +4977,7 @@ ], "support": { "issues": "https://github.com/predis/predis/issues", - "source": "https://github.com/predis/predis/tree/v1.1.10" + "source": "https://github.com/predis/predis/tree/v2.2.2" }, "funding": [ { @@ -4990,7 +4985,7 @@ "type": "github" } ], - "time": "2022-01-05T17:46:08+00:00" + "time": "2023-09-13T16:42:03+00:00" }, { "name": "psr/cache", @@ -9930,27 +9925,27 @@ }, { "name": "laravel/sail", - "version": "v1.23.4", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "cfa1ad579349110a87f9412eb65ecba94d682ac2" + "reference": "c60fe037004e272efd0d81f416ed2bfc623d70b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/cfa1ad579349110a87f9412eb65ecba94d682ac2", - "reference": "cfa1ad579349110a87f9412eb65ecba94d682ac2", + "url": "https://api.github.com/repos/laravel/sail/zipball/c60fe037004e272efd0d81f416ed2bfc623d70b4", + "reference": "c60fe037004e272efd0d81f416ed2bfc623d70b4", "shasum": "" }, "require": { - "illuminate/console": "^8.0|^9.0|^10.0", - "illuminate/contracts": "^8.0|^9.0|^10.0", - "illuminate/support": "^8.0|^9.0|^10.0", + "illuminate/console": "^9.0|^10.0|^11.0", + "illuminate/contracts": "^9.0|^10.0|^11.0", + "illuminate/support": "^9.0|^10.0|^11.0", "php": "^8.0", - "symfony/yaml": "^6.0" + "symfony/yaml": "^6.0|^7.0" }, "require-dev": { - "orchestra/testbench": "^6.0|^7.0|^8.0", + "orchestra/testbench": "^7.0|^8.0|^9.0", "phpstan/phpstan": "^1.10" }, "bin": [ @@ -9991,7 +9986,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2023-08-17T12:49:32+00:00" + "time": "2023-10-18T13:57:15+00:00" }, { "name": "laravel/telescope", diff --git a/database/migrations/2022_09_16_115525_create_nmrium_table.php b/database/migrations/2022_09_16_115525_create_nmrium_table.php index 5f54e12f..31a0f539 100644 --- a/database/migrations/2022_09_16_115525_create_nmrium_table.php +++ b/database/migrations/2022_09_16_115525_create_nmrium_table.php @@ -20,10 +20,10 @@ public function up() $table->timestamps(); }); - Schema::table('datasets', function (Blueprint $table) { - $table->dropColumn('nmrium_info'); - $table->boolean('has_nmrium')->nullable()->default(0); - }); + // Schema::table('datasets', function (Blueprint $table) { + // $table->dropColumn('nmrium_info'); + // $table->boolean('has_nmrium')->nullable()->default(0); + // }); } /** diff --git a/docker-compose.yml b/docker-compose.yml index 6194e60b..32e79cdc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: "3" services: laravel.test: build: - context: ./docker/8.1 + context: ./docker/8.2 dockerfile: Dockerfile args: WWWGROUP: "${WWWGROUP}" @@ -26,11 +26,12 @@ services: - selenium # - minio pgsql: - image: "postgres:13" + image: "informaticsmatters/rdkit-cartridge-debian:latest" + pull_policy: always ports: - "${FORWARD_DB_PORT:-5432}:5432" environment: - PGPASSWORD: "${DB_PASSWORD:-secret}" + PG_VERSION: "${DB_VERSION}" POSTGRES_DB: "${DB_DATABASE}" POSTGRES_USER: "${DB_USERNAME}" POSTGRES_PASSWORD: "${DB_PASSWORD:-secret}" @@ -89,6 +90,8 @@ services: - "sailmeilisearch:/data.ms" networks: - sail + environment: + MEILI_MASTER_KEY: "${MEILISEARCH_PRIVATEKEY}" healthcheck: test: [ diff --git a/docker/8.2/Dockerfile b/docker/8.2/Dockerfile new file mode 100644 index 00000000..414301f1 --- /dev/null +++ b/docker/8.2/Dockerfile @@ -0,0 +1,63 @@ +FROM ubuntu:22.04 + +LABEL maintainer="Taylor Otwell" + +ARG WWWGROUP +ARG NODE_VERSION=20 +ARG POSTGRES_VERSION=15 + +WORKDIR /var/www/html + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ=UTC + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +RUN apt-get update \ + && mkdir -p /etc/apt/keyrings \ + && apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils librsvg2-bin fswatch \ + && curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /etc/apt/keyrings/ppa_ondrej_php.gpg > /dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ + && apt-get update \ + && apt-get install -y php8.2-cli php8.2-dev \ + php8.2-pgsql php8.2-sqlite3 php8.2-gd php8.2-imagick \ + php8.2-curl \ + php8.2-imap php8.2-mysql php8.2-mbstring \ + php8.2-xml php8.2-zip php8.2-bcmath php8.2-soap \ + php8.2-intl php8.2-readline \ + php8.2-ldap \ + php8.2-msgpack php8.2-igbinary php8.2-redis php8.2-swoole \ + php8.2-memcached php8.2-pcov php8.2-xdebug \ + && curl -sLS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \ + && apt-get update \ + && apt-get install -y nodejs \ + && npm install -g npm \ + && npm install -g pnpm \ + && npm install -g bun \ + && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/keyrings/yarn.gpg >/dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \ + && curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/keyrings/pgdg.gpg >/dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ + && apt-get update \ + && apt-get install -y yarn \ + && apt-get install -y mysql-client \ + && apt-get install -y postgresql-client-$POSTGRES_VERSION \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2 + +RUN groupadd --force -g $WWWGROUP sail +RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail + +COPY start-container /usr/local/bin/start-container +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini +RUN chmod +x /usr/local/bin/start-container + +EXPOSE 8000 + +ENTRYPOINT ["start-container"] diff --git a/docker/8.2/php.ini b/docker/8.2/php.ini new file mode 100644 index 00000000..39dcbcac --- /dev/null +++ b/docker/8.2/php.ini @@ -0,0 +1,7 @@ +[PHP] +post_max_size = 100M +upload_max_filesize = 100M +variables_order = EGPCS + +[opcache] +opcache.enable_cli=1 diff --git a/docker/8.2/start-container b/docker/8.2/start-container new file mode 100644 index 00000000..b8643990 --- /dev/null +++ b/docker/8.2/start-container @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +if [ ! -z "$WWWUSER" ]; then + usermod -u $WWWUSER sail +fi + +if [ ! -d /.composer ]; then + mkdir /.composer +fi + +chmod -R ugo+rw /.composer + +if [ $# -gt 0 ]; then + exec gosu $WWWUSER "$@" +else + exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf +fi diff --git a/docker/8.2/supervisord.conf b/docker/8.2/supervisord.conf new file mode 100644 index 00000000..9d284795 --- /dev/null +++ b/docker/8.2/supervisord.conf @@ -0,0 +1,14 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:php] +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80 +user=sail +environment=LARAVEL_SAIL="1" +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/docker/8.3/Dockerfile b/docker/8.3/Dockerfile new file mode 100644 index 00000000..aa79dfb9 --- /dev/null +++ b/docker/8.3/Dockerfile @@ -0,0 +1,64 @@ +FROM ubuntu:22.04 + +LABEL maintainer="Taylor Otwell" + +ARG WWWGROUP +ARG NODE_VERSION=20 +ARG POSTGRES_VERSION=15 + +WORKDIR /var/www/html + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ=UTC + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +RUN apt-get update \ + && mkdir -p /etc/apt/keyrings \ + && apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils librsvg2-bin fswatch \ + && curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /etc/apt/keyrings/ppa_ondrej_php.gpg > /dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \ + && apt-get update \ + && apt-get install -y php8.3-cli php8.3-dev \ + php8.3-pgsql php8.3-sqlite3 php8.3-gd \ + php8.3-curl \ + php8.3-imap php8.3-mysql php8.3-mbstring \ + php8.3-xml php8.3-zip php8.3-bcmath php8.3-soap \ + php8.3-intl php8.3-readline \ + php8.3-ldap \ + # php8.3-msgpack php8.3-igbinary php8.3-redis php8.3-swoole \ + # php8.3-memcached php8.3-pcov php8.3-xdebug \ + # php8.3-imagick \ + && curl -sLS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \ + && apt-get update \ + && apt-get install -y nodejs \ + && npm install -g npm \ + && npm install -g pnpm \ + && npm install -g bun \ + && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/keyrings/yarn.gpg >/dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \ + && curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/keyrings/pgdg.gpg >/dev/null \ + && echo "deb [signed-by=/etc/apt/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ + && apt-get update \ + && apt-get install -y yarn \ + && apt-get install -y mysql-client \ + && apt-get install -y postgresql-client-$POSTGRES_VERSION \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.3 + +RUN groupadd --force -g $WWWGROUP sail +RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail + +COPY start-container /usr/local/bin/start-container +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY php.ini /etc/php/8.3/cli/conf.d/99-sail.ini +RUN chmod +x /usr/local/bin/start-container + +EXPOSE 8000 + +ENTRYPOINT ["start-container"] diff --git a/docker/8.3/php.ini b/docker/8.3/php.ini new file mode 100644 index 00000000..39dcbcac --- /dev/null +++ b/docker/8.3/php.ini @@ -0,0 +1,7 @@ +[PHP] +post_max_size = 100M +upload_max_filesize = 100M +variables_order = EGPCS + +[opcache] +opcache.enable_cli=1 diff --git a/docker/8.3/start-container b/docker/8.3/start-container new file mode 100644 index 00000000..b8643990 --- /dev/null +++ b/docker/8.3/start-container @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +if [ ! -z "$WWWUSER" ]; then + usermod -u $WWWUSER sail +fi + +if [ ! -d /.composer ]; then + mkdir /.composer +fi + +chmod -R ugo+rw /.composer + +if [ $# -gt 0 ]; then + exec gosu $WWWUSER "$@" +else + exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf +fi diff --git a/docker/8.3/supervisord.conf b/docker/8.3/supervisord.conf new file mode 100644 index 00000000..9d284795 --- /dev/null +++ b/docker/8.3/supervisord.conf @@ -0,0 +1,14 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:php] +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80 +user=sail +environment=LARAVEL_SAIL="1" +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/resources/js/Layouts/AppLayout.vue b/resources/js/Layouts/AppLayout.vue index 6ee9878e..c46e6c7a 100644 --- a/resources/js/Layouts/AppLayout.vue +++ b/resources/js/Layouts/AppLayout.vue @@ -198,14 +198,14 @@ :class="[item.auth ? 'border-t' : '']" >
    {{ item.prefix }}
    - +
    @@ -219,7 +219,7 @@
    - +
    ORCID logo
    - +
    @@ -188,8 +188,8 @@ @@ -229,6 +229,12 @@ export default { SelectOrcidId, ref, }, + setup() { + const selectOrcidIdElement = ref(null); + return { + selectOrcidIdElement, + }; + }, data() { return { @@ -249,12 +255,6 @@ export default { error: {}, }; }, - setup() { - const selectOrcidIdElement = ref(null); - return { - selectOrcidIdElement, - }; - }, methods: { findOrcidID() { diff --git a/resources/js/Pages/Console/Users/Partials/UserProfile.vue b/resources/js/Pages/Console/Users/Partials/UserProfile.vue index ca89178d..a7e1b279 100644 --- a/resources/js/Pages/Console/Users/Partials/UserProfile.vue +++ b/resources/js/Pages/Console/Users/Partials/UserProfile.vue @@ -153,7 +153,7 @@ >
    - +
    diff --git a/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue b/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue index c04e50aa..c31f8098 100644 --- a/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue +++ b/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue @@ -160,7 +160,7 @@ >
    - +
    @@ -196,8 +196,8 @@
    @@ -226,6 +226,12 @@ export default { }, props: ["user"], + setup() { + const selectOrcidIdElement = ref(null); + return { + selectOrcidIdElement, + }; + }, data() { return { @@ -243,12 +249,6 @@ export default { photoPreview: null, }; }, - setup() { - const selectOrcidIdElement = ref(null); - return { - selectOrcidIdElement, - }; - }, methods: { findOrcidID() { diff --git a/resources/js/Pages/Project/Index.vue b/resources/js/Pages/Project/Index.vue index 193a31c4..e4c55c7f 100644 --- a/resources/js/Pages/Project/Index.vue +++ b/resources/js/Pages/Project/Index.vue @@ -166,8 +166,8 @@ class="flex justify-between items-center bg-white shadow-md border rounded-lg px-6 py-6" >
    @@ -263,9 +263,9 @@ >

    {{ tag.name["en"] }} diff --git a/resources/js/Pages/Project/Partials/Details.vue b/resources/js/Pages/Project/Partials/Details.vue index 9593e86e..8fae5d8e 100644 --- a/resources/js/Pages/Project/Partials/Details.vue +++ b/resources/js/Pages/Project/Partials/Details.vue @@ -338,12 +338,12 @@

    {{ option.name }} @@ -102,7 +102,6 @@ class="relative z-0 inline-flex shadow-sm rounded-md" >