diff --git a/backend/ebios_rm/helpers.py b/backend/ebios_rm/helpers.py
new file mode 100644
index 000000000..efd2d7779
--- /dev/null
+++ b/backend/ebios_rm/helpers.py
@@ -0,0 +1,87 @@
+from django.db.models.query import QuerySet
+import math
+
+
+def ecosystem_radar_chart_data(stakeholders_queryset: QuerySet):
+ qs = stakeholders_queryset
+
+ def get_exposure_segment_id(value):
+ if value < 3:
+ return 1
+ if value >= 3 and value < 7:
+ return 2
+ if value >= 7 and value <= 9:
+ return 3
+ if value > 9:
+ return 4
+ return 0
+
+ def get_reliability_cluster(value):
+ if value < 4:
+ return "clst1"
+ if value >= 4 and value < 6:
+ return "clst2"
+ if value >= 6 and value <= 7:
+ return "clst3"
+ if value > 7:
+ return "clst4"
+ return 1
+
+ """
+ // data format: f1-f4 (fiabilité cyber = maturité x confiance ) to get the clusters and colors
+ // x,y, z
+ // x: criticité calculée avec cap à 5,5
+ // y: the angle (output of dict to make sure they end up on the right quadrant, min: 45, max:-45) -> done on BE
+ // z: the size of item (exposition = dependence x penetration) based on a dict, -> done on BE
+ // label: name of the 3rd party entity
+ Angles start at 56,25 (45+45/4) and end at -45-45/4 = 303,75
+ """
+
+ c_data = {"clst1": [], "clst2": [], "clst3": [], "clst4": []}
+ r_data = {"clst1": [], "clst2": [], "clst3": [], "clst4": []}
+ angle_offsets = {"client": 135, "partner": 225, "supplier": 45}
+
+ cnt_c_not_displayed = 0
+ cnt_r_not_displayed = 0
+ for sh in qs:
+ # current
+ c_reliability = sh.current_maturity * sh.current_trust
+ c_exposure = sh.current_dependency * sh.current_penetration
+ c_exposure_val = get_exposure_segment_id(c_exposure) * 4
+
+ c_criticality = (
+ math.floor(sh.current_criticality * 100) / 100.0
+ if sh.current_criticality <= 5
+ else 5.25
+ )
+
+ angle = angle_offsets[sh.category] + (
+ get_exposure_segment_id(c_exposure) * (45 / 4)
+ )
+
+ vector = [c_criticality, angle, c_exposure_val, str(sh)]
+
+ cluser_id = get_reliability_cluster(c_reliability)
+ c_data[cluser_id].append(vector)
+
+ # residual
+ r_reliability = sh.residual_maturity * sh.residual_trust
+ r_exposure = sh.residual_dependency * sh.residual_penetration
+ r_exposure_val = get_exposure_segment_id(r_exposure) * 4
+
+ r_criticality = (
+ math.floor(sh.residual_criticality * 100) / 100.0
+ if sh.residual_criticality <= 5
+ else 5.25
+ )
+
+ angle = angle_offsets[sh.category] + (
+ get_exposure_segment_id(r_exposure) * (45 / 4)
+ )
+
+ vector = [r_criticality, angle, r_exposure_val, str(sh)]
+
+ cluser_id = get_reliability_cluster(r_reliability)
+ r_data[cluser_id].append(vector)
+
+ return {"current": c_data, "residual": r_data}
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 8477fab8b..bbb46688b 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -477,7 +477,7 @@ def get_scope(self):
return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
def __str__(self):
- return f"{self.entity.name} - {self.get_category_display()}"
+ return f"{self.entity.name}-{self.get_category_display()}"
def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index 7f5786329..d1e78f9ab 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -1,7 +1,7 @@
import django_filters as df
from core.serializers import RiskMatrixReadSerializer
from core.views import BaseModelViewSet as AbstractBaseModelViewSet
-from core.serializers import RiskMatrixReadSerializer
+from .helpers import ecosystem_radar_chart_data
from .models import (
EbiosRMStudy,
FearedEvent,
@@ -19,8 +19,6 @@
LONG_CACHE_TTL = 60 # mn
-import math
-
class BaseModelViewSet(AbstractBaseModelViewSet):
serializers_module = "ebios_rm.serializers"
@@ -86,6 +84,12 @@ def update_workshop_step_status(self, request, pk, workshop, step):
)
return Response(EbiosRMStudyReadSerializer(ebios_rm_study).data)
+ @action(detail=True, name="Get ecosystem radar chart data")
+ def ecosystem_chart_data(self, request, pk):
+ return Response(
+ ecosystem_radar_chart_data(Stakeholder.objects.filter(ebios_rm_study=pk))
+ )
+
class FearedEventViewSet(BaseModelViewSet):
model = FearedEvent
@@ -161,89 +165,7 @@ def category(self, request):
@action(detail=False, name="Get chart data")
def chart_data(self, request):
- def get_exposure_segment_id(value):
- if value < 3:
- return 1
- if value >= 3 and value < 7:
- return 2
- if value >= 7 and value <= 9:
- return 3
- if value > 9:
- return 4
- return 0
-
- def get_reliability_cluster(value):
- if value < 4:
- return "clst1"
- if value >= 4 and value < 6:
- return "clst2"
- if value >= 6 and value <= 7:
- return "clst3"
- if value > 7:
- return "clst4"
- return 1
-
- """
- // data format: f1-f4 (fiabilité cyber = maturité x confiance ) to get the clusters and colors
- // x,y, z
- // x: criticité calculée avec cap à 5,5
- // y: the angle (output of dict to make sure they end up on the right quadrant, min: 45, max:-45) -> done on BE
- // z: the size of item (exposition = dependence x penetration) based on a dict, -> done on BE
- // label: name of the 3rd party entity
- Angles start at 56,25 (45+45/4) and end at -45-45/4 = 303,75
- """
-
- # we can add a filter on the Stakeholder concerned by the ebios study here
- qs = Stakeholder.objects.all()
-
- c_data = {"clst1": [], "clst2": [], "clst3": [], "clst4": []}
- r_data = {"clst1": [], "clst2": [], "clst3": [], "clst4": []}
- angle_offsets = {"client": 135, "partner": 225, "supplier": 45}
-
- cnt_c_not_displayed = 0
- cnt_r_not_displayed = 0
- for sh in qs:
- # current
- c_reliability = sh.current_maturity * sh.current_trust
- c_exposure = sh.current_dependency * sh.current_penetration
- c_exposure_val = get_exposure_segment_id(c_exposure) * 4
-
- c_criticality = (
- math.floor(sh.current_criticality * 100) / 100.0
- if sh.current_criticality <= 5
- else 5.25
- )
-
- angle = angle_offsets[sh.category] + (
- get_exposure_segment_id(c_exposure) * (45 / 4)
- )
-
- vector = [c_criticality, angle, c_exposure_val, str(sh)]
-
- cluser_id = get_reliability_cluster(c_reliability)
- c_data[cluser_id].append(vector)
-
- # residual
- r_reliability = sh.residual_maturity * sh.residual_trust
- r_exposure = sh.residual_dependency * sh.residual_penetration
- r_exposure_val = get_exposure_segment_id(r_exposure) * 4
-
- r_criticality = (
- math.floor(sh.residual_criticality * 100) / 100.0
- if sh.residual_criticality <= 5
- else 5.25
- )
-
- angle = angle_offsets[sh.category] + (
- get_exposure_segment_id(r_exposure) * (45 / 4)
- )
-
- vector = [r_criticality, angle, r_exposure_val, str(sh)]
-
- cluser_id = get_reliability_cluster(r_reliability)
- r_data[cluser_id].append(vector)
-
- return Response({"current": c_data, "residual": r_data})
+ return Response(ecosystem_radar_chart_data(Stakeholder.objects.all()))
class StrategicScenarioViewSet(BaseModelViewSet):
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index a94439d61..422da66de 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -1019,8 +1019,11 @@
"markAsInProgress": "Mark as in progress",
"riskAnalyses": "Risk analyses",
"client": "Client",
+ "clients": "Clients",
"partner": "Partner",
+ "partners": "Partners",
"supplier": "Supplier",
+ "suppliers": "Suppliers",
"referenceEntity": "Reference entity",
"referenceEntitySemiColon": "Reference entity:",
"moderate": "Moderate",
@@ -1067,5 +1070,8 @@
"operationalScenarioThreatsHelpText": "Unitary actions carried out by a risk source on a critical support asset as part of an operational scenario",
"operationalScenarioIsSelectedHelpText": "Selection of the operational scenario for the study",
"attackPathStakeholdersHelpText": "Stakeholders involved in the attack path",
- "attackPathIsSelectedHelpText": "Selection of the attack path for the study"
+ "attackPathIsSelectedHelpText": "Selection of the attack path for the study",
+ "ecosystemRadar": "Ecosystem radar",
+ "criticalitySemiColon": "Criticality:",
+ "cyberFiability": "Cyber fiability"
}
diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json
index 164389a7a..f4a655fee 100644
--- a/frontend/messages/fr.json
+++ b/frontend/messages/fr.json
@@ -1019,8 +1019,11 @@
"markAsInProgress": "Reprendre",
"riskAnalyses": "Analyses de risques",
"client": "Client",
+ "clients": "Clients",
"partner": "Partenaire",
+ "partners": "Partenaires",
"supplier": "Fournisseur",
+ "suppliers": "Fournisseurs",
"referenceEntity": "Entité de référence",
"referenceEntitySemiColon": "Entité de référence :",
"moderate": "Modérée",
@@ -1067,5 +1070,8 @@
"operationalScenarioThreatsHelpText": "Actions élémentaires réalisées par une source de risque sur un bien support critique dans le cadre d'un scénario opérationnel",
"operationalScenarioIsSelectedHelpText": "Sélection du scénario opérationnel pour l'étude",
"attackPathStakeholdersHelpText": "Parties prenantes impactées par le chemin d'attaque",
- "attackPathIsSelectedHelpText": "Sélection du chemin d'attaque pour l'étude"
+ "attackPathIsSelectedHelpText": "Sélection du chemin d'attaque pour l'étude",
+ "ecosystemRadar": "Radar de l'écosystème",
+ "criticalitySemiColon": "Criticité :",
+ "cyberFiability": "Fiabilité cyber"
}
diff --git a/frontend/src/lib/components/Chart/EcosystemRadarChart.svelte b/frontend/src/lib/components/Chart/EcosystemRadarChart.svelte
index df867d697..dbe9b1cb9 100644
--- a/frontend/src/lib/components/Chart/EcosystemRadarChart.svelte
+++ b/frontend/src/lib/components/Chart/EcosystemRadarChart.svelte
@@ -1,8 +1,7 @@
-