Skip to content

Commit

Permalink
feat: filter stakeholders in study ecosystem chart
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohamed-Hacene committed Dec 26, 2024
1 parent fc4bb86 commit 3f9201d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 90 deletions.
86 changes: 86 additions & 0 deletions backend/ebios_rm/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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}
92 changes: 6 additions & 86 deletions backend/ebios_rm/views.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -19,8 +19,6 @@

LONG_CACHE_TTL = 60 # mn

import math


class BaseModelViewSet(AbstractBaseModelViewSet):
serializers_module = "ebios_rm.serializers"
Expand Down Expand Up @@ -85,6 +83,10 @@ def update_workshop_step_status(self, request, pk, workshop, step):
workshop, step, new_status=request.data.get("status", "in_progress")
)
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):
Expand Down Expand Up @@ -161,89 +163,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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
meta: data // metaData
};

const radarEndpoint = `${BASE_API_URL}/ebios-rm/stakeholders/chart_data/`;
const radarEndpoint = `${BASE_API_URL}/ebios-rm/studies/${params.id}/ecosystem_chart_data/`;

const radarRes = await fetch(radarEndpoint);
const radar = await radarRes.json();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
</script>

<div class="space-y-2">
<Accordion class="bg-white rounded-md border hover:text-primary-700" hover="bg-white">
<Accordion class="bg-white rounded-md border hover:text-primary-700 text-gray-800" hover="bg-white">
<AccordionItem>
<svelte:fragment slot="lead"><i class="fa-solid fa-bullseye"></i></svelte:fragment>
<svelte:fragment slot="summary">{m.ecosystemRadar()}</svelte:fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
import type { PageData } from './$types';
export let data: PageData;
import EcosystemRadarChart from '$lib/components/Chart/EcosystemRadarChart.svelte';
import * as m from '$paraglide/messages.js';
</script>

<div class="bg-white shadow flex overflow-x-auto">
<div class="w-full h-screen">
<EcosystemRadarChart title="Ecosystem - current" name="c_ecosystem" data={data.data.current} />
<EcosystemRadarChart title={m.current()} name="c_ecosystem" data={data.data.current} />
<EcosystemRadarChart
title="Ecosystem - residual"
title={m.residual()}
name="r_ecosystem"
data={data.data.residual}
/>
Expand Down

0 comments on commit 3f9201d

Please sign in to comment.