diff --git a/backend/app_tests/api/test_api_requirement_assessments.py b/backend/app_tests/api/test_api_requirement_assessments.py index ef49c83e1..12dad4661 100644 --- a/backend/app_tests/api/test_api_requirement_assessments.py +++ b/backend/app_tests/api/test_api_requirement_assessments.py @@ -124,7 +124,48 @@ def test_get_requirement_assessments(self, test): "id": str(compliance_assessment.id), "str": compliance_assessment.name, }, - "requirement": str(RequirementNode.objects.all()[0].id), + "requirement": { + "str": str(RequirementNode.objects.all()[0]), + "id": str(RequirementNode.objects.all()[0].id), + "urn": RequirementNode.objects.all()[0].urn, + "annotation": RequirementNode.objects.all()[0].annotation, + "name": RequirementNode.objects.all()[0].name, + "description": RequirementNode.objects.all()[0].description, + "typical_evidence": RequirementNode.objects.all()[ + 0 + ].typical_evidence, + "ref_id": RequirementNode.objects.all()[0].ref_id, + "associated_reference_controls": RequirementNode.objects.all()[ + 0 + ].associated_reference_controls, + "associated_threats": RequirementNode.objects.all()[ + 0 + ].associated_threats, + "parent_requirement": { + "str": RequirementNode.objects.all()[0].parent_requirement.get( + "str" + ), + "urn": RequirementNode.objects.all()[0].parent_requirement.get( + "urn" + ), + "id": str( + RequirementNode.objects.all()[0].parent_requirement.get( + "id" + ) + ), + "ref_id": RequirementNode.objects.all()[ + 0 + ].parent_requirement.get("ref_id"), + "name": RequirementNode.objects.all()[0].parent_requirement.get( + "name" + ), + "description": RequirementNode.objects.all()[ + 0 + ].parent_requirement.get("description"), + } + if RequirementNode.objects.all()[0].parent_requirement + else None, + }, }, base_count=-1, user_group=test.user_group, @@ -210,7 +251,48 @@ def test_update_requirement_assessments(self, test): "id": str(compliance_assessment.id), "str": compliance_assessment.name, }, - "requirement": str(RequirementNode.objects.all()[0].id), + "requirement": { + "str": str(RequirementNode.objects.all()[0]), + "id": str(RequirementNode.objects.all()[0].id), + "urn": RequirementNode.objects.all()[0].urn, + "annotation": RequirementNode.objects.all()[0].annotation, + "name": RequirementNode.objects.all()[0].name, + "description": RequirementNode.objects.all()[0].description, + "typical_evidence": RequirementNode.objects.all()[ + 0 + ].typical_evidence, + "ref_id": RequirementNode.objects.all()[0].ref_id, + "associated_reference_controls": RequirementNode.objects.all()[ + 0 + ].associated_reference_controls, + "associated_threats": RequirementNode.objects.all()[ + 0 + ].associated_threats, + "parent_requirement": { + "str": RequirementNode.objects.all()[0].parent_requirement.get( + "str" + ), + "urn": RequirementNode.objects.all()[0].parent_requirement.get( + "urn" + ), + "id": str( + RequirementNode.objects.all()[0].parent_requirement.get( + "id" + ) + ), + "ref_id": RequirementNode.objects.all()[ + 0 + ].parent_requirement.get("ref_id"), + "name": RequirementNode.objects.all()[0].parent_requirement.get( + "name" + ), + "description": RequirementNode.objects.all()[ + 0 + ].parent_requirement.get("description"), + } + if RequirementNode.objects.all()[0].parent_requirement + else None, + }, }, user_group=test.user_group, ) diff --git a/backend/core/models.py b/backend/core/models.py index a2f2253e5..096bbc79e 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -1049,6 +1049,40 @@ class RequirementNode(ReferentialObjectMixin, I18nObjectMixin): ) question = models.JSONField(blank=True, null=True, verbose_name=_("Question")) + @property + def associated_reference_controls(self): + _reference_controls = self.reference_controls.all() + reference_controls = [] + for control in _reference_controls: + reference_controls.append( + {"str": control.display_long, "urn": control.urn, "id": control.id} + ) + return reference_controls + + @property + def associated_threats(self): + _threats = self.threats.all() + threats = [] + for control in _threats: + threats.append( + {"str": control.display_long, "urn": control.urn, "id": control.id} + ) + return threats + + @property + def parent_requirement(self): + parent_requirement = RequirementNode.objects.filter(urn=self.parent_urn).first() + if not parent_requirement: + return None + return { + "str": parent_requirement.display_long, + "urn": parent_requirement.urn, + "id": parent_requirement.id, + "ref_id": parent_requirement.ref_id, + "name": parent_requirement.name, + "description": parent_requirement.description, + } + class Meta: verbose_name = _("RequirementNode") verbose_name_plural = _("RequirementNodes") diff --git a/backend/core/serializers.py b/backend/core/serializers.py index e42d8c9e2..1b2661a14 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -612,6 +612,20 @@ class RequirementAssessmentReadSerializer(BaseModelSerializer): compliance_assessment = FieldsRelatedField() folder = FieldsRelatedField() assessable = serializers.BooleanField(source="requirement.assessable") + requirement = FieldsRelatedField( + [ + "id", + "urn", + "annotation", + "name", + "description", + "typical_evidence", + "ref_id", + "associated_reference_controls", + "associated_threats", + "parent_requirement", + ] + ) class Meta: model = RequirementAssessment diff --git a/backend/core/startup.py b/backend/core/startup.py index 0b5294dc5..f3faad47d 100644 --- a/backend/core/startup.py +++ b/backend/core/startup.py @@ -345,7 +345,6 @@ "view_complianceassessment", "view_requirementassessment", "change_requirementassessment", - "view_requirementnode", "view_evidence", "add_evidence", "change_evidence", diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index 425dca1ec..52a7e0830 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -430,7 +430,11 @@ export const URL_MODEL_MAP: ModelMap = { verboseNamePlural: 'Evidences', fileFields: ['attachment'], foreignKeyFields: [ - { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO&content_type=GL' }, + { + field: 'folder', + urlModel: 'folders', + urlParams: 'content_type=DO&content_type=GL&content_type=EN' + }, { field: 'applied_controls', urlModel: 'applied-controls' } ] }, diff --git a/frontend/src/routes/(app)/(internal)/compliance-assessments/[id=uuid]/flash-mode/+page.svelte b/frontend/src/routes/(app)/(internal)/compliance-assessments/[id=uuid]/flash-mode/+page.svelte index 76913b580..8b0dae806 100644 --- a/frontend/src/routes/(app)/(internal)/compliance-assessments/[id=uuid]/flash-mode/+page.svelte +++ b/frontend/src/routes/(app)/(internal)/compliance-assessments/[id=uuid]/flash-mode/+page.svelte @@ -26,7 +26,7 @@ const requirementHashmap = Object.fromEntries( data.requirements.map((requirement) => [requirement.id, requirement]) ); - $: requirement = requirementHashmap[currentRequirementAssessment.requirement]; + $: requirement = requirementHashmap[currentRequirementAssessment.requirement.id]; $: parent = data.requirements.find((req) => req.urn === requirement.parent_urn); $: title = requirement.display_short diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.server.ts index acb0fb1c7..177c5ff37 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.server.ts +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.server.ts @@ -12,13 +12,8 @@ export const load = (async ({ fetch, params }) => { const complianceAssessmentScore = await fetch( `${BASE_API_URL}/compliance-assessments/${requirementAssessment.compliance_assessment.id}/global_score/` ).then((res) => res.json()); - const requirement = await fetch( - `${BASE_API_URL}/requirement-nodes/${requirementAssessment.requirement}/` - ).then((res) => res.json()); - const parentRequirementNodeEndpoint = `${BASE_API_URL}/requirement-nodes/?urn=${requirement.parent_urn}`; - const parent = await fetch(parentRequirementNodeEndpoint) - .then((res) => res.json()) - .then((res) => res.results[0]); + const requirement = requirementAssessment.requirement; + const parent = requirementAssessment.requirement.parent_requirement; const tables: Record = {}; diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte index 33163029d..58cf6fa78 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte @@ -12,13 +12,14 @@ import { page } from '$app/stores'; export let data: PageData; - const threats = data.requirement.threats; - const reference_controls = data.requirement.reference_controls; + const threats = data.requirementAssessment.requirement.associated_threats ?? []; + const reference_controls = + data.requirementAssessment.requirement.associated_reference_controls ?? []; const annotation = data.requirement.annotation; const typical_evidence = data.requirement.typical_evidence; - const has_threats = threats && threats.length > 0; - const has_reference_controls = reference_controls && reference_controls.length > 0; + const has_threats = threats.length > 0; + const has_reference_controls = reference_controls.length > 0; $: mappingInference = { sourceRequirementAssessment: diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts index a3fd98236..08e68fed1 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts @@ -29,16 +29,12 @@ export const load = (async ({ fetch, params }) => { } const requirementAssessment = await fetchJson(endpoint); - const [compliance_assessment_score, requirement] = await Promise.all([ - fetchJson( - `${baseUrl}/compliance-assessments/${requirementAssessment.compliance_assessment.id}/global_score/` - ), - fetchJson(`${baseUrl}/requirement-nodes/${requirementAssessment.requirement}/`) - ]); - - const parent = await fetchJson( - `${baseUrl}/requirement-nodes/?urn=${requirement.parent_urn}` - ).then((res) => res.results[0]); + const requirement = requirementAssessment.requirement; + const compliance_assessment_score = await fetchJson( + `${baseUrl}/compliance-assessments/${requirementAssessment.compliance_assessment.id}/global_score/` + ); + + const parent = requirementAssessment.requirement.parent_requirement; const model = getModelInfo(URLModel); const object = { ...requirementAssessment }; diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte index 8b247aecc..e03b5b656 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte @@ -6,13 +6,14 @@ export let data: PageData; export let form: ActionData; - const threats = data.requirement.threats; - const reference_controls = data.requirement.reference_controls; + const threats = data.requirementAssessment.requirement.associated_threats ?? []; + const reference_controls = + data.requirementAssessment.requirement.associated_reference_controls ?? []; const annotation = data.requirement.annotation; const typical_evidence = data.requirement.typical_evidence; - const has_threats = threats && threats.length > 0; - const has_reference_controls = reference_controls && reference_controls.length > 0; + const has_threats = threats.length > 0; + const has_reference_controls = reference_controls.length > 0; import { page } from '$app/stores'; import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';