Skip to content

Commit

Permalink
Feat/add enterprise ebios reference entity (#1217)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohamed-Hacene authored Dec 20, 2024
2 parents 3386022 + 909a073 commit 348dd2a
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 40 deletions.
2 changes: 1 addition & 1 deletion backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,7 @@ def get_descendants(self) -> set[Self]:
children = self.get_children()
sub_children = set()
for child in children:
sub_children.append(child)
sub_children.add(child)
sub_children.update(child.get_descendants())
return sub_children

Expand Down
3 changes: 2 additions & 1 deletion backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,11 @@ class RiskAssessmentReadSerializer(AssessmentReadSerializer):
risk_scenarios = FieldsRelatedField(many=True)
risk_scenarios_count = serializers.IntegerField(source="risk_scenarios.count")
risk_matrix = FieldsRelatedField()
ebios_rm_study = FieldsRelatedField(["id", "name"])

class Meta:
model = RiskAssessment
exclude = ["ebios_rm_study"]
exclude = []


class AssetWriteSerializer(BaseModelSerializer):
Expand Down
29 changes: 29 additions & 0 deletions backend/ebios_rm/migrations/0009_alter_roto_activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 5.1.4 on 2024-12-20 12:16

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("ebios_rm", "0008_remove_attackpath_ro_to_couple_strategicscenario_and_more"),
]

operations = [
migrations.AlterField(
model_name="roto",
name="activity",
field=models.PositiveSmallIntegerField(
choices=[
(0, "undefined"),
(1, "very_low"),
(2, "low"),
(3, "moderate"),
(4, "important"),
],
default=0,
validators=[django.core.validators.MaxValueValidator(4)],
verbose_name="Activity",
),
),
]
14 changes: 12 additions & 2 deletions backend/ebios_rm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ class Resources(models.IntegerChoices):
IMPORTANT = 3, "important"
UNLIMITED = 4, "unlimited"

class Activity(models.IntegerChoices):
UNDEFINED = 0, "undefined"
VERY_LOW = 1, "very_low"
LOW = 2, "low"
MODERATE = 3, "moderate"
IMPORTANT = 4, "important"

class Pertinence(models.IntegerChoices):
UNDEFINED = 0, "undefined"
IRRELAVANT = 1, "irrelevant"
Expand Down Expand Up @@ -306,7 +313,10 @@ class Pertinence(models.IntegerChoices):
default=Resources.UNDEFINED,
)
activity = models.PositiveSmallIntegerField(
verbose_name=_("Activity"), default=0, validators=[MaxValueValidator(4)]
verbose_name=_("Activity"),
choices=Activity.choices,
default=Activity.UNDEFINED,
validators=[MaxValueValidator(4)],
)
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
Expand Down Expand Up @@ -645,7 +655,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.filter(is_selected=True)
)
assets = set()
for asset in initial_assets:
Expand Down
2 changes: 2 additions & 0 deletions backend/ebios_rm/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class EbiosRMStudyReadSerializer(BaseModelSerializer):
str = serializers.CharField(source="__str__")
project = FieldsRelatedField(["id", "folder"])
folder = FieldsRelatedField()
reference_entity = FieldsRelatedField()
risk_matrix = FieldsRelatedField()
reference_entity = FieldsRelatedField()
assets = FieldsRelatedField(many=True)
Expand Down Expand Up @@ -97,6 +98,7 @@ class RoToReadSerializer(BaseModelSerializer):

motivation = serializers.CharField(source="get_motivation_display")
resources = serializers.CharField(source="get_resources_display")
activity = serializers.CharField(source="get_activity_display")
pertinence = serializers.CharField(source="get_pertinence")

class Meta:
Expand Down
8 changes: 6 additions & 2 deletions backend/ebios_rm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def update_workshop_step_status(self, request, pk, workshop, step):
class FearedEventViewSet(BaseModelViewSet):
model = FearedEvent

filterset_fields = ["ebios_rm_study", "ro_to_couples"]
filterset_fields = ["ebios_rm_study", "ro_to_couples", "is_selected"]

@action(detail=True, name="Get risk matrix", url_path="risk-matrix")
def risk_matrix(self, request, pk=None):
Expand Down Expand Up @@ -140,6 +140,10 @@ def motivation(self, request):
def resources(self, request):
return Response(dict(RoTo.Resources.choices))

@action(detail=False, name="Get activity choices")
def activity(self, request):
return Response(dict(RoTo.Activity.choices))


