From 9a48ca5c4042d760574847e71929a14b415b42ad Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Mon, 16 Dec 2024 18:57:40 +0100 Subject: [PATCH 01/12] feat: auto fill risk assessment with ebios rm study --- backend/core/views.py | 31 +++++++++++++++++++++++++++++++ backend/ebios_rm/models.py | 19 +++++++++++++------ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/backend/core/views.py b/backend/core/views.py index 6f43015713..b8d3f79272 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -69,10 +69,16 @@ AppliedControl, ComplianceAssessment, RequirementMappingSet, + RiskAssessment, ) from core.serializers import ComplianceAssessmentReadSerializer from core.utils import RoleCodename, UserGroupCodename +from ebios_rm.models import ( + EbiosRMStudy, + OperationalScenario, +) + from .models import * from .serializers import * @@ -578,6 +584,31 @@ class RiskAssessmentViewSet(BaseModelViewSet): "ebios_rm_study", ] + def perform_create(self, serializer): + instance: RiskAssessment = serializer.save() + if instance.ebios_rm_study: + instance.risk_matrix = instance.ebios_rm_study.risk_matrix + ebios_rm_study = EbiosRMStudy.objects.get(id=instance.ebios_rm_study.id) + for operational_scenario in ebios_rm_study.operational_scenarios.all(): + risk_scenario = RiskScenario.objects.create( + risk_assessment=instance, + name=operational_scenario.name, + ref_id=operational_scenario.ref_id + if operational_scenario.ref_id + else RiskScenario.get_default_ref_id(instance), + description=operational_scenario.operating_modes_description, + current_proba=operational_scenario.likelihood, + current_impact=operational_scenario.gravity, + ) + risk_scenario.assets.set(operational_scenario.get_assets()) + risk_scenario.threats.set(operational_scenario.threats.all()) + risk_scenario.existing_applied_controls.set( + operational_scenario.get_applied_controls() + ) + risk_scenario.save() + instance.save() + return super().perform_create(serializer) + @action(detail=False, name="Risk assessments per status") def per_status(self, request): data = assessment_per_status(request.user, RiskAssessment) diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index 7eab4f5d2d..165d255604 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -458,12 +458,11 @@ def parsed_matrix(self): @property def ref_id(self): - sorted_operational_scenarios = list( - OperationalScenario.objects.filter( - ebios_rm_study=self.ebios_rm_study - ).order_by("created_at") - ) - return sorted_operational_scenarios.index(self) + 1 + return self.attack_path.ref_id + + @property + def name(self): + return self.attack_path.name @property def gravity(self): @@ -477,6 +476,14 @@ def stakeholders(self): def ro_to(self): return self.attack_path.ro_to_couple + def get_assets(self): + return Asset.objects.filter( + feared_events__in=self.attack_path.ro_to_couple.feared_events.all() + ) + + def get_applied_controls(self): + return AppliedControl.objects.filter(stakeholders__in=self.stakeholders.all()) + def get_likelihood_display(self): if self.likelihood < 0: return { From 1f6a6d4234f89c942e327e91c059d17c630580dd Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 12:18:52 +0100 Subject: [PATCH 02/12] fix: gravity not rated display --- backend/ebios_rm/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index 165d255604..0a76b88007 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -149,6 +149,7 @@ def get_gravity_display(self): "name": "--", "description": "not rated", "value": -1, + "hexcolor": "#f9fafb", } risk_matrix = self.parsed_matrix return { @@ -506,6 +507,7 @@ def get_gravity_display(self): "name": "--", "description": "not rated", "value": -1, + "hexcolor": "#f9fafb", } risk_matrix = self.parsed_matrix return { From b1f994a27aaee32a177e6dea7dc3c6a25a980e97 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 12:21:02 +0100 Subject: [PATCH 03/12] feat: improve feared event attack path tables --- frontend/src/lib/utils/table.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts index 844034bb49..cf6e52bd16 100644 --- a/frontend/src/lib/utils/table.ts +++ b/frontend/src/lib/utils/table.ts @@ -571,8 +571,8 @@ export const listViewFields: ListViewFieldsConfig = { body: ['name', 'description'] }, 'feared-events': { - head: ['selected', 'assets', 'fearedEvent', 'qualifications', 'gravity'], - body: ['is_selected', 'assets', 'description', 'qualifications', 'gravity'] + head: ['selected', 'name', 'assets', 'fearedEvent', 'qualifications', 'gravity'], + body: ['is_selected', 'name', 'assets', 'description', 'qualifications', 'gravity'] }, 'ro-to': { head: [ @@ -597,8 +597,8 @@ export const listViewFields: ListViewFieldsConfig = { body: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'] }, 'attack-paths': { - head: ['risk_origin', 'target_objective', 'stakeholders', 'attackPath'], - body: ['risk_origin', 'target_objective', 'stakeholders', 'description'] + head: ['is_selected', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'attackPath'], + body: ['is_selected', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'description'] }, 'operational-scenarios': { head: ['operatingModesDescription', 'threats', 'likelihood'], From c8074baf16420f492ca75d021973ccca4621a7b0 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 12:27:18 +0100 Subject: [PATCH 04/12] fix: use attack path name in form --- .../components/Forms/ModelForm/OperationalScenarioForm.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte index 116a1205c4..449a679c81 100644 --- a/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte @@ -76,8 +76,7 @@ Date: Tue, 17 Dec 2024 12:56:01 +0100 Subject: [PATCH 05/12] feat: add filters and checks --- backend/ebios_rm/models.py | 2 ++ frontend/src/lib/utils/crud.ts | 4 +++- .../[model=urlmodel]/[id=uuid]/edit/+layout.server.ts | 10 +++++++++- .../workshop-three/strategic-scenarios/+page.server.ts | 4 +++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index 0a76b88007..bac7e8b3e6 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -88,6 +88,8 @@ class Status(models.TextChoices): related_name="reviewers", ) observation = models.TextField(null=True, blank=True, verbose_name=_("Observation")) + + fields_to_check = ["name", "version"] class Meta: verbose_name = _("Ebios RM Study") diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index a076556f06..d91bc18ede 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -106,6 +106,7 @@ interface ForeignKeyField { endpointUrl?: string; urlParams?: string; detail?: boolean; + detailUrlParams?: string[]; // To prepare possible fetch for foreign keys with detail in generic views } interface Field { @@ -677,7 +678,8 @@ export const URL_MODEL_MAP: ModelMap = { verboseNamePlural: 'Attack paths', foreignKeyFields: [ { field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders' }, - { field: 'ro_to_couple', urlModel: 'ro-to', endpointUrl: 'ebios-rm/ro-to' }, + { field: 'ro_to_couple', urlModel: 'ro-to', endpointUrl: 'ebios-rm/ro-to', urlParams: 'ebios_rm_study=', + detail: true }, { field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' }, { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' } ] diff --git a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts index dadfb90bbd..22c34b4505 100644 --- a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts +++ b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts @@ -47,7 +47,15 @@ export const load: LayoutServerLoad = async (event) => { if (foreignKeyFields) { for (const keyField of foreignKeyFields) { - const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : ''; + let queryParams = keyField.urlParams ? `?${keyField.urlParams}` : ''; + if (keyField.detailUrlParams && Array.isArray(keyField.detailUrlParams)) { + keyField.detailUrlParams.forEach(detailParam => { + const paramValue = object[detailParam]?.id; + if (paramValue) { + queryParams += queryParams ? `&${detailParam}=${paramValue}` : `?${detailParam}=${paramValue}`; + } + }); + } // To prepare possible fetch for foreign keys with detail in generic views const keyModel = getModelInfo(keyField.urlModel); let url = keyModel.endpointUrl ? `${BASE_API_URL}/${keyModel.endpointUrl}/${queryParams}` diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts index 2b31addc0a..94c75806dc 100644 --- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts +++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts @@ -51,7 +51,9 @@ export const load: PageServerLoad = async ({ params, fetch }) => { for (const keyField of foreignKeyFields) { const model = getModelInfo(keyField.urlModel); - const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : ''; + const queryParams = keyField.urlParams + ? `?${keyField.urlParams}${keyField.detail ? params.id : ''}` + : ''; const url = model.endpointUrl ? `${BASE_API_URL}/${model.endpointUrl}/${queryParams}` : `${BASE_API_URL}/${model.urlModel}/${queryParams}`; From 8c96b6b0d935233304e98f3e666e1ffc1321272c Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 12:56:51 +0100 Subject: [PATCH 06/12] chore: format --- backend/ebios_rm/models.py | 2 +- frontend/src/lib/utils/crud.ts | 9 +++++++-- .../[model=urlmodel]/[id=uuid]/edit/+layout.server.ts | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index bac7e8b3e6..71d6a9db92 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -88,7 +88,7 @@ class Status(models.TextChoices): related_name="reviewers", ) observation = models.TextField(null=True, blank=True, verbose_name=_("Observation")) - + fields_to_check = ["name", "version"] class Meta: diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index d91bc18ede..47f7d15c42 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -678,8 +678,13 @@ export const URL_MODEL_MAP: ModelMap = { verboseNamePlural: 'Attack paths', foreignKeyFields: [ { field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders' }, - { field: 'ro_to_couple', urlModel: 'ro-to', endpointUrl: 'ebios-rm/ro-to', urlParams: 'ebios_rm_study=', - detail: true }, + { + field: 'ro_to_couple', + urlModel: 'ro-to', + endpointUrl: 'ebios-rm/ro-to', + urlParams: 'ebios_rm_study=', + detail: true + }, { field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' }, { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' } ] diff --git a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts index 22c34b4505..b02849fd6f 100644 --- a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts +++ b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts @@ -49,10 +49,12 @@ export const load: LayoutServerLoad = async (event) => { for (const keyField of foreignKeyFields) { let queryParams = keyField.urlParams ? `?${keyField.urlParams}` : ''; if (keyField.detailUrlParams && Array.isArray(keyField.detailUrlParams)) { - keyField.detailUrlParams.forEach(detailParam => { + keyField.detailUrlParams.forEach((detailParam) => { const paramValue = object[detailParam]?.id; if (paramValue) { - queryParams += queryParams ? `&${detailParam}=${paramValue}` : `?${detailParam}=${paramValue}`; + queryParams += queryParams + ? `&${detailParam}=${paramValue}` + : `?${detailParam}=${paramValue}`; } }); } // To prepare possible fetch for foreign keys with detail in generic views From f41fa84d5c536d83d16f8d02a396ade2a72624a0 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 18:49:37 +0100 Subject: [PATCH 07/12] chore: format --- frontend/src/lib/utils/table.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts index 51e366482c..0340afc49f 100644 --- a/frontend/src/lib/utils/table.ts +++ b/frontend/src/lib/utils/table.ts @@ -597,8 +597,24 @@ export const listViewFields: ListViewFieldsConfig = { body: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'] }, 'attack-paths': { - head: ['is_selected', 'ref_id', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'attackPath'], - body: ['is_selected', 'ref_id', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'description'] + head: [ + 'is_selected', + 'ref_id', + 'name', + 'risk_origin', + 'target_objective', + 'stakeholders', + 'attackPath' + ], + body: [ + 'is_selected', + 'ref_id', + 'name', + 'risk_origin', + 'target_objective', + 'stakeholders', + 'description' + ] }, 'operational-scenarios': { head: ['operatingModesDescription', 'threats', 'likelihood'], From c06b64b341812b6a0d9fa58fbd0d73ff04680857 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 17 Dec 2024 20:07:10 +0100 Subject: [PATCH 08/12] feat: create only selected operational scenarios --- backend/core/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/core/views.py b/backend/core/views.py index b8d3f79272..915e0c054d 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -589,7 +589,11 @@ def perform_create(self, serializer): if instance.ebios_rm_study: instance.risk_matrix = instance.ebios_rm_study.risk_matrix ebios_rm_study = EbiosRMStudy.objects.get(id=instance.ebios_rm_study.id) - for operational_scenario in ebios_rm_study.operational_scenarios.all(): + for operational_scenario in [ + operational_scenario + for operational_scenario in ebios_rm_study.operational_scenarios.all() + if operational_scenario.is_selected + ]: risk_scenario = RiskScenario.objects.create( risk_assessment=instance, name=operational_scenario.name, From 3a6d4a8bef37e7984ca14cd7c4bbcdff1ff4efcb Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Thu, 19 Dec 2024 21:35:07 +0100 Subject: [PATCH 09/12] feat: add in risk scenario operational assets and descendants --- backend/core/models.py | 11 +++++++++++ backend/ebios_rm/models.py | 12 ++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/backend/core/models.py b/backend/core/models.py index 4d5ba2c026..a9a239a6d6 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -1493,6 +1493,17 @@ def ancestors_plus_self(self) -> set[Self]: for x in self.parent_assets.all(): result.update(x.ancestors_plus_self()) return set(result) + + def get_children(self): + return Asset.objects.filter(parent_assets=self) + + def get_descendants(self) -> set[Self]: + children = self.get_children() + sub_children = set() + for child in children: + sub_children.append(child) + sub_children.update(child.get_descendants()) + return sub_children def get_security_objectives(self) -> dict[str, dict[str, dict[str, int | bool]]]: """ diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index 63d13782d8..488f394bfc 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -12,8 +12,6 @@ ) from iam.models import FolderMixin, User from tprm.models import Entity -import json - class EbiosRMStudy(NameDescriptionMixin, ETADueDateMixin, FolderMixin): class Status(models.TextChoices): @@ -494,9 +492,15 @@ def ro_to(self): return self.attack_path.ro_to_couple def get_assets(self): - return Asset.objects.filter( - feared_events__in=self.attack_path.ro_to_couple.feared_events.all() + initial_assets = Asset.objects.filter( + feared_events__in=self.ro_to.feared_events.all(), + is_selected=True ) + assets = set() + for asset in initial_assets: + assets.add(asset) + assets.update(asset.get_descendants()) + return Asset.objects.filter(id__in=[asset.id for asset in assets]) def get_applied_controls(self): return AppliedControl.objects.filter(stakeholders__in=self.stakeholders.all()) From 27b8f2b82ff71151572a24e88f11b273dd709f7a Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Thu, 19 Dec 2024 21:35:20 +0100 Subject: [PATCH 10/12] chore: format --- backend/core/models.py | 4 ++-- backend/ebios_rm/models.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/core/models.py b/backend/core/models.py index a9a239a6d6..7407d48535 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -1493,10 +1493,10 @@ def ancestors_plus_self(self) -> set[Self]: for x in self.parent_assets.all(): result.update(x.ancestors_plus_self()) return set(result) - + def get_children(self): return Asset.objects.filter(parent_assets=self) - + def get_descendants(self) -> set[Self]: children = self.get_children() sub_children = set() diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index 488f394bfc..adad6e3673 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -13,6 +13,7 @@ from iam.models import FolderMixin, User from tprm.models import Entity + class EbiosRMStudy(NameDescriptionMixin, ETADueDateMixin, FolderMixin): class Status(models.TextChoices): PLANNED = "planned", _("Planned") @@ -493,8 +494,7 @@ def ro_to(self): def get_assets(self): initial_assets = Asset.objects.filter( - feared_events__in=self.ro_to.feared_events.all(), - is_selected=True + feared_events__in=self.ro_to.feared_events.all(), is_selected=True ) assets = set() for asset in initial_assets: From 185312df2c3a11b65b9e82515d058fa5b14a38a3 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Thu, 19 Dec 2024 22:03:12 +0100 Subject: [PATCH 11/12] feat: filter assets in feared events --- frontend/src/lib/utils/crud.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index 47f7d15c42..2a23ce3716 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -626,7 +626,7 @@ export const URL_MODEL_MAP: ModelMap = { verboseNamePlural: 'Feared events', foreignKeyFields: [ { field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' }, - { field: 'assets', urlModel: 'assets', urlParams: 'ebios_rm_studies=', detail: true }, + { field: 'assets', urlModel: 'assets', urlParams: 'type=PR&ebios_rm_studies=', detail: true }, { field: 'qualifications', urlModel: 'qualifications' } ], selectFields: [{ field: 'gravity', valueType: 'number', detail: true }] From 32d4b8dd7a56b88bacb9a3ce46f0222266d16877 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Thu, 19 Dec 2024 23:01:39 +0100 Subject: [PATCH 12/12] fix: risk assessment modal in ebios rm --- .../ebios-rm/[id=uuid]/+page.server.ts | 51 ++++++++++++++++++- .../ebios-rm/[id=uuid]/+page.svelte | 11 ++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts index f28ed8334a..6d37a78e8d 100644 --- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts +++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts @@ -1,6 +1,10 @@ import { defaultWriteFormAction } from '$lib/utils/actions'; import { BASE_API_URL } from '$lib/utils/constants'; -import { getModelInfo } from '$lib/utils/crud'; +import { + getModelInfo, + urlParamModelForeignKeyFields, + urlParamModelSelectFields +} from '$lib/utils/crud'; import { modelSchema } from '$lib/utils/schemas'; import type { ModelInfo } from '$lib/utils/types'; import { type Actions } from '@sveltejs/kit'; @@ -28,8 +32,51 @@ export const load: PageServerLoad = async ({ params, fetch }) => { const createRiskAnalysisForm = await superValidate(initialData, zod(createSchema), { errors: false }); + const riskModel = getModelInfo('risk-assessments'); + const foreignKeyFields = urlParamModelForeignKeyFields(riskModel.urlModel); + const selectFields = urlParamModelSelectFields(riskModel.urlModel); - return { createRiskAnalysisForm, model: getModelInfo('risk-assessments') }; + const foreignKeys: Record = {}; + + for (const keyField of foreignKeyFields) { + const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : ''; + const keyModel = getModelInfo(keyField.urlModel); + const url = keyModel.endpointUrl + ? `${BASE_API_URL}/${keyModel.endpointUrl}/${queryParams}` + : `${BASE_API_URL}/${keyField.urlModel}/${queryParams}`; + const response = await fetch(url); + if (response.ok) { + foreignKeys[keyField.field] = await response.json().then((data) => data.results); + } else { + console.error(`Failed to fetch data for ${keyField.field}: ${response.statusText}`); + } + } + + riskModel['foreignKeys'] = foreignKeys; + + const selectOptions: Record = {}; + + for (const selectField of selectFields) { + if (selectField.detail) continue; + const url = riskModel.endpointUrl + ? `${BASE_API_URL}/${riskModel.endpointUrl}/${selectField.field}/` + : `${BASE_API_URL}/${riskModel.urlModel}/${selectField.field}/`; + const response = await fetch(url); + if (response.ok) { + selectOptions[selectField.field] = await response.json().then((data) => + Object.entries(data).map(([key, value]) => ({ + label: value, + value: selectField.valueType === 'number' ? parseInt(key) : key + })) + ); + } else { + console.error(`Failed to fetch data for ${selectField.field}: ${response.statusText}`); + } + } + + riskModel['selectOptions'] = selectOptions; + + return { createRiskAnalysisForm, riskModel }; }; export const actions: Actions = { diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte index 02b6356595..87c405b67c 100644 --- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte @@ -123,17 +123,18 @@ ref: CreateModal, props: { form: data.createRiskAnalysisForm, - model: data.model + model: data.riskModel } }; let modal: ModalSettings = { type: 'component', component: modalComponent, // Data - title: safeTranslate('add-' + data.model.localName) + title: safeTranslate('add-' + data.riskModel.localName) }; if ( - checkConstraints(data.createRiskAnalysisForm.constraints, data.model.foreignKeys).length > 0 + checkConstraints(data.createRiskAnalysisForm.constraints, data.riskModel.foreignKeys).length > + 0 ) { modalComponent = { ref: MissingConstraintsModal @@ -142,8 +143,8 @@ type: 'component', component: modalComponent, title: m.warning(), - body: safeTranslate('add-' + data.model.localName).toLowerCase(), - value: checkConstraints(data.createRiskAnalysisForm.constraints, data.model.foreignKeys) + body: safeTranslate('add-' + data.riskModel.localName).toLowerCase(), + value: checkConstraints(data.createRiskAnalysisForm.constraints, data.riskModel.foreignKeys) }; } modalStore.trigger(modal);