From f47e4dea07da8f4a6b3220eb173610ba14895ea9 Mon Sep 17 00:00:00 2001
From: Sagar
Date: Wed, 19 Nov 2025 11:26:16 +0100
Subject: [PATCH 01/11] fix: the cms api base url is now accessed through the
config.
---
.../RelationManagers/EntriesRelationManager.php | 8 ++++----
app/Filament/Dashboard/Resources/MoleculeResource.php | 2 +-
.../RelationManagers/MoleculesRelationManager.php | 2 +-
.../RelationManagers/RelatedRelationManager.php | 2 +-
.../RelationManagers/MoleculesRelationManager.php | 2 +-
.../RelationManagers/EntriesRelationManager.php | 8 ++++----
.../RelationManagers/MoleculesRelationManager.php | 2 +-
app/Livewire/MoleculeDepict2d.php | 4 ++--
config/services.php | 4 ++++
resources/views/molecule.blade.php | 4 ++--
10 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php b/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
index 9cef396f..b3e5e5e4 100644
--- a/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
@@ -99,21 +99,21 @@ public function infolist(Infolist $infolist): Infolist
])
->schema([
ImageEntry::make('parent_canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('standardized_canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
@@ -133,7 +133,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource.php b/app/Filament/Dashboard/Resources/MoleculeResource.php
index 3c7041a6..11894e10 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource.php
@@ -90,7 +90,7 @@ public static function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
index b297563e..b47e153b 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
@@ -26,7 +26,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
index c890aa7d..ae132fdc 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
@@ -26,7 +26,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
index 2052b6c5..a9359be7 100644
--- a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
@@ -40,7 +40,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
index ce7075ec..291a988e 100644
--- a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
@@ -94,21 +94,21 @@ public function infolist(Infolist $infolist): Infolist
])
->schema([
ImageEntry::make('parent_canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('standardized_canonical_smiles')->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
@@ -128,7 +128,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
index 27247b19..107cda4a 100644
--- a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
@@ -35,7 +35,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
})
->width(200)
->height(200)
diff --git a/app/Livewire/MoleculeDepict2d.php b/app/Livewire/MoleculeDepict2d.php
index 76b5666a..bc5d1478 100644
--- a/app/Livewire/MoleculeDepict2d.php
+++ b/app/Livewire/MoleculeDepict2d.php
@@ -28,13 +28,13 @@ class MoleculeDepict2d extends Component
#[Computed]
public function source()
{
- return env('CM_PUBLIC_API').'depict/2D?smiles='.urlencode($this->smiles).'&height='.$this->height.'&width='.$this->width.'&toolkit='.$this->toolkit.'&CIP='.$this->CIP;
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($this->smiles).'&height='.$this->height.'&width='.$this->width.'&toolkit='.$this->toolkit.'&CIP='.$this->CIP;
}
#[Computed]
public function preview()
{
- return env('CM_PUBLIC_API').'depict/2D?smiles='.urlencode($this->smiles);
+ return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($this->smiles);
}
public function downloadMolFile($toolkit)
diff --git a/config/services.php b/config/services.php
index ad1a400b..f1158ed6 100644
--- a/config/services.php
+++ b/config/services.php
@@ -49,4 +49,8 @@
'redirect' => env('NFDI_REDIRECT_URL'),
],
+ 'cheminf' => [
+ 'api_url' => env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/'),
+ ],
+
];
diff --git a/resources/views/molecule.blade.php b/resources/views/molecule.blade.php
index 058806a6..637ab628 100644
--- a/resources/views/molecule.blade.php
+++ b/resources/views/molecule.blade.php
@@ -34,7 +34,7 @@
+ content="{{ config('services.cheminf.api_url') . 'depict/2D?smiles=' . urlencode($molecule->canonical_smiles) . '&height=630&width=1200&toolkit=cdk' ?? asset('img/coconut-og-image.png') }}">
@@ -56,7 +56,7 @@
and found in the collection{{ $molecule->collections->count() > 1 ? 's' : '' }}:
{{ implode(', ', $molecule->collections->pluck('title')->toArray()) }} @endif">
+ content="{{ config('services.cheminf.api_url') . 'depict/2D?smiles=' . urlencode($molecule->canonical_smiles) . '&height=630&width=1200&toolkit=cdk' ?? asset('img/coconut-og-image.png') }}">
From 1a389dd56332b2db38d15ed7db972a549373dbff Mon Sep 17 00:00:00 2001
From: Sagar
Date: Wed, 19 Nov 2025 11:27:06 +0100
Subject: [PATCH 02/11] fix: changed the trigger branch in the workflow.
---
.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 d25cf0c8..7525fa1c 100644
--- a/.github/workflows/dev-build.yml
+++ b/.github/workflows/dev-build.yml
@@ -13,7 +13,7 @@ name : Development - Build COCONUT image and push to Docker Hub
on:
push:
- branches: [development]
+ branches: [fix-access-env-variables]
env:
REPOSITORY_NAME: coconut
From 713b54c59697732ed6f855222f71e0bd828a5cc3 Mon Sep 17 00:00:00 2001
From: Sagar
Date: Wed, 19 Nov 2025 13:11:40 +0100
Subject: [PATCH 03/11] fix: audit vulnerability.
---
composer.lock | 95 +++++++++++++++++++++++++++++++++------------------
1 file changed, 62 insertions(+), 33 deletions(-)
diff --git a/composer.lock b/composer.lock
index 340106f4..3b49658b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -11797,16 +11797,16 @@
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.1",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
- "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
@@ -11819,7 +11819,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.5-dev"
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -11844,7 +11844,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -11860,7 +11860,7 @@
"type": "tidelift"
}
],
- "time": "2024-09-25T14:20:29+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/error-handler",
@@ -12228,16 +12228,16 @@
},
{
"name": "symfony/http-foundation",
- "version": "v7.2.6",
+ "version": "v7.3.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "6023ec7607254c87c5e69fb3558255aca440d72b"
+ "reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6023ec7607254c87c5e69fb3558255aca440d72b",
- "reference": "6023ec7607254c87c5e69fb3558255aca440d72b",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4",
+ "reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4",
"shasum": ""
},
"require": {
@@ -12254,6 +12254,7 @@
"doctrine/dbal": "^3.6|^4",
"predis/predis": "^1.1|^2.0",
"symfony/cache": "^6.4.12|^7.1.5",
+ "symfony/clock": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/expression-language": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
@@ -12286,7 +12287,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v7.2.6"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.7"
},
"funding": [
{
@@ -12297,12 +12298,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-09T08:14:01+00:00"
+ "time": "2025-11-08T16:41:12+00:00"
},
{
"name": "symfony/http-kernel",
@@ -12500,16 +12505,16 @@
},
{
"name": "symfony/mime",
- "version": "v7.2.6",
+ "version": "v7.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "706e65c72d402539a072d0d6ad105fff6c161ef1"
+ "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/706e65c72d402539a072d0d6ad105fff6c161ef1",
- "reference": "706e65c72d402539a072d0d6ad105fff6c161ef1",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35",
+ "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35",
"shasum": ""
},
"require": {
@@ -12564,7 +12569,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v7.2.6"
+ "source": "https://github.com/symfony/mime/tree/v7.3.4"
},
"funding": [
{
@@ -12575,12 +12580,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-27T13:34:41+00:00"
+ "time": "2025-09-16T08:38:17+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -12741,7 +12750,7 @@
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
@@ -12804,7 +12813,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
},
"funding": [
{
@@ -12815,6 +12824,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -12824,7 +12837,7 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -12885,7 +12898,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -12896,6 +12909,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -12905,7 +12922,7 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -12966,7 +12983,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -12977,6 +12994,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -12986,7 +13007,7 @@
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
@@ -13046,7 +13067,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
},
"funding": [
{
@@ -13057,6 +13078,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -13066,16 +13091,16 @@
},
{
"name": "symfony/polyfill-php83",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491"
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"shasum": ""
},
"require": {
@@ -13122,7 +13147,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
},
"funding": [
{
@@ -13133,12 +13158,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-07-08T02:45:35+00:00"
},
{
"name": "symfony/polyfill-uuid",
From f29c8b1a3e79536122c8a19efe7d8667ef58684c Mon Sep 17 00:00:00 2001
From: Sagar
Date: Wed, 19 Nov 2025 14:19:59 +0100
Subject: [PATCH 04/11] chore: refactored to use env variables to be served
from config.
---
app/Console/Commands/GenerateCoordinates.php | 2 +-
.../FetchCitationMetadataAuto.php | 6 +++---
.../SampleLocationsRelationManager.php | 2 +-
app/Filament/Dashboard/Resources/ReportResource.php | 2 +-
app/Helper.php | 6 +++---
app/Jobs/ImportEntry.php | 6 +++---
app/Jobs/ImportEntryAuto.php | 6 +++---
app/Jobs/ProcessEntry.php | 2 +-
app/Jobs/ProcessEntryBatch.php | 2 +-
app/Models/Molecule.php | 2 +-
.../PostPublishJobFailedNotification.php | 2 +-
app/Notifications/PrePublishJobFailedNotification.php | 2 +-
app/Notifications/ReportAssignedNotification.php | 2 +-
app/Notifications/ReportStatusChangedNotification.php | 4 ++--
app/Notifications/ReportSubmittedNotification.php | 4 ++--
config/filesystems.php | 2 +-
config/services.php | 11 +++++++++++
resources/views/components/tawk-chat.blade.php | 2 +-
.../views/forms/components/organisms-table.blade.php | 2 +-
19 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/app/Console/Commands/GenerateCoordinates.php b/app/Console/Commands/GenerateCoordinates.php
index a0a55489..51c25fb9 100644
--- a/app/Console/Commands/GenerateCoordinates.php
+++ b/app/Console/Commands/GenerateCoordinates.php
@@ -71,7 +71,7 @@ public function handle()
$canonical_smiles = $mol->canonical_smiles;
// Build endpoints.
- $apiUrl = env('API_URL', 'https://api.cheminf.studio/latest/');
+ $apiUrl = config('services.cheminf.internal_api_url');
$d2Endpoint = $apiUrl.'convert/mol2D?smiles='.urlencode($canonical_smiles).'&toolkit=rdkit';
$d3Endpoint = $apiUrl.'convert/mol3D?smiles='.urlencode($canonical_smiles).'&toolkit=rdkit';
diff --git a/app/Console/Commands/SubmissionsAutoProcess/FetchCitationMetadataAuto.php b/app/Console/Commands/SubmissionsAutoProcess/FetchCitationMetadataAuto.php
index dd5ead55..3d8fc55a 100644
--- a/app/Console/Commands/SubmissionsAutoProcess/FetchCitationMetadataAuto.php
+++ b/app/Console/Commands/SubmissionsAutoProcess/FetchCitationMetadataAuto.php
@@ -146,7 +146,7 @@ private function fetchCitationFromAPIs($doi): ?array
$citationResponse = null;
// Try EuropePMC first
- $europemcUrl = env('EUROPEPMC_WS_API');
+ $europemcUrl = config('services.citation.europepmc_url');
$europemcParams = [
'query' => 'DOI:'.$doi,
'format' => 'json',
@@ -161,14 +161,14 @@ private function fetchCitationFromAPIs($doi): ?array
$citationResponse = $this->formatCitationResponse($europemcResponse['resultList']['result'][0], 'europemc');
} else {
// Try CrossRef
- $crossrefUrl = env('CROSSREF_WS_API').$doi;
+ $crossrefUrl = config('services.citation.crossref_url').$doi;
$response = $this->makeRequest($crossrefUrl);
$crossrefResponse = ($response && method_exists($response, 'json')) ? $response->json() : null;
if ($crossrefResponse && isset($crossrefResponse['message'])) {
$citationResponse = $this->formatCitationResponse($crossrefResponse['message'], 'crossref');
} else {
// Try DataCite as last resort
- $dataciteUrl = env('DATACITE_WS_API').$doi;
+ $dataciteUrl = config('services.citation.datacite_url').$doi;
$response = $this->makeRequest($dataciteUrl);
$dataciteResponse = ($response && method_exists($response, 'json')) ? $response->json() : null;
if ($dataciteResponse && isset($dataciteResponse['data'])) {
diff --git a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/SampleLocationsRelationManager.php b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/SampleLocationsRelationManager.php
index 159a9fd9..454c0438 100644
--- a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/SampleLocationsRelationManager.php
+++ b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/SampleLocationsRelationManager.php
@@ -38,7 +38,7 @@ public function table(Table $table): Table
])
->actions([
Tables\Actions\Action::make('edit')
- ->url(fn (SampleLocation $record) => env('APP_URL').'/dashboard/sample-locations/'.$record->id.'/edit')
+ ->url(fn (SampleLocation $record) => config('app.url').'/dashboard/sample-locations/'.$record->id.'/edit')
// ->color('info')
->icon('heroicon-m-pencil-square'),
// Tables\Actions\EditAction::make(),
diff --git a/app/Filament/Dashboard/Resources/ReportResource.php b/app/Filament/Dashboard/Resources/ReportResource.php
index 12b8be91..daeddcf3 100644
--- a/app/Filament/Dashboard/Resources/ReportResource.php
+++ b/app/Filament/Dashboard/Resources/ReportResource.php
@@ -228,7 +228,7 @@ public static function form(Form $form): Form
}),
Action::make('viewCompoundPage')
->color('info')
- ->url(fn (string $operation, $record): string => $operation === 'create' ? env('APP_URL').'/compounds/'.request()->compound_id : env('APP_URL').'/compounds/'.$record->mol_ids)
+ ->url(fn (string $operation, $record): string => $operation === 'create' ? config('app.url').'/compounds/'.request()->compound_id : config('app.url').'/compounds/'.$record->mol_ids)
->openUrlInNewTab()
->hidden(function (Get $get, string $operation) {
return ! $get('type');
diff --git a/app/Helper.php b/app/Helper.php
index 4f36c30b..ef527c7f 100644
--- a/app/Helper.php
+++ b/app/Helper.php
@@ -75,7 +75,7 @@ function doiRegxMatch($doi)
function fetchDOICitation($doi)
{
$citationResponse = null;
- $europemcUrl = env('EUROPEPMC_WS_API');
+ $europemcUrl = config('services.citation.europepmc_url');
$europemcParams = [
'query' => 'DOI:'.$doi,
'format' => 'json',
@@ -89,13 +89,13 @@ function fetchDOICitation($doi)
$citationResponse = formatCitationResponse($europemcResponse['resultList']['result'][0], 'europemc');
} else {
// fetch citation from CrossRef
- $crossrefUrl = env('CROSSREF_WS_API').$doi;
+ $crossrefUrl = config('services.citation.crossref_url').$doi;
$crossrefResponse = makeRequest($crossrefUrl);
if ($crossrefResponse && isset($crossrefResponse['message'])) {
$citationResponse = formatCitationResponse($crossrefResponse['message'], 'crossref');
} else {
// fetch citation from DataCite
- $dataciteUrl = env('DATACITE_WS_API').$doi;
+ $dataciteUrl = config('services.citation.datacite_url').$doi;
$dataciteResponse = makeRequest($dataciteUrl);
if ($dataciteResponse && isset($dataciteResponse['data'])) {
$citationResponse = formatCitationResponse($dataciteResponse['data'], 'datacite');
diff --git a/app/Jobs/ImportEntry.php b/app/Jobs/ImportEntry.php
index d411a162..3eb2605a 100644
--- a/app/Jobs/ImportEntry.php
+++ b/app/Jobs/ImportEntry.php
@@ -282,7 +282,7 @@ public function fetchDOICitation($doi, $molecule)
$citationResponse = null;
if ($citation->wasRecentlyCreated || $citation->title == '') {
// fetch citation from EuropePMC
- $europemcUrl = env('EUROPEPMC_WS_API');
+ $europemcUrl = config('services.citation.europepmc_url');
$europemcParams = [
'query' => 'DOI:'.$doi,
'format' => 'json',
@@ -296,14 +296,14 @@ public function fetchDOICitation($doi, $molecule)
$citationResponse = $this->formatCitationResponse($europemcResponse['resultList']['result'][0], 'europemc');
} else {
// fetch citation from CrossRef
- $crossrefUrl = env('CROSSREF_WS_API').$doi;
+ $crossrefUrl = config('services.citation.crossref_url').$doi;
$response = $this->makeRequest($crossrefUrl);
$crossrefResponse = $response ? $response->json() : null;
if ($crossrefResponse && isset($crossrefResponse['message'])) {
$citationResponse = $this->formatCitationResponse($crossrefResponse['message'], 'crossref');
} else {
// fetch citation from DataCite
- $dataciteUrl = env('DATACITE_WS_API').$doi;
+ $dataciteUrl = config('services.citation.datacite_url').$doi;
$response = $this->makeRequest($dataciteUrl);
$dataciteResponse = $response ? $response->json() : null;
if ($dataciteResponse && isset($dataciteResponse['data'])) {
diff --git a/app/Jobs/ImportEntryAuto.php b/app/Jobs/ImportEntryAuto.php
index 59845b99..93d22916 100644
--- a/app/Jobs/ImportEntryAuto.php
+++ b/app/Jobs/ImportEntryAuto.php
@@ -363,7 +363,7 @@ public function fetchDOICitation($doi, $molecule)
$citationResponse = null;
if ($citation->wasRecentlyCreated || $citation->title == '') {
// fetch citation from EuropePMC
- $europemcUrl = env('EUROPEPMC_WS_API');
+ $europemcUrl = config('services.citation.europepmc_url');
$europemcParams = [
'query' => 'DOI:'.$doi,
'format' => 'json',
@@ -377,14 +377,14 @@ public function fetchDOICitation($doi, $molecule)
$citationResponse = $this->formatCitationResponse($europemcResponse['resultList']['result'][0], 'europemc');
} else {
// fetch citation from CrossRef
- $crossrefUrl = env('CROSSREF_WS_API').$doi;
+ $crossrefUrl = config('services.citation.crossref_url').$doi;
$response = $this->makeRequest($crossrefUrl);
$crossrefResponse = $response ? $response->json() : null;
if ($crossrefResponse && isset($crossrefResponse['message'])) {
$citationResponse = $this->formatCitationResponse($crossrefResponse['message'], 'crossref');
} else {
// fetch citation from DataCite
- $dataciteUrl = env('DATACITE_WS_API').$doi;
+ $dataciteUrl = config('services.citation.datacite_url').$doi;
$response = $this->makeRequest($dataciteUrl);
$dataciteResponse = $response ? $response->json() : null;
if ($dataciteResponse && isset($dataciteResponse['data'])) {
diff --git a/app/Jobs/ProcessEntry.php b/app/Jobs/ProcessEntry.php
index 5c17ea83..7fe84406 100644
--- a/app/Jobs/ProcessEntry.php
+++ b/app/Jobs/ProcessEntry.php
@@ -55,7 +55,7 @@ public function handle(): void
$has_stereocenters = false;
$is_invalid = false;
$error_code = -1;
- $API_URL = env('API_URL', 'https://api.cheminf.studio/latest/');
+ $API_URL = config('services.cheminf.internal_api_url');
$ENDPOINT = $API_URL.'chem/coconut/pre-processing?smiles='.urlencode($canonical_smiles).'&_3d_mol=false&descriptors=false';
try {
diff --git a/app/Jobs/ProcessEntryBatch.php b/app/Jobs/ProcessEntryBatch.php
index 12d79a89..c36f229b 100644
--- a/app/Jobs/ProcessEntryBatch.php
+++ b/app/Jobs/ProcessEntryBatch.php
@@ -121,7 +121,7 @@ public function processEntry(Entry $entry): void
$is_cis_trans = false;
$is_invalid = false;
$error_code = -1;
- $API_URL = env('API_URL', 'https://api.cheminf.studio/latest/');
+ $API_URL = config('services.cheminf.internal_api_url');
$ENDPOINT = $API_URL.'chem/coconut/pre-processing?smiles='.urlencode($canonical_smiles).'&_3d_mol=false&descriptors=false';
try {
diff --git a/app/Models/Molecule.php b/app/Models/Molecule.php
index db9b3b91..d03f01b4 100644
--- a/app/Models/Molecule.php
+++ b/app/Models/Molecule.php
@@ -303,7 +303,7 @@ public function getSchema($type = 'bioschemas')
$moleculeSchema->identifier($this->identifier)
->name($this->name)
- ->url(env('APP_URL').'/compound/'.$this->identifier)
+ ->url(config('app.url').'/compound/'.$this->identifier)
->inChI($this->standard_inchi)
->inChIKey($this->standard_inchi_key)
->iupacName($this->iupac_name)
diff --git a/app/Notifications/PostPublishJobFailedNotification.php b/app/Notifications/PostPublishJobFailedNotification.php
index 58c822e6..c5683b27 100644
--- a/app/Notifications/PostPublishJobFailedNotification.php
+++ b/app/Notifications/PostPublishJobFailedNotification.php
@@ -43,7 +43,7 @@ public function toMail(object $notifiable): MailMessage
$timestamp = $this->event->errorDetails['timestamp'];
// Create a dashboard URL for admins to check logs
- $dashboardUrl = url(env('APP_URL').'/dashboard');
+ $dashboardUrl = url(config('app.url').'/dashboard');
$mailMessage = (new MailMessage)
->subject('Coconut: Post Publish Job Failed - '.$jobName)
diff --git a/app/Notifications/PrePublishJobFailedNotification.php b/app/Notifications/PrePublishJobFailedNotification.php
index daa8850d..69671a05 100644
--- a/app/Notifications/PrePublishJobFailedNotification.php
+++ b/app/Notifications/PrePublishJobFailedNotification.php
@@ -43,7 +43,7 @@ public function toMail(object $notifiable): MailMessage
$timestamp = $this->event->errorDetails['timestamp'];
// Create a dashboard URL for admins to check logs
- $dashboardUrl = url(env('APP_URL').'/dashboard');
+ $dashboardUrl = url(config('app.url').'/dashboard');
$mailMessage = (new MailMessage)
->subject('Coconut: Pre Publish Job Failed - '.$jobName)
diff --git a/app/Notifications/ReportAssignedNotification.php b/app/Notifications/ReportAssignedNotification.php
index 1278b549..f29cf456 100644
--- a/app/Notifications/ReportAssignedNotification.php
+++ b/app/Notifications/ReportAssignedNotification.php
@@ -37,7 +37,7 @@ public function via(object $notifiable): array
*/
public function toMail(object $notifiable)
{
- $url = url(env('APP_URL').'/dashboard/reports/'.$this->event->report->id.'/edit');
+ $url = url(config('app.url').'/dashboard/reports/'.$this->event->report->id.'/edit');
return (new ReportAssignedMail($this->event, $notifiable, 'curator', $url))
->to($notifiable->email);
diff --git a/app/Notifications/ReportStatusChangedNotification.php b/app/Notifications/ReportStatusChangedNotification.php
index e93f69ba..610e9f22 100644
--- a/app/Notifications/ReportStatusChangedNotification.php
+++ b/app/Notifications/ReportStatusChangedNotification.php
@@ -41,9 +41,9 @@ public function via(object $notifiable): array
public function toMail(object $notifiable)
{
if ($notifiable->can('update', $this->event->report)) {
- $url = url(env('APP_URL').'/dashboard/reports/'.$this->event->report->id.'/edit');
+ $url = url(config('app.url').'/dashboard/reports/'.$this->event->report->id.'/edit');
} else {
- $url = url(env('APP_URL').'/dashboard/reports/'.$this->event->report->id);
+ $url = url(config('app.url').'/dashboard/reports/'.$this->event->report->id);
}
return (new ReportStatusChangedMail($this->event, $notifiable, $this->mail_to, $url))
diff --git a/app/Notifications/ReportSubmittedNotification.php b/app/Notifications/ReportSubmittedNotification.php
index 0d99e770..246ef6c9 100644
--- a/app/Notifications/ReportSubmittedNotification.php
+++ b/app/Notifications/ReportSubmittedNotification.php
@@ -41,9 +41,9 @@ public function via(object $notifiable): array
public function toMail(object $notifiable)
{
if ($notifiable->can('update', $this->event->report)) {
- $url = url(env('APP_URL').'/dashboard/reports/'.$this->event->report->id.'/edit');
+ $url = url(config('app.url').'/dashboard/reports/'.$this->event->report->id.'/edit');
} else {
- $url = url(env('APP_URL').'/dashboard/reports/'.$this->event->report->id);
+ $url = url(config('app.url').'/dashboard/reports/'.$this->event->report->id);
}
return (new ReportSubmittedMail($this->event, $notifiable, $this->mail_to, $url))
diff --git a/config/filesystems.php b/config/filesystems.php
index 6a645054..54016361 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -39,7 +39,7 @@
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
- 'url' => env('APP_URL').'/storage',
+ 'url' => config('app.url').'/storage',
'visibility' => 'public',
'throw' => false,
],
diff --git a/config/services.php b/config/services.php
index f1158ed6..d25f80cf 100644
--- a/config/services.php
+++ b/config/services.php
@@ -51,6 +51,17 @@
'cheminf' => [
'api_url' => env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/'),
+ 'internal_api_url' => env('API_URL', 'https://api.cheminf.studio/latest/'),
+ ],
+
+ 'citation' => [
+ 'europepmc_url' => env('EUROPEPMC_WS_API'),
+ 'crossref_url' => env('CROSSREF_WS_API'),
+ 'datacite_url' => env('DATACITE_WS_API'),
+ ],
+
+ 'tawk' => [
+ 'url' => env('TAWK_URL'),
],
];
diff --git a/resources/views/components/tawk-chat.blade.php b/resources/views/components/tawk-chat.blade.php
index fa7f24b3..b4416c64 100644
--- a/resources/views/components/tawk-chat.blade.php
+++ b/resources/views/components/tawk-chat.blade.php
@@ -5,7 +5,7 @@
var s1 = document.createElement("script"),
s0 = document.getElementsByTagName("script")[0];
s1.async = true;
- s1.src = '{{ env('TAWK_URL') }}';
+ s1.src = '{{ config('services.tawk.url') }}';
s1.charset = 'UTF-8';
s1.setAttribute('crossorigin', '*');
s0.parentNode.insertBefore(s1, s0);
diff --git a/resources/views/forms/components/organisms-table.blade.php b/resources/views/forms/components/organisms-table.blade.php
index 7403be0f..f3758ea6 100644
--- a/resources/views/forms/components/organisms-table.blade.php
+++ b/resources/views/forms/components/organisms-table.blade.php
@@ -14,7 +14,7 @@
-
+
Edit
From 29fbdf7f69e1fbeb2a50b8d51f214639726e3e36 Mon Sep 17 00:00:00 2001
From: Sagar
Date: Wed, 19 Nov 2025 14:22:41 +0100
Subject: [PATCH 05/11] chore: revered the triggering branch to development.
---
.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 7525fa1c..d25cf0c8 100644
--- a/.github/workflows/dev-build.yml
+++ b/.github/workflows/dev-build.yml
@@ -13,7 +13,7 @@ name : Development - Build COCONUT image and push to Docker Hub
on:
push:
- branches: [fix-access-env-variables]
+ branches: [development]
env:
REPOSITORY_NAME: coconut
From 9fa62488c54b6596367ffdbe6dba67b47114659c Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:18:44 +0100
Subject: [PATCH 06/11] feat: cms client to handle all the requests.
---
app/Services/CmsClient.php | 74 ++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 app/Services/CmsClient.php
diff --git a/app/Services/CmsClient.php b/app/Services/CmsClient.php
new file mode 100644
index 00000000..dc51aee6
--- /dev/null
+++ b/app/Services/CmsClient.php
@@ -0,0 +1,74 @@
+internalUrl = config('services.cheminf.internal_api_url');
+ $this->publicUrl = config('services.cheminf.api_url');
+ $this->authToken = config('services.cheminf.internal_token');
+ }
+
+ /**
+ * Make a GET request to the CMS API
+ *
+ * @return \Illuminate\Http\Client\Response
+ */
+ public function get(string $endpoint, array $params = [])
+ {
+ return $this->makeRequest('GET', $endpoint, $params);
+ }
+
+ /**
+ * Make a POST request to the CMS API
+ *
+ * @return \Illuminate\Http\Client\Response
+ */
+ public function post(string $endpoint, array $data = [])
+ {
+ return $this->makeRequest('POST', $endpoint, $data);
+ }
+
+ /**
+ * Make the actual HTTP request
+ *
+ * @return \Illuminate\Http\Client\Response
+ */
+ private function makeRequest(string $method, string $endpoint, array $data = [])
+ {
+ $request = Http::timeout(120);
+
+ // Add authentication token if available
+ if ($this->authToken) {
+ $request = $request->withHeaders([
+ 'Authorization' => 'Bearer '.$this->authToken,
+ ]);
+ }
+
+ $url = $this->internalUrl.ltrim($endpoint, '/');
+
+ return match (strtoupper($method)) {
+ 'GET' => $request->get($url, $data),
+ 'POST' => $request->post($url, $data),
+ default => throw new \InvalidArgumentException("Unsupported HTTP method: {$method}"),
+ };
+ }
+
+ /**
+ * Get the public URL for the CMS API (for frontend use)
+ */
+ public function getPublicUrl(): string
+ {
+ return $this->publicUrl;
+ }
+}
From b62191528bb72b12fa59af358deaf6c5dc0954fd Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:19:26 +0100
Subject: [PATCH 07/11] feat: controller to handle front end requests.
---
app/Http/Controllers/CmsProxyController.php | 58 +++++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 app/Http/Controllers/CmsProxyController.php
diff --git a/app/Http/Controllers/CmsProxyController.php b/app/Http/Controllers/CmsProxyController.php
new file mode 100644
index 00000000..fa49fe87
--- /dev/null
+++ b/app/Http/Controllers/CmsProxyController.php
@@ -0,0 +1,58 @@
+cmsClient = $cmsClient;
+ }
+
+ /**
+ * Generic proxy for CMS API requests
+ * CSRF protection is automatically applied by Laravel's web middleware
+ *
+ * @return \Illuminate\Http\Response
+ */
+ public function proxy(Request $request)
+ {
+ $endpoint = $request->input('endpoint');
+ $params = $request->except(['endpoint', '_token']);
+ $method = $request->method();
+
+ $response = match ($method) {
+ 'GET' => $this->cmsClient->get($endpoint, $params),
+ 'POST' => $this->cmsClient->post($endpoint, $params),
+ default => abort(405, 'Method not allowed'),
+ };
+
+ return response($response->body())
+ ->header('Content-Type', $response->header('Content-Type'))
+ ->header('Cache-Control', 'public, max-age=86400')
+ ->setStatusCode($response->status());
+ }
+
+ /**
+ * Proxy for 2D depiction - used by img tags
+ * No CSRF protection (called directly by browsers via img src)
+ * Rate limited via route middleware to prevent abuse
+ *
+ * @return \Illuminate\Http\Response
+ */
+ public function depict2D(Request $request)
+ {
+ $params = $request->only(['smiles', 'height', 'width', 'toolkit', 'CIP']);
+
+ $response = $this->cmsClient->get('depict/2D', $params);
+
+ return response($response->body())
+ ->header('Content-Type', $response->header('Content-Type') ?? 'image/svg+xml')
+ ->header('Cache-Control', 'public, max-age=86400');
+ }
+}
From 48edf63af31f52f2e8ff10c2612203f473641e08 Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:20:09 +0100
Subject: [PATCH 08/11] feat: route and service config setup.
---
config/services.php | 2 ++
routes/web.php | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/config/services.php b/config/services.php
index d25f80cf..9073b4d1 100644
--- a/config/services.php
+++ b/config/services.php
@@ -52,6 +52,8 @@
'cheminf' => [
'api_url' => env('CM_PUBLIC_API', 'https://api.cheminf.studio/latest/'),
'internal_api_url' => env('API_URL', 'https://api.cheminf.studio/latest/'),
+ 'internal_token' => env('CMS_INTERNAL_AUTH_TOKEN'),
+ 'rate_limit' => env('CMS_RATE_LIMIT', 200),
],
'citation' => [
diff --git a/routes/web.php b/routes/web.php
index d62ed6c9..d0bc41cd 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -2,6 +2,7 @@
use App\Http\Controllers\ApplicationController;
use App\Http\Controllers\Auth\SocialController;
+use App\Http\Controllers\CmsProxyController;
use App\Http\Controllers\CollectionController;
use App\Http\Controllers\MoleculeController;
use App\Livewire\About;
@@ -43,6 +44,17 @@
Route::get('/collections', CollectionList::class)->name('collections.index');
+// CMS API Proxy - CSRF protected for generic proxy
+Route::match(['GET', 'POST'], '/cms-proxy', [CmsProxyController::class, 'proxy'])->name('cms.proxy');
+
+// CMS Depict endpoint - No CSRF needed (used in img tags)
+// Rate limited per minute based on CMS_RATE_LIMIT env variable (default: 200, 0 = no limit)
+$rateLimit = (int) config('services.cheminf.rate_limit', 200);
+$depictRoute = Route::get('/cms/depict2d', [CmsProxyController::class, 'depict2D'])->name('cms.depict2d');
+if ($rateLimit > 0) {
+ $depictRoute->middleware('throttle:'.$rateLimit.',1');
+}
+
// Compound pages
Route::get('compound/coconut_id/{id}', MoleculeController::class)->name('old_compound');
Route::get('compounds/{id}', MoleculeController::class)->name('compound');
From c044628faace8e3c5d14e06f77f4843283c31295 Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:22:48 +0100
Subject: [PATCH 09/11] feat: modified the cms api access for backend.
---
app/Console/Commands/GenerateCoordinates.php | 24 ++++++++++----------
app/Jobs/ProcessEntry.php | 13 +++++++----
app/Jobs/ProcessEntryBatch.php | 13 +++++++----
3 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/app/Console/Commands/GenerateCoordinates.php b/app/Console/Commands/GenerateCoordinates.php
index 51c25fb9..155e5348 100644
--- a/app/Console/Commands/GenerateCoordinates.php
+++ b/app/Console/Commands/GenerateCoordinates.php
@@ -5,9 +5,9 @@
use App\Models\Collection;
use App\Models\Molecule;
use App\Models\Structure;
+use App\Services\CmsClient;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Throwable;
@@ -63,21 +63,18 @@ public function handle()
$progressBar->start();
// Process molecules in chunks using the static list of IDs.
- $moleculeIds->chunk(10000)->each(function ($idsChunk) use ($progressBar) {
+ $cmsClient = app(CmsClient::class);
+
+ $moleculeIds->chunk(10000)->each(function ($idsChunk) use ($progressBar, $cmsClient) {
$mols = Molecule::whereIn('id', $idsChunk)->select('id', 'canonical_smiles')->get();
$data = [];
foreach ($mols as $mol) {
$id = $mol->id;
$canonical_smiles = $mol->canonical_smiles;
- // Build endpoints.
- $apiUrl = config('services.cheminf.internal_api_url');
- $d2Endpoint = $apiUrl.'convert/mol2D?smiles='.urlencode($canonical_smiles).'&toolkit=rdkit';
- $d3Endpoint = $apiUrl.'convert/mol3D?smiles='.urlencode($canonical_smiles).'&toolkit=rdkit';
-
// Fetch coordinates from API.
- $d2 = $this->fetchFromApi($d2Endpoint, $canonical_smiles);
- $d3 = $this->fetchFromApi($d3Endpoint, $canonical_smiles);
+ $d2 = $this->fetchFromApi($cmsClient, 'convert/mol2D', $canonical_smiles);
+ $d3 = $this->fetchFromApi($cmsClient, 'convert/mol3D', $canonical_smiles);
// Accumulate data for batch insertion.
$data[] = [
@@ -103,9 +100,9 @@ public function handle()
/**
* Make an HTTP GET request with basic retry/backoff handling (e.g. 429 Too Many Requests).
*
- * @return mixed (array|null) Returns the JSON-decoded response or null on failure.
+ * @return mixed (string|null) Returns the response body or null on failure.
*/
- private function fetchFromApi(string $endpoint, string $smiles)
+ private function fetchFromApi(CmsClient $cmsClient, string $endpoint, string $smiles)
{
$maxRetries = 3;
$attempt = 0;
@@ -113,7 +110,10 @@ private function fetchFromApi(string $endpoint, string $smiles)
while ($attempt < $maxRetries) {
try {
- $response = Http::timeout(600)->get($endpoint);
+ $response = $cmsClient->get($endpoint, [
+ 'smiles' => $smiles,
+ 'toolkit' => 'rdkit',
+ ], false);
if ($response->successful()) {
return $response->body();
diff --git a/app/Jobs/ProcessEntry.php b/app/Jobs/ProcessEntry.php
index 7fe84406..6b6ef5a2 100644
--- a/app/Jobs/ProcessEntry.php
+++ b/app/Jobs/ProcessEntry.php
@@ -4,6 +4,7 @@
use App\Enums\ReportStatus;
use App\Events\PrePublishJobFailed;
+use App\Services\CmsClient;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -11,7 +12,6 @@
use Illuminate\Http\Client\RequestException;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
-use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class ProcessEntry implements ShouldQueue
@@ -55,11 +55,16 @@ public function handle(): void
$has_stereocenters = false;
$is_invalid = false;
$error_code = -1;
- $API_URL = config('services.cheminf.internal_api_url');
- $ENDPOINT = $API_URL.'chem/coconut/pre-processing?smiles='.urlencode($canonical_smiles).'&_3d_mol=false&descriptors=false';
+
+ $cmsClient = app(CmsClient::class);
try {
- $response = Http::timeout(600)->get($ENDPOINT);
+ $response = $cmsClient->get('chem/coconut/pre-processing', [
+ 'smiles' => $canonical_smiles,
+ '_3d_mol' => 'false',
+ 'descriptors' => 'false',
+ ], false);
+
if ($response->successful()) {
$data = $response->json();
if (array_key_exists('original', $data)) {
diff --git a/app/Jobs/ProcessEntryBatch.php b/app/Jobs/ProcessEntryBatch.php
index c36f229b..a2dac9b5 100644
--- a/app/Jobs/ProcessEntryBatch.php
+++ b/app/Jobs/ProcessEntryBatch.php
@@ -5,6 +5,7 @@
use App\Enums\ReportStatus;
use App\Events\PrePublishJobFailed;
use App\Models\Entry;
+use App\Services\CmsClient;
use Exception;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
@@ -13,7 +14,6 @@
use Illuminate\Http\Client\RequestException;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
-use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class ProcessEntryBatch implements ShouldQueue
@@ -121,11 +121,16 @@ public function processEntry(Entry $entry): void
$is_cis_trans = false;
$is_invalid = false;
$error_code = -1;
- $API_URL = config('services.cheminf.internal_api_url');
- $ENDPOINT = $API_URL.'chem/coconut/pre-processing?smiles='.urlencode($canonical_smiles).'&_3d_mol=false&descriptors=false';
+
+ $cmsClient = app(CmsClient::class);
try {
- $response = Http::timeout(600)->get($ENDPOINT);
+ $response = $cmsClient->get('chem/coconut/pre-processing', [
+ 'smiles' => $canonical_smiles,
+ '_3d_mol' => 'false',
+ 'descriptors' => 'false',
+ ], false);
+
if ($response->successful()) {
$data = $response->json();
if (array_key_exists('original', $data)) {
From 56b1bba3f867f9fe06f1a6607c088de1066dac4f Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:23:19 +0100
Subject: [PATCH 10/11] feat: modified the cms access for frontend.
---
.../EntriesRelationManager.php | 8 +++----
.../Dashboard/Resources/MoleculeResource.php | 2 +-
.../MoleculesRelationManager.php | 2 +-
.../RelatedRelationManager.php | 2 +-
.../MoleculesRelationManager.php | 2 +-
.../EntriesRelationManager.php | 8 +++----
.../MoleculesRelationManager.php | 2 +-
app/Helper.php | 21 +++++++++++++++++++
app/Livewire/MoleculeDepict2d.php | 4 ++--
resources/views/molecule.blade.php | 4 ++--
10 files changed, 38 insertions(+), 17 deletions(-)
diff --git a/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php b/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
index b3e5e5e4..7d1569a2 100644
--- a/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/CollectionResource/RelationManagers/EntriesRelationManager.php
@@ -99,21 +99,21 @@ public function infolist(Infolist $infolist): Infolist
])
->schema([
ImageEntry::make('parent_canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->parent_canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('standardized_canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->standardized_canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
@@ -133,7 +133,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource.php b/app/Filament/Dashboard/Resources/MoleculeResource.php
index 11894e10..46b31332 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource.php
@@ -90,7 +90,7 @@ public static function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
index b47e153b..88516d97 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/MoleculesRelationManager.php
@@ -26,7 +26,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
index ae132fdc..2599165b 100644
--- a/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
+++ b/app/Filament/Dashboard/Resources/MoleculeResource/RelationManagers/RelatedRelationManager.php
@@ -26,7 +26,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
index a9359be7..5b8c03fc 100644
--- a/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/OrganismResource/RelationManagers/MoleculesRelationManager.php
@@ -40,7 +40,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
index 291a988e..6fb4b5ae 100644
--- a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/EntriesRelationManager.php
@@ -94,21 +94,21 @@ public function infolist(Infolist $infolist): Infolist
])
->schema([
ImageEntry::make('parent_canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->parent_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->parent_canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
->ring(5)
->defaultImageUrl(url('/images/placeholder.png')),
ImageEntry::make('standardized_canonical_smiles')->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->standardized_canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->standardized_canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
@@ -128,7 +128,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
index 107cda4a..d4834703 100644
--- a/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
+++ b/app/Filament/Dashboard/Resources/ReportResource/RelationManagers/MoleculesRelationManager.php
@@ -35,7 +35,7 @@ public function table(Table $table): Table
ImageColumn::make('structure')->square()
->label('Structure')
->state(function ($record) {
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($record->canonical_smiles).'&height=300&width=300&CIP=true&toolkit=cdk';
+ return getDepictUrl($record->canonical_smiles, 300, 300, 'cdk', true);
})
->width(200)
->height(200)
diff --git a/app/Helper.php b/app/Helper.php
index ef527c7f..03c37da7 100644
--- a/app/Helper.php
+++ b/app/Helper.php
@@ -638,3 +638,24 @@ function handleJobFailure(
$batchId
);
}
+
+/**
+ * Generate a URL for 2D molecule depiction through the CMS proxy
+ *
+ * @param string $smiles The SMILES string
+ * @param int $height Image height (default: 300)
+ * @param int $width Image width (default: 300)
+ * @param string $toolkit Toolkit to use: cdk, rdkit, openbabel (default: cdk)
+ * @param bool $CIP Whether to include CIP labels (default: true)
+ * @return string The proxy URL
+ */
+function getDepictUrl(string $smiles, int $height = 300, int $width = 300, string $toolkit = 'cdk', bool $CIP = true): string
+{
+ return route('cms.depict2d', [
+ 'smiles' => $smiles,
+ 'height' => $height,
+ 'width' => $width,
+ 'toolkit' => $toolkit,
+ 'CIP' => $CIP ? 'true' : 'false',
+ ]);
+}
diff --git a/app/Livewire/MoleculeDepict2d.php b/app/Livewire/MoleculeDepict2d.php
index bc5d1478..49a96a74 100644
--- a/app/Livewire/MoleculeDepict2d.php
+++ b/app/Livewire/MoleculeDepict2d.php
@@ -28,13 +28,13 @@ class MoleculeDepict2d extends Component
#[Computed]
public function source()
{
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($this->smiles).'&height='.$this->height.'&width='.$this->width.'&toolkit='.$this->toolkit.'&CIP='.$this->CIP;
+ return getDepictUrl($this->smiles, $this->height, $this->width, $this->toolkit, $this->CIP);
}
#[Computed]
public function preview()
{
- return config('services.cheminf.api_url').'depict/2D?smiles='.urlencode($this->smiles);
+ return getDepictUrl($this->smiles);
}
public function downloadMolFile($toolkit)
diff --git a/resources/views/molecule.blade.php b/resources/views/molecule.blade.php
index 637ab628..46111b5e 100644
--- a/resources/views/molecule.blade.php
+++ b/resources/views/molecule.blade.php
@@ -34,7 +34,7 @@
+ content="{{ getDepictUrl($molecule->canonical_smiles, 630, 1200, 'cdk', true) ?? asset('img/coconut-og-image.png') }}">
@@ -56,7 +56,7 @@
and found in the collection{{ $molecule->collections->count() > 1 ? 's' : '' }}:
{{ implode(', ', $molecule->collections->pluck('title')->toArray()) }} @endif">
+ content="{{ getDepictUrl($molecule->canonical_smiles, 630, 1200, 'cdk', true) ?? asset('img/coconut-og-image.png') }}">
From 98caa6c6bc9f229c292bcc0cd4fb4b670b51544e Mon Sep 17 00:00:00 2001
From: Sagar
Date: Sun, 23 Nov 2025 12:23:46 +0100
Subject: [PATCH 11/11] feat: added example env content.
---
.env.example | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/.env.example b/.env.example
index 2d7f02fd..c3d44a68 100644
--- a/.env.example
+++ b/.env.example
@@ -57,3 +57,13 @@ VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
+
+# CMS (ChemInformatics Microservice) API Configuration
+# API_URL: Internal/Docker network URL for backend requests
+# CM_PUBLIC_API: Public URL for frontend/proxy requests
+# CMS_INTERNAL_AUTH_TOKEN: Authentication token to bypass rate limits
+# CMS_RATE_LIMIT: Maximum requests per minute to /cms/depict2d endpoint (default: 200, set to 0 to disable)
+API_URL=https://api.cheminf.studio/latest/
+CM_PUBLIC_API=https://api.cheminf.studio/latest/
+CMS_INTERNAL_AUTH_TOKEN=
+CMS_RATE_LIMIT=200