From 752794c69cd650abe802286b93bf784110e8898b Mon Sep 17 00:00:00 2001
From: melinoix
Date: Wed, 20 Nov 2024 17:34:08 +0100
Subject: [PATCH 01/12] still have to connect api point + migration
---
.../migrations/0037_riskscenario_ref_id.py | 19 ++++++++++
backend/core/models.py | 17 ++++++---
backend/core/serializers.py | 1 -
backend/core/views.py | 22 ++++++++++--
.../Forms/ModelForm/RiskScenarioForm.svelte | 36 +++++++++++++++++++
.../RiskMatrix/RiskScenarioItem.stories.ts | 2 +-
.../RiskMatrix/RiskScenarioItem.svelte | 2 +-
frontend/src/lib/utils/schemas.ts | 3 +-
frontend/src/lib/utils/table.ts | 2 ++
9 files changed, 92 insertions(+), 12 deletions(-)
create mode 100644 backend/core/migrations/0037_riskscenario_ref_id.py
diff --git a/backend/core/migrations/0037_riskscenario_ref_id.py b/backend/core/migrations/0037_riskscenario_ref_id.py
new file mode 100644
index 000000000..9aad60a9e
--- /dev/null
+++ b/backend/core/migrations/0037_riskscenario_ref_id.py
@@ -0,0 +1,19 @@
+# Generated by Django 5.1.1 on 2024-11-20 12:53
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0036_asset_owner"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="riskscenario",
+ name="ref_id",
+ field=models.CharField(
+ blank=True, max_length=100, verbose_name="Reference ID"
+ ),
+ ),
+ ]
diff --git a/backend/core/models.py b/backend/core/models.py
index c1c2ec8b9..9e8d377f2 100644
--- a/backend/core/models.py
+++ b/backend/core/models.py
@@ -2026,6 +2026,18 @@ class RiskScenario(NameDescriptionMixin):
verbose_name=_("Treatment status"),
)
+ @classmethod
+ def get_default_ref_id(cls, risk_assessment: RiskAssessment):
+ """return associated risk assessment id"""
+ scenarios_ref_ids = [x.ref_id for x in risk_assessment.risk_scenarios.all()]
+ nb_scenarios = len(scenarios_ref_ids) + 1
+ candidates = [f"R.{i}" for i in range(nb_scenarios)]
+ return next(x for x in candidates if x not in scenarios_ref_ids)
+
+ ref_id = models.CharField(
+ max_length=100, blank=False, verbose_name=_("Reference ID")
+ )
+
qualifications = models.JSONField(default=list, verbose_name=_("Qualifications"))
strength_of_knowledge = models.IntegerField(
@@ -2153,11 +2165,6 @@ def get_strength_of_knowledge(self):
def __str__(self):
return str(self.parent_project()) + _(": ") + str(self.name)
- @property
- def rid(self):
- """return associated risk assessment id"""
- return f"R.{self.scoped_id(scope=RiskScenario.objects.filter(risk_assessment=self.risk_assessment))}"
-
def save(self, *args, **kwargs):
if self.current_proba >= 0 and self.current_impact >= 0:
self.current_level = risk_scoring(
diff --git a/backend/core/serializers.py b/backend/core/serializers.py
index a27692c3e..91ce52ff4 100644
--- a/backend/core/serializers.py
+++ b/backend/core/serializers.py
@@ -306,7 +306,6 @@ class RiskScenarioReadSerializer(RiskScenarioWriteSerializer):
applied_controls = FieldsRelatedField(many=True)
existing_applied_controls = FieldsRelatedField(many=True)
- rid = serializers.CharField()
owner = FieldsRelatedField(many=True)
diff --git a/backend/core/views.py b/backend/core/views.py
index 557e28bd6..329bff8c2 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -592,7 +592,7 @@ def treatment_plan_csv(self, request, pk):
):
risk_scenarios = ",".join(
[
- f"{scenario.rid}: {scenario.name}"
+ f"{scenario.ref_id}: {scenario.name}"
for scenario in mtg.risk_scenarios.all()
]
)
@@ -628,7 +628,7 @@ def risk_assessment_csv(self, request, pk):
writer = csv.writer(response, delimiter=";")
columns = [
- "rid",
+ "ref_id",
"threats",
"name",
"description",
@@ -646,7 +646,7 @@ def risk_assessment_csv(self, request, pk):
)
threats = ",".join([t.name for t in scenario.threats.all()])
row = [
- scenario.rid,
+ scenario.ref_id,
threats,
scenario.name,
scenario.description,
@@ -1146,6 +1146,22 @@ def count_per_level(self, request):
def per_status(self, request):
return Response({"results": risk_per_status(request.user)})
+ @action(detail=False, methods=["get"], name="Get the smallest ref_id available")
+ def default_ref_id(self, request):
+ risk_assessment_id = request.query_params.get("risk_assessment")
+ if not risk_assessment_id:
+ return Response(
+ {"error": "Missing 'risk_assessment' parameter."}, status=400
+ )
+ try:
+ risk_assessment = RiskAssessment.objects.get(pk=risk_assessment_id)
+
+ # Use the class method to compute the default ref_id
+ default_ref_id = RiskScenario.get_default_ref_id(risk_assessment)
+ return Response({"results": default_ref_id})
+ except Exception as e:
+ return Response({"error": str(e)}, status=400)
+
class RiskAcceptanceViewSet(BaseModelViewSet):
"""
diff --git a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
index b89866439..37531427a 100644
--- a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
@@ -1,6 +1,7 @@
{
+ if (e.detail) {
+ await fetchDefaultRefId(e.detail);
+ }
+ }}
+/>
+
+
+
;
const scenario = {
id: '7059ef1b-7d4f-46bc-b735-ed41b531bb22',
name: 'RS1',
- rid: 'R.1',
+ ref_id: 'R.1',
strength_of_knowledge: {
name: 'Very High',
description: 'The strength of the knowledge supporting the assessment is very high',
diff --git a/frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte b/frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte
index 9bc48e0f7..83071905d 100644
--- a/frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte
+++ b/frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte
@@ -6,5 +6,5 @@
{#if data.strength_of_knowledge && data.strength_of_knowledge.symbol !== undefined}
{data.strength_of_knowledge.symbol}
{/if}
- {data.rid}
+ {data.ref_id}
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index bdc82f1b9..40bd90eba 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -118,7 +118,8 @@ export const RiskScenarioSchema = baseNamedObject({
threats: z.string().uuid().optional().array().optional(),
assets: z.string().uuid().optional().array().optional(),
vulnerabilities: z.string().uuid().optional().array().optional(),
- owner: z.string().uuid().optional().array().optional()
+ owner: z.string().uuid().optional().array().optional(),
+ ref_id: z.string()
});
export const AppliedControlSchema = baseNamedObject({
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index c7dbe065a..f6eb27fd6 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -313,6 +313,7 @@ export const listViewFields: ListViewFieldsConfig = {
},
'risk-scenarios': {
head: [
+ 'ref_id',
'name',
'threats',
'riskAssessment',
@@ -322,6 +323,7 @@ export const listViewFields: ListViewFieldsConfig = {
'residualLevel'
],
body: [
+ 'ref_id',
'name',
'threats',
'risk_assessment',
From bc77e9dc9f69754d743f9f64b2a4c87f9a96869b Mon Sep 17 00:00:00 2001
From: melinoix
Date: Thu, 21 Nov 2024 19:14:22 +0100
Subject: [PATCH 02/12] corrected migration
---
.../migrations/0037_riskscenario_ref_id.py | 24 +++++++++++++++++--
backend/core/views.py | 6 ++++-
enterprise/backend/enterprise_core/models.py | 2 +-
.../Forms/ModelForm/RiskScenarioForm.svelte | 4 +++-
4 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/backend/core/migrations/0037_riskscenario_ref_id.py b/backend/core/migrations/0037_riskscenario_ref_id.py
index 9aad60a9e..520911616 100644
--- a/backend/core/migrations/0037_riskscenario_ref_id.py
+++ b/backend/core/migrations/0037_riskscenario_ref_id.py
@@ -1,8 +1,26 @@
-# Generated by Django 5.1.1 on 2024-11-20 12:53
+# Generated by Django 5.1.1 on 2024-11-21 17:22
from django.db import migrations, models
+def populate_default_ref_ids(apps, schema_editor):
+ RiskAssessment = apps.get_model("core", "RiskAssessment")
+
+ def get_default_ref_id(risk_assessment):
+ """Return a unique reference ID for a given risk assessment."""
+ scenarios_ref_ids = [
+ x.ref_id for x in risk_assessment.risk_scenarios.all() if x.ref_id
+ ]
+ nb_scenarios = len(scenarios_ref_ids) + 1
+ candidates = [f"R.{i}" for i in range(nb_scenarios)]
+ return next(x for x in candidates if x not in scenarios_ref_ids)
+
+ for risk_assessment in RiskAssessment.objects.all():
+ for scenario in risk_assessment.risk_scenarios.filter(ref_id=""):
+ scenario.ref_id = get_default_ref_id(risk_assessment)
+ scenario.save()
+
+
class Migration(migrations.Migration):
dependencies = [
("core", "0036_asset_owner"),
@@ -13,7 +31,9 @@ class Migration(migrations.Migration):
model_name="riskscenario",
name="ref_id",
field=models.CharField(
- blank=True, max_length=100, verbose_name="Reference ID"
+ default="", max_length=100, verbose_name="Reference ID"
),
+ preserve_default=False,
),
+ migrations.RunPython(populate_default_ref_ids),
]
diff --git a/backend/core/views.py b/backend/core/views.py
index 329bff8c2..77ff22d2d 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -51,6 +51,8 @@
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN
from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework.views import APIView
+from rest_framework.permissions import AllowAny
+
from weasyprint import HTML
@@ -1146,7 +1148,9 @@ def count_per_level(self, request):
def per_status(self, request):
return Response({"results": risk_per_status(request.user)})
- @action(detail=False, methods=["get"], name="Get the smallest ref_id available")
+ @action(
+ detail=False, methods=["get"], permission_classes=[permissions.IsAuthenticated]
+ )
def default_ref_id(self, request):
risk_assessment_id = request.query_params.get("risk_assessment")
if not risk_assessment_id:
diff --git a/enterprise/backend/enterprise_core/models.py b/enterprise/backend/enterprise_core/models.py
index a4cde30a8..f0cc47590 100644
--- a/enterprise/backend/enterprise_core/models.py
+++ b/enterprise/backend/enterprise_core/models.py
@@ -19,7 +19,7 @@ class FileField(Enum):
name = models.CharField(max_length=255, blank=True)
logo = models.ImageField(
- upload_to="client_logos",
+ upload_to="",
null=True,
blank=True,
validators=[FileExtensionValidator(["png", "jpeg", "jpg", "webp", "svg"])],
diff --git a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
index 37531427a..55ecf21ae 100644
--- a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
@@ -5,6 +5,7 @@
import type { SuperValidated } from 'sveltekit-superforms';
import type { ModelInfo, CacheLock } from '$lib/utils/types';
import * as m from '$paraglide/messages.js';
+ import { BASE_API_URL } from '$lib/utils/constants';
export let form: SuperValidated;
export let model: ModelInfo;
@@ -17,9 +18,10 @@
async function fetchDefaultRefId(riskAssessmentId: string) {
try {
const response = await fetch(
- `/risk-scenarios/default-ref-id/?risk_assessment=${riskAssessmentId}`
+ `${BASE_API_URL}/risk-scenarios/default_ref_id/?risk_assessment=${riskAssessmentId}`
);
const result = await response.json();
+ console.log(result);
if (response.ok && result.results) {
form.form.update((currentData) => {
updated_fields.add('ref_id');
From c8da9097a1a5b5cd0b74e6f605c894274aff5212 Mon Sep 17 00:00:00 2001
From: melinoix
Date: Fri, 22 Nov 2024 12:44:21 +0100
Subject: [PATCH 03/12] Corrected fetching & migrations
---
..._ref_id.py => 0039_riskscenario_ref_id.py} | 4 ++--
backend/core/models.py | 2 +-
.../settings/client-settings/logo/+server.ts | 2 +-
.../Forms/ModelForm/RiskScenarioForm.svelte | 4 ++--
.../risk-scenarios/default-ref-id/+server.ts | 21 +++++++++++++++++++
5 files changed, 27 insertions(+), 6 deletions(-)
rename backend/core/migrations/{0037_riskscenario_ref_id.py => 0039_riskscenario_ref_id.py} (90%)
create mode 100644 frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
diff --git a/backend/core/migrations/0037_riskscenario_ref_id.py b/backend/core/migrations/0039_riskscenario_ref_id.py
similarity index 90%
rename from backend/core/migrations/0037_riskscenario_ref_id.py
rename to backend/core/migrations/0039_riskscenario_ref_id.py
index 520911616..87ae403e9 100644
--- a/backend/core/migrations/0037_riskscenario_ref_id.py
+++ b/backend/core/migrations/0039_riskscenario_ref_id.py
@@ -12,7 +12,7 @@ def get_default_ref_id(risk_assessment):
x.ref_id for x in risk_assessment.risk_scenarios.all() if x.ref_id
]
nb_scenarios = len(scenarios_ref_ids) + 1
- candidates = [f"R.{i}" for i in range(nb_scenarios)]
+ candidates = [f"R.{i+1}" for i in range(nb_scenarios)]
return next(x for x in candidates if x not in scenarios_ref_ids)
for risk_assessment in RiskAssessment.objects.all():
@@ -23,7 +23,7 @@ def get_default_ref_id(risk_assessment):
class Migration(migrations.Migration):
dependencies = [
- ("core", "0036_asset_owner"),
+ ("core", "0038_asset_disaster_recovery_objectives_and_more"),
]
operations = [
diff --git a/backend/core/models.py b/backend/core/models.py
index 39b6ea559..b233437d9 100644
--- a/backend/core/models.py
+++ b/backend/core/models.py
@@ -2242,7 +2242,7 @@ def get_default_ref_id(cls, risk_assessment: RiskAssessment):
"""return associated risk assessment id"""
scenarios_ref_ids = [x.ref_id for x in risk_assessment.risk_scenarios.all()]
nb_scenarios = len(scenarios_ref_ids) + 1
- candidates = [f"R.{i}" for i in range(nb_scenarios)]
+ candidates = [f"R.{i}" for i in range(1, nb_scenarios + 1)]
return next(x for x in candidates if x not in scenarios_ref_ids)
ref_id = models.CharField(
diff --git a/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts b/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
index bb3448819..f22ec3d6f 100644
--- a/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
+++ b/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
@@ -7,7 +7,7 @@ export const GET: RequestHandler = async ({ fetch }) => {
const res = await fetch(endpoint);
if (!res.ok) {
- error(400, 'Error fetching logo');
+ error(400, 'Failed to fetch default ref_id');
}
const logo = await res.json();
diff --git a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
index 55ecf21ae..df5b60e9c 100644
--- a/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/RiskScenarioForm.svelte
@@ -18,7 +18,7 @@
async function fetchDefaultRefId(riskAssessmentId: string) {
try {
const response = await fetch(
- `${BASE_API_URL}/risk-scenarios/default_ref_id/?risk_assessment=${riskAssessmentId}`
+ `/risk-scenarios/default-ref-id/?risk_assessment=${riskAssessmentId}`
);
const result = await response.json();
console.log(result);
@@ -58,7 +58,7 @@
diff --git a/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts b/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
new file mode 100644
index 000000000..0e44cadce
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
@@ -0,0 +1,21 @@
+import { BASE_API_URL } from '$lib/utils/constants';
+
+import { error } from '@sveltejs/kit';
+import type { RequestHandler } from './$types';
+export const GET: RequestHandler = async ({ fetch, url }) => {
+ console.log(url);
+ const riskAssessmentId = url.searchParams.get('risk_assessment');
+ const endpoint = `${BASE_API_URL}/risk-scenarios/default_ref_id/?risk_assessment=${riskAssessmentId}`;
+
+ const res = await fetch(endpoint);
+ if (!res.ok) {
+ error(400, 'Error fetching logo');
+ }
+ const logo = await res.json();
+
+ return new Response(JSON.stringify(logo), {
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+};
From c06f19e16ea335492e94b255943e2e859d5f6a06 Mon Sep 17 00:00:00 2001
From: melinoix
Date: Fri, 22 Nov 2024 12:53:17 +0100
Subject: [PATCH 04/12] corrected files
---
enterprise/backend/enterprise_core/models.py | 2 +-
.../(app)/(internal)/settings/client-settings/logo/+server.ts | 2 +-
.../(app)/(internal)/risk-scenarios/default-ref-id/+server.ts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/enterprise/backend/enterprise_core/models.py b/enterprise/backend/enterprise_core/models.py
index f0cc47590..a4cde30a8 100644
--- a/enterprise/backend/enterprise_core/models.py
+++ b/enterprise/backend/enterprise_core/models.py
@@ -19,7 +19,7 @@ class FileField(Enum):
name = models.CharField(max_length=255, blank=True)
logo = models.ImageField(
- upload_to="",
+ upload_to="client_logos",
null=True,
blank=True,
validators=[FileExtensionValidator(["png", "jpeg", "jpg", "webp", "svg"])],
diff --git a/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts b/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
index f22ec3d6f..bb3448819 100644
--- a/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
+++ b/enterprise/frontend/src/routes/(app)/(internal)/settings/client-settings/logo/+server.ts
@@ -7,7 +7,7 @@ export const GET: RequestHandler = async ({ fetch }) => {
const res = await fetch(endpoint);
if (!res.ok) {
- error(400, 'Failed to fetch default ref_id');
+ error(400, 'Error fetching logo');
}
const logo = await res.json();
diff --git a/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts b/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
index 0e44cadce..036c5a014 100644
--- a/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
+++ b/frontend/src/routes/(app)/(internal)/risk-scenarios/default-ref-id/+server.ts
@@ -9,7 +9,7 @@ export const GET: RequestHandler = async ({ fetch, url }) => {
const res = await fetch(endpoint);
if (!res.ok) {
- error(400, 'Error fetching logo');
+ error(400, 'Failed to fetch default ref_id');
}
const logo = await res.json();
From f3bce17f513e1f1d59062e142c8ed37e7f97fdad Mon Sep 17 00:00:00 2001
From: melinoix
Date: Fri, 22 Nov 2024 12:55:06 +0100
Subject: [PATCH 05/12] corrected file exposure
---
backend/core/views.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/backend/core/views.py b/backend/core/views.py
index c3071732a..90dc8956a 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -1190,7 +1190,10 @@ def default_ref_id(self, request):
default_ref_id = RiskScenario.get_default_ref_id(risk_assessment)
return Response({"results": default_ref_id})
except Exception as e:
- return Response({"error": str(e)}, status=400)
+ logger.error("Error in default_ref_id: %s", str(e))
+ return Response(
+ {"error": "Error in default_ref_id has occurred."}, status=400
+ )
class RiskAcceptanceViewSet(BaseModelViewSet):
From 3457eb88ce20360c81d57d98705abe38224e007f Mon Sep 17 00:00:00 2001
From: melinoix
Date: Fri, 22 Nov 2024 14:02:29 +0100
Subject: [PATCH 06/12] corrected tests
---
backend/app_tests/api/test_api_risk_scenarios.py | 5 +++++
backend/core/tests/test_models.py | 9 ++++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/backend/app_tests/api/test_api_risk_scenarios.py b/backend/app_tests/api/test_api_risk_scenarios.py
index d0c6a30ee..f1c2d6e63 100644
--- a/backend/app_tests/api/test_api_risk_scenarios.py
+++ b/backend/app_tests/api/test_api_risk_scenarios.py
@@ -18,6 +18,7 @@
RISK_SCENARIO_DESCRIPTION = "Test Description"
RISK_SCENARIO_existing_controls = "Test Existing Controls"
RISK_SCENARIO_existing_controls2 = "Test New Existing Controls"
+RISK_SCENARIO_REF_ID = "Test Ref ID"
RISK_SCENARIO_CURRENT_PROBABILITIES = {
"value": 2,
"abbreviation": "H",
@@ -223,6 +224,7 @@ def test_get_risk_scenarios(self, test):
{
"name": RISK_SCENARIO_NAME,
"description": RISK_SCENARIO_DESCRIPTION,
+ "ref_id": RISK_SCENARIO_REF_ID,
"existing_controls": RISK_SCENARIO_existing_controls[0],
"current_proba": RISK_SCENARIO_CURRENT_PROBABILITIES["value"],
"current_impact": RISK_SCENARIO_CURRENT_IMPACT["value"],
@@ -280,6 +282,7 @@ def test_create_risk_scenarios(self, test):
{
"name": RISK_SCENARIO_NAME,
"description": RISK_SCENARIO_DESCRIPTION,
+ "ref_id": RISK_SCENARIO_REF_ID,
"existing_controls": RISK_SCENARIO_existing_controls[0],
"current_proba": RISK_SCENARIO_CURRENT_PROBABILITIES["value"],
"current_impact": RISK_SCENARIO_CURRENT_IMPACT["value"],
@@ -349,6 +352,7 @@ def test_update_risk_scenarios(self, test):
{
"name": RISK_SCENARIO_NAME,
"description": RISK_SCENARIO_DESCRIPTION,
+ "ref_id": RISK_SCENARIO_REF_ID,
"existing_controls": RISK_SCENARIO_existing_controls[0],
"current_proba": RISK_SCENARIO_CURRENT_PROBABILITIES["value"],
"current_impact": RISK_SCENARIO_CURRENT_IMPACT["value"],
@@ -364,6 +368,7 @@ def test_update_risk_scenarios(self, test):
{
"name": "new " + RISK_SCENARIO_NAME,
"description": "new " + RISK_SCENARIO_DESCRIPTION,
+ "ref_id": "new" + RISK_SCENARIO_REF_ID,
"existing_controls": RISK_SCENARIO_existing_controls2[0],
"current_proba": RISK_SCENARIO_CURRENT_PROBABILITIES2["value"],
"current_impact": RISK_SCENARIO_CURRENT_IMPACT2["value"],
diff --git a/backend/core/tests/test_models.py b/backend/core/tests/test_models.py
index b9ab44ca7..91dc191e5 100644
--- a/backend/core/tests/test_models.py
+++ b/backend/core/tests/test_models.py
@@ -585,22 +585,25 @@ def test_risk_scenario_rid_is_deterministic(self):
scenario = RiskScenario.objects.create(
name="test scenario",
description="test scenario description",
+ ref_id="R.1",
risk_assessment=risk_assessment,
)
scenario2 = RiskScenario.objects.create(
name="test scenario 2",
description="test scenario description",
+ ref_id="R.2",
risk_assessment=risk_assessment,
)
scenario3 = RiskScenario.objects.create(
name="test scenario 3",
description="test scenario description",
+ ref_id="R.3",
risk_assessment=risk_assessment,
)
- assert scenario.rid == "R.1"
- assert scenario2.rid == "R.2"
- assert scenario3.rid == "R.3"
+ assert scenario.ref_id == "R.1"
+ assert scenario2.ref_id == "R.2"
+ assert scenario3.ref_id == "R.3"
@pytest.mark.django_db
From 8fd3a5c93a61fcb897d859b5ac26d77a06d3b52c Mon Sep 17 00:00:00 2001
From: Nassim Tabchiche
Date: Sat, 23 Nov 2024 15:56:09 +0100
Subject: [PATCH 07/12] Set RiskScenario.ref_id max length to 8 characters
---
backend/core/migrations/0039_riskscenario_ref_id.py | 2 +-
backend/core/models.py | 4 +---
frontend/src/lib/utils/schemas.ts | 2 +-
3 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/backend/core/migrations/0039_riskscenario_ref_id.py b/backend/core/migrations/0039_riskscenario_ref_id.py
index 87ae403e9..d1e0f1d92 100644
--- a/backend/core/migrations/0039_riskscenario_ref_id.py
+++ b/backend/core/migrations/0039_riskscenario_ref_id.py
@@ -31,7 +31,7 @@ class Migration(migrations.Migration):
model_name="riskscenario",
name="ref_id",
field=models.CharField(
- default="", max_length=100, verbose_name="Reference ID"
+ default="", max_length=8, verbose_name="Reference ID"
),
preserve_default=False,
),
diff --git a/backend/core/models.py b/backend/core/models.py
index dd4893db4..c2ce37a46 100644
--- a/backend/core/models.py
+++ b/backend/core/models.py
@@ -2243,9 +2243,7 @@ def get_default_ref_id(cls, risk_assessment: RiskAssessment):
candidates = [f"R.{i}" for i in range(1, nb_scenarios + 1)]
return next(x for x in candidates if x not in scenarios_ref_ids)
- ref_id = models.CharField(
- max_length=100, blank=False, verbose_name=_("Reference ID")
- )
+ ref_id = models.CharField(max_length=8, blank=False, verbose_name=_("Reference ID"))
qualifications = models.JSONField(default=list, verbose_name=_("Qualifications"))
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index 291ceb375..7ce262432 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -119,7 +119,7 @@ export const RiskScenarioSchema = baseNamedObject({
assets: z.string().uuid().optional().array().optional(),
vulnerabilities: z.string().uuid().optional().array().optional(),
owner: z.string().uuid().optional().array().optional(),
- ref_id: z.string()
+ ref_id: z.string().max(8).optional().nullable()
});
export const AppliedControlSchema = baseNamedObject({
From 5cb0a3eb65628c3c86ff52cc94c09b3b6949677b Mon Sep 17 00:00:00 2001
From: Nassim Tabchiche
Date: Sat, 23 Nov 2024 16:06:00 +0100
Subject: [PATCH 08/12] Add classesContainer prop to TextField component
---
frontend/src/lib/components/Forms/TextField.svelte | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frontend/src/lib/components/Forms/TextField.svelte b/frontend/src/lib/components/Forms/TextField.svelte
index b244e1253..97ea45c96 100644
--- a/frontend/src/lib/components/Forms/TextField.svelte
+++ b/frontend/src/lib/components/Forms/TextField.svelte
@@ -3,9 +3,11 @@
import { onMount } from 'svelte';
import type { CacheLock } from '$lib/utils/types';
import { safeTranslate } from '$lib/utils/i18n';
+ import type { CssClasses } from '@skeletonlabs/skeleton';
let _class = '';
export { _class as class };
+ export let classesContainer: CssClasses = '';
export let label: string | undefined = undefined;
export let field: string;
export let helpText: string | undefined = undefined;
@@ -33,7 +35,7 @@
$: classesDisabled = (d: boolean) => (d ? 'opacity-50' : '');
-
+
{#if label !== undefined && !hidden}
{#if $constraints?.required || required}
From 1e0bcd91ff5935b7e4cb507e45487da9bd3e18db Mon Sep 17 00:00:00 2001
From: Nassim Tabchiche
Date: Sat, 23 Nov 2024 16:06:11 +0100
Subject: [PATCH 09/12] Add ref_id field to risk scenario update form
---
.../(internal)/risk-scenarios/[id=uuid]/edit/+page.svelte | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.svelte b/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.svelte
index f8d2b42d0..0508120fe 100644
--- a/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.svelte
@@ -177,7 +177,10 @@