class StakeholderViewSet(BaseModelViewSet):
model = Stakeholder
Expand Down Expand Up @@ -172,7 +176,7 @@ def is_used(self, queryset, name, value):

class Meta:
model = AttackPath
fields = ["ebios_rm_study", "is_selected", "used"]
fields = ["ebios_rm_study", "is_selected", "used", "strategic_scenario"]


class AttackPathViewSet(BaseModelViewSet):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<script lang="ts">
import type { SuperValidated } from 'sveltekit-superforms';
import type { ModelInfo, CacheLock } from '$lib/utils/types';
import TextField from '$lib/components/Forms/TextField.svelte';
import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';
import * as m from '$paraglide/messages.js';
import { getOptions } from '$lib/utils/crud';
import TextArea from '../TextArea.svelte';
import { page } from '$app/stores';
export let form: SuperValidated<any>;
export let model: ModelInfo;
export let cacheLocks: Record<string, CacheLock> = {};
export let formDataCache: Record<string, any> = {};
export let initialData: Record<string, any> = {};
export let context: string;
let activeActivity: string | null = null;
$page.url.searchParams.forEach((value, key) => {
if (key === 'activity' && value === 'one') {
activeActivity = 'one';
} else if (key === 'activity' && value === 'two') {
activeActivity = 'two';
}
});
</script>

{#if context != 'selectAudit'}
<TextField
{form}
field="name"
label={m.name()}
cacheLock={cacheLocks['name']}
bind:cachedValue={formDataCache['name']}
data-focusindex="0"
/>
{/if}
{#if context !== 'ebiosRmStudy' && context !== 'selectAudit'}
<TextField
{form}
field="version"
label={m.version()}
cacheLock={cacheLocks['version']}
bind:cachedValue={formDataCache['version']}
/>
<TextField
{form}
field="ref_id"
label={m.refId()}
cacheLock={cacheLocks['ref_id']}
bind:cachedValue={formDataCache['ref_id']}
/>
<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['folder'] })}
field="folder"
cacheLock={cacheLocks['folder']}
bind:cachedValue={formDataCache['folder']}
label={m.domain()}
hidden={initialData.folder}
/>
<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['reference_entity'] })}
field="reference_entity"
cacheLock={cacheLocks['reference_entity']}
bind:cachedValue={formDataCache['reference_entity']}
label={m.referenceEntity()}
hidden={initialData.reference_entity}
/>
<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['risk_matrix'] })}
field="risk_matrix"
cacheLock={cacheLocks['risk_matrix']}
bind:cachedValue={formDataCache['risk_matrix']}
label={m.riskMatrix()}
placeholder={m.ebiosRmRiskMatrix()}
helpText={m.ebiosRmMatrixHelpText()}
/>
{:else if context === 'ebiosRmStudy'}
<div
class="relative p-2 space-y-2 rounded-md {activeActivity === 'one'
? 'border-2 border-primary-500'
: 'border-2 border-gray-300 border-dashed'}"
>
<p
class="absolute -top-3 bg-white font-bold {activeActivity === 'one'
? 'text-primary-500'
: 'text-gray-500'}"
>
{m.activityOne()}
</p>
<TextArea
{form}
field="description"
label={m.description()}
cacheLock={cacheLocks['description']}
bind:cachedValue={formDataCache['description']}
data-focusindex="1"
/>
<TextField
{form}
field="version"
label={m.version()}
cacheLock={cacheLocks['version']}
bind:cachedValue={formDataCache['version']}
/>
<TextField
{form}
field="ref_id"
label={m.refId()}
cacheLock={cacheLocks['ref_id']}
bind:cachedValue={formDataCache['ref_id']}
/>
<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['reference_entity'] })}
field="reference_entity"
cacheLock={cacheLocks['reference_entity']}
bind:cachedValue={formDataCache['reference_entity']}
label={m.referenceEntity()}
hidden={initialData.reference_entity}
/>
<AutocompleteSelect
multiple
{form}
options={getOptions({ objects: model.foreignKeys['authors'], label: 'email' })}
field="authors"
cacheLock={cacheLocks['authors']}
bind:cachedValue={formDataCache['authors']}
label={m.authors()}
/>
<AutocompleteSelect
multiple
{form}
options={getOptions({ objects: model.foreignKeys['reviewers'], label: 'email' })}
field="reviewers"
cacheLock={cacheLocks['reviewers']}
bind:cachedValue={formDataCache['reviewers']}
label={m.reviewers()}
/>
</div>
<div
class="relative p-2 space-y-2 rounded-md {activeActivity === 'two'
? 'border-2 border-primary-500'
: 'border-2 border-gray-300 border-dashed'}"
>
<p
class="absolute -top-3 bg-white font-bold {activeActivity === 'two'
? 'text-primary-500'
: 'text-gray-500'}"
>
{m.activityTwo()}
</p>
<AutocompleteSelect
multiple
{form}
options={getOptions({
objects: model.foreignKeys['assets'],
extra_fields: [['folder', 'str']],
label: 'auto'
})}
field="assets"
label={m.assets()}
/>
</div>
<TextArea
{form}
field="observation"
label={m.observation()}
cacheLock={cacheLocks['observation']}
bind:cachedValue={formDataCache['observation']}
/>
{:else}
<AutocompleteSelect
multiple
{form}
options={getOptions({ objects: model.foreignKeys['compliance_assessments'] })}
field="compliance_assessments"
cacheLock={cacheLocks['compliance_assessments']}
bind:cachedValue={formDataCache['compliance_assessments']}
label={m.complianceAssessment()}
/>
{/if}
10 changes: 9 additions & 1 deletion frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1013,5 +1013,13 @@
"goBackToEbiosRmStudy": "Go back to Ebios RM study",
"addStrategicScenario": "Add strategic scenario",
"markAsDone": "Mark as done",
"markAsInProgress": "Mark as in progress"
"markAsInProgress": "Mark as in progress",
"ebiosRmRiskMatrix": "4x4 risk matrix from EBIOS-RM",
"riskAnalyses": "Risk analyses",
"client": "Client",
"partner": "Partner",
"supplier": "Supplier",
"referenceEntity": "Reference entity",
"referenceEntitySemiColon": "Reference entity:",
"moderate": "Moderate"
}
8 changes: 7 additions & 1 deletion frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1011,5 +1011,11 @@
"strategicScenario": "Scénario stratégique",
"strategicScenarios": "Scénarios stratégiques",
"goBackToEbiosRmStudy": "Retour à l'étude",
"addStrategicScenario": "Ajouter un scénario stratégique"
"addStrategicScenario": "Ajouter un scénario stratégique",
"client": "Client",
"partner": "Partenaire",
"supplier": "Fournisseur",
"referenceEntity": "Entité de référence",
"referenceEntitySemiColon": "Entité de référence :",
"moderate": "Modérée"
}
5 changes: 4 additions & 1 deletion frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
let crumbs: Array<{ label: string; href: string; icon?: string }> = [];
const disableWorkhopLink = ['workshop1', 'workshop2', 'workshop3', 'workshop4', 'workshop5']; // Disable workshops links in breadcrumb
$: {
// Remove zero-length tokens.
const tokens = $page.url.pathname.split('/').filter((t) => t !== '');
Expand All @@ -35,7 +37,8 @@
label: $page.data.label || t,
href:
Object.keys(listViewFields).includes(tokens[0]) &&
!listViewFields[tokens[0]].breadcrumb_link_disabled
!listViewFields[tokens[0]].breadcrumb_link_disabled &&
!disableWorkhopLink.includes(t) // Disable workshops links in breadcrumb
? tokenPath
: null
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/DetailView/DetailView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@
<a href={value} target="_blank" class="anchor">{value}</a>
{:else if ISO_8601_REGEX.test(value) && (key === 'created_at' || key === 'updated_at' || key === 'expiry_date' || key === 'accepted_at' || key === 'rejected_at' || key === 'revoked_at' || key === 'eta')}
{formatDateOrDateTime(value, languageTag())}
{:else if m[toCamelCase((value.str || value.name) ?? value)]}
{:else if m[toCamelCase(value.str || value.name)]}
{safeTranslate((value.str || value.name) ?? value)}
{:else}
{(value.str || value.name) ?? value}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
cacheLock={cacheLocks['risk_matrix']}
bind:cachedValue={formDataCache['risk_matrix']}
label={m.riskMatrix()}
placeholder={m.ebiosRmRiskMatrix()}
helpText={m.ebiosRmMatrixHelpText()}
/>
{:else if context === 'ebiosRmStudy'}
Expand Down
Loading

0 comments on commit 348dd2a

Please sign in to comment.