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

Ca 616 serialize requirement node fields in requirement assessment #1087

Merged
86 changes: 84 additions & 2 deletions backend/app_tests/api/test_api_requirement_assessments.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
)
Expand Down
34 changes: 34 additions & 0 deletions backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
14 changes: 14 additions & 0 deletions backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion backend/core/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@
"view_complianceassessment",
"view_requirementassessment",
"change_requirementassessment",
"view_requirementnode",
"view_evidence",
"add_evidence",
"change_evidence",
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/lib/utils/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, any> = {};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Loading