Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add enterprise ebios reference entity #1217

Merged
merged 24 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8163a97
feat: filter selected feared events in ro-to form
Mohamed-Hacene Dec 20, 2024
b4abf53
feat: add ebios rm risk matrix placeholder
Mohamed-Hacene Dec 20, 2024
1dff57d
feat: add activity choices
Mohamed-Hacene Dec 20, 2024
bd30973
feat: disable workshop links in breadcrumbs
Mohamed-Hacene Dec 20, 2024
4c38ba5
feat: add icons for true/false
Mohamed-Hacene Dec 20, 2024
cbe6a28
fix: add missing safeTranslate
Mohamed-Hacene Dec 20, 2024
c2579d5
fix: risk assessment generation
Mohamed-Hacene Dec 20, 2024
c265d76
chore: add missing translation
Mohamed-Hacene Dec 20, 2024
2988eb9
chore: add missing translation
Mohamed-Hacene Dec 20, 2024
c81796b
fix: update functional tests
Mohamed-Hacene Dec 20, 2024
69dc6a7
feat: add back to study anchors
Mohamed-Hacene Dec 20, 2024
fd2ec42
fix: typo in test id
Mohamed-Hacene Dec 20, 2024
15ada98
fix: functional tests
Mohamed-Hacene Dec 20, 2024
e5bc1f3
chore: format
Mohamed-Hacene Dec 20, 2024
91ab717
feat: add reference entity field for enterprise ebios
Mohamed-Hacene Dec 20, 2024
05b014e
chore: always display reference entity
Mohamed-Hacene Dec 20, 2024
b2da031
chore: missing translation
Mohamed-Hacene Dec 20, 2024
d97f224
feat: filter attack paths by scenarios
Mohamed-Hacene Dec 20, 2024
caf1a76
style: improve table layout
Mohamed-Hacene Dec 20, 2024
a97f3da
chore: format
Mohamed-Hacene Dec 20, 2024
917f4e2
Revert "style: improve table layout"
Mohamed-Hacene Dec 20, 2024
f41693e
fix: some steps status
Mohamed-Hacene Dec 20, 2024
b0e3baf
feat: add true/false icon margin left
Mohamed-Hacene Dec 20, 2024
909a073
typo: change margin
Mohamed-Hacene Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading