From 8bb987f4ed2f7df50979385403998cd560a5e1b1 Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:16:40 +0200 Subject: [PATCH 01/16] Add cost field to applied controls Currency not yet managed. NumberField needs improvement --- .../api/test_api_applied_controls.py | 6 + backend/app_tests/api/test_utils.py | 1 + .../migrations/0025_appliedcontrol_cost.py | 21 +++ backend/core/models.py | 18 +++ backend/core/serializers.py | 1 + .../core/templates/core/action_plan_pdf.html | 2 + backend/core/templates/snippets/mp_data.html | 2 + backend/core/views.py | 10 +- documentation/architecture/data-model.md | 5 + .../src/lib/components/Forms/ModelForm.svelte | 8 + frontend/messages/ar.json | 3 + frontend/messages/de.json | 3 + frontend/messages/en.json | 3 + frontend/messages/es.json | 3 + frontend/messages/fr.json | 3 + frontend/messages/hi.json | 3 + frontend/messages/it.json | 5 +- frontend/messages/nl.json | 3 + frontend/messages/pl.json | 3 + frontend/messages/pt.json | 3 + frontend/messages/ro.json | 3 + frontend/messages/ur.json | 3 + .../src/lib/components/Forms/ModelForm.svelte | 9 ++ .../lib/components/Forms/NumberField.svelte | 75 +++++++++ .../src/lib/components/Forms/TextField.svelte | 1 + frontend/src/lib/utils/crud.ts | 1 + frontend/src/lib/utils/locales.ts | 2 + frontend/src/lib/utils/schemas.ts | 1 + .../[id=uuid]/action-plan/+page.svelte | 144 ++++-------------- .../[id=uuid]/remediation-plan/+page.svelte | 2 + frontend/tests/functional/user-route.test.ts | 1 + frontend/tests/utils/test-utils.ts | 1 + 32 files changed, 235 insertions(+), 114 deletions(-) create mode 100644 backend/core/migrations/0025_appliedcontrol_cost.py create mode 100644 frontend/src/lib/components/Forms/NumberField.svelte diff --git a/backend/app_tests/api/test_api_applied_controls.py b/backend/app_tests/api/test_api_applied_controls.py index b7705cfc5..782f1dc4e 100644 --- a/backend/app_tests/api/test_api_applied_controls.py +++ b/backend/app_tests/api/test_api_applied_controls.py @@ -16,6 +16,8 @@ APPLIED_CONTROL_EFFORT2 = ("M", "Medium") APPLIED_CONTROL_LINK = "https://example.com" APPLIED_CONTROL_ETA = "2024-01-01" +APPLIED_CONTROL_COST = 24.42 +APPLIED_CONTROL_COST2 = 25.43 @pytest.mark.django_db @@ -104,6 +106,7 @@ def test_get_applied_controls(self, test): "link": APPLIED_CONTROL_LINK, "eta": APPLIED_CONTROL_ETA, "effort": APPLIED_CONTROL_EFFORT[0], + "cost": APPLIED_CONTROL_COST, "folder": test.folder, }, { @@ -135,6 +138,7 @@ def test_create_applied_controls(self, test): "link": APPLIED_CONTROL_LINK, "eta": APPLIED_CONTROL_ETA, "effort": APPLIED_CONTROL_EFFORT[0], + "cost": APPLIED_CONTROL_COST, "folder": str(test.folder.id), }, { @@ -167,6 +171,7 @@ def test_update_applied_controls(self, test): "link": APPLIED_CONTROL_LINK, "eta": APPLIED_CONTROL_ETA, "effort": APPLIED_CONTROL_EFFORT[0], + "cost": APPLIED_CONTROL_COST, "folder": test.folder, }, { @@ -177,6 +182,7 @@ def test_update_applied_controls(self, test): "link": "new " + APPLIED_CONTROL_LINK, "eta": "2025-01-01", "effort": APPLIED_CONTROL_EFFORT2[0], + "cost": APPLIED_CONTROL_COST2, "folder": str(folder.id), }, { diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index 448c5073b..bf691cbb6 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -494,6 +494,7 @@ def get_object( json.loads(response_item[key]) == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" else: + print("coucou", type(value)) assert ( response_item[key] == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" diff --git a/backend/core/migrations/0025_appliedcontrol_cost.py b/backend/core/migrations/0025_appliedcontrol_cost.py new file mode 100644 index 000000000..b008363b8 --- /dev/null +++ b/backend/core/migrations/0025_appliedcontrol_cost.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1 on 2024-09-08 20:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0024_appliedcontrol_owner"), + ] + + operations = [ + migrations.AddField( + model_name="appliedcontrol", + name="cost", + field=models.FloatField( + help_text="Cost of the measure (using globally-chosen currency)", + null=True, + verbose_name="Cost", + ), + ), + ] diff --git a/backend/core/models.py b/backend/core/models.py index 64e3a6506..f052de87f 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -1274,6 +1274,11 @@ class Status(models.TextChoices): help_text=_("Relative effort of the measure (using T-Shirt sizing)"), verbose_name=_("Effort"), ) + cost = models.FloatField( + null=True, + help_text=_("Cost of the measure (using globally-chosen currency)"), + verbose_name=_("Cost"), + ) fields_to_check = ["name"] @@ -1628,6 +1633,19 @@ def quality_check(self) -> dict: } ) + if not mtg["cost"]: + warnings_lst.append( + { + "msg": _( + "{} does not have an estimated cost. This will help you for prioritization" + ).format(mtg["name"]), + "msgid": "appliedControlNoCost", + "link": f"applied-controls/{mtg['id']}", + "obj_type": "appliedcontrol", + "object": {"name": mtg["name"], "id": mtg["id"]}, + } + ) + if not mtg["link"]: info_lst.append( { diff --git a/backend/core/serializers.py b/backend/core/serializers.py index fac6fff35..3ae5d1912 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -310,6 +310,7 @@ class AppliedControlReadSerializer(AppliedControlWriteSerializer): ) # type : get_type_display evidences = FieldsRelatedField(many=True) effort = serializers.CharField(source="get_effort_display") + cost = serializers.FloatField() ranking_score = serializers.IntegerField(source="get_ranking_score") owner = FieldsRelatedField(many=True) diff --git a/backend/core/templates/core/action_plan_pdf.html b/backend/core/templates/core/action_plan_pdf.html index 3397130c3..e46c31fdb 100644 --- a/backend/core/templates/core/action_plan_pdf.html +++ b/backend/core/templates/core/action_plan_pdf.html @@ -46,6 +46,7 @@

{% trans "Action plan" %}

{% trans "ETA" %} {% trans "Expiry date" %} {% trans "Effort" %} + {% trans "Cost" %} {% trans "Matching requirements" %} @@ -59,6 +60,7 @@

{% trans "Action plan" %}

{{ applied_control.eta|default:"--" }} {{ applied_control.expiry_date|default:"--" }} {{ applied_control.get_effort_display|default:"--" }} + {{ applied_control.cost|default:"--" }} {% get_requirements_count applied_control compliance_assessment %} {% empty %} diff --git a/backend/core/templates/snippets/mp_data.html b/backend/core/templates/snippets/mp_data.html index ab5d70457..207186e9c 100644 --- a/backend/core/templates/snippets/mp_data.html +++ b/backend/core/templates/snippets/mp_data.html @@ -61,6 +61,7 @@ {% trans "Reference control" %} {% trans "ETA" %} {% trans "Effort" %} + {% trans "Cost" %} {% trans "Link" %} {% trans "Status" %} @@ -74,6 +75,7 @@ {% if appliedcontrol.reference_control %}{{ appliedcontrol.reference_control }}{% else %}--{% endif %} {% if appliedcontrol.eta %}{{ appliedcontrol.eta }}{% else %}--{%endif%} {% if appliedcontrol.effort %}{{ appliedcontrol.effort }}{% else %}--{%endif%} + {% if appliedcontrol.cost %}{{ appliedcontrol.cost }}{% else %}--{%endif%} {% if appliedcontrol.link %}{% else %}--{% endif %} diff --git a/backend/core/views.py b/backend/core/views.py index baf9e8417..911acb72b 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -431,6 +431,7 @@ def treatment_plan_csv(self, request, pk): "reference_control", "eta", "effort", + "cost", "link", "status", ] @@ -457,6 +458,7 @@ def treatment_plan_csv(self, request, pk): mtg.reference_control, mtg.eta, mtg.effort, + mtg.cost, mtg.link, mtg.status, ] @@ -615,6 +617,7 @@ class AppliedControlViewSet(BaseModelViewSet): "status", "reference_control", "effort", + "cost", "risk_scenarios", "requirement_assessments", "evidences", @@ -670,7 +673,7 @@ def todo(self, request): """measures = [{ key: getattr(mtg,key) for key in [ - "id","folder","reference_control","type","status","effort","name","description","eta","link","created_at","updated_at" + "id","folder","reference_control","type","status","effort", "cost", "name","description","eta","link","created_at","updated_at" ] } for mtg in measures] for i in range(len(measures)) : @@ -1432,6 +1435,7 @@ def action_plan(self, request, pk): "expiry_date": applied_control.expiry_date, "link": applied_control.link, "effort": applied_control.effort, + "cost": applied_control.cost, "owners": [ { "id": owner.id, @@ -1784,7 +1788,7 @@ def todo(self, request): """measures = [{ key: getattr(mtg,key) for key in [ - "id","folder","reference_control","type","status","effort","name","description","eta","link","created_at","updated_at" + "id","folder","reference_control","type","status","effort","cost","name","description","eta","link","created_at","updated_at" ] } for mtg in measures] for i in range(len(measures)) : @@ -1979,6 +1983,7 @@ def export_mp_csv(request): "reference_control", "eta", "effort", + "cost", "link", "status", ] @@ -2000,6 +2005,7 @@ def export_mp_csv(request): mtg.reference_control, mtg.eta, mtg.effort, + mtg.cost, mtg.link, mtg.status, ] diff --git a/documentation/architecture/data-model.md b/documentation/architecture/data-model.md index 67e7474bf..84734fbca 100644 --- a/documentation/architecture/data-model.md +++ b/documentation/architecture/data-model.md @@ -227,6 +227,7 @@ erDiagram date expiration url link string effort + float cost string[] tags } @@ -598,6 +599,7 @@ namespace DomainObjects { +DateField expiry_date +CharField link +CharField effort + +Decimal cost +RiskScenario[] risk_scenarios() +RiskAssessments[] risk_assessments() @@ -777,11 +779,14 @@ A applied control has the following specific fields: - an Estimated Time of Arrival date - a validity date (expiration field) - an effort (--/S/M/L/XL) +- a cost (--/float value) - a url link - a list of user-defined tags When a applied control derives from a reference control, the same category and csf_function are proposed, but this can be changed. +Costs are measured in a global currency/multiple that is defined in global settings. + ## Compliance and risk assessments Both types of assessments have common fields: diff --git a/enterprise/frontend/src/lib/components/Forms/ModelForm.svelte b/enterprise/frontend/src/lib/components/Forms/ModelForm.svelte index e481fea7b..c92890ac2 100644 --- a/enterprise/frontend/src/lib/components/Forms/ModelForm.svelte +++ b/enterprise/frontend/src/lib/components/Forms/ModelForm.svelte @@ -400,6 +400,14 @@ cacheLock={cacheLocks['effort']} bind:cachedValue={formDataCache['effort']} /> + + + {#if helpText} +

{helpText}

+ {/if} + diff --git a/frontend/src/lib/components/Forms/TextField.svelte b/frontend/src/lib/components/Forms/TextField.svelte index ff39bb115..503e9296b 100644 --- a/frontend/src/lib/components/Forms/TextField.svelte +++ b/frontend/src/lib/components/Forms/TextField.svelte @@ -1,6 +1,7 @@ diff --git a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/remediation-plan/+page.svelte b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/remediation-plan/+page.svelte index f33d1a983..9c651cc61 100644 --- a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/remediation-plan/+page.svelte +++ b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/remediation-plan/+page.svelte @@ -94,6 +94,7 @@ {m.referenceControl()} {m.eta()} {m.effort()} + {m.cost()} {m.link()} {m.status()} @@ -112,6 +113,7 @@ > {measure.eta ?? '--'} {measure.effort ?? '--'} + {measure.cost ?? '--'} {measure.link ?? '--'} ({ { name: 'expiry_date', type: type.DATE }, { name: 'link', type: type.TEXT }, { name: 'effort', type: type.SELECT }, + { name: 'cost', type: type.TEXT }, { name: 'folder', type: type.SELECT_AUTOCOMPLETE }, { name: 'reference_control', type: type.SELECT_AUTOCOMPLETE } ]); From e8549f5b46ef6551d627adfa3d7036958531a3a8 Mon Sep 17 00:00:00 2001 From: Nassim Tabchiche Date: Wed, 11 Sep 2024 17:32:12 +0200 Subject: [PATCH 02/16] Add number input type in functional tests --- frontend/tests/utils/form-content.ts | 3 ++- frontend/tests/utils/test-utils.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/tests/utils/form-content.ts b/frontend/tests/utils/form-content.ts index 7a2afd6b8..fb4f05f87 100644 --- a/frontend/tests/utils/form-content.ts +++ b/frontend/tests/utils/form-content.ts @@ -7,7 +7,8 @@ export enum FormFieldType { SELECT = 'select', SELECT_AUTOCOMPLETE = 'select-autocomplete', SELECT_MULTIPLE_AUTOCOMPLETE = 'select-multi-autocomplete', - TEXT = 'text' + TEXT = 'text', + NUMBER = 'number' } type FormField = { diff --git a/frontend/tests/utils/test-utils.ts b/frontend/tests/utils/test-utils.ts index a99ede306..574d11a1c 100644 --- a/frontend/tests/utils/test-utils.ts +++ b/frontend/tests/utils/test-utils.ts @@ -230,7 +230,7 @@ export const test = base.extend({ { name: 'expiry_date', type: type.DATE }, { name: 'link', type: type.TEXT }, { name: 'effort', type: type.SELECT }, - { name: 'cost', type: type.TEXT }, + { name: 'cost', type: type.NUMBER }, { name: 'folder', type: type.SELECT_AUTOCOMPLETE }, { name: 'reference_control', type: type.SELECT_AUTOCOMPLETE } ]); From 1316f8f4656bce6267a8ceec6cf71ab6c1d77e10 Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Wed, 11 Sep 2024 19:09:49 +0200 Subject: [PATCH 03/16] Update data-model.md reference control can be defined in a subdomain --- documentation/architecture/data-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/architecture/data-model.md b/documentation/architecture/data-model.md index 67e7474bf..1b5a5075a 100644 --- a/documentation/architecture/data-model.md +++ b/documentation/architecture/data-model.md @@ -46,7 +46,6 @@ erDiagram DOMAIN ||--o{ RISK_ASSESSMENT_REVIEW : contains DOMAIN ||--o{ COMPLIANCE_ASSESSMENT_REVIEW: contains ROOT_FOLDER ||--o{ FRAMEWORK : contains - ROOT_FOLDER ||--o{ REFERENCE_CONTROL : contains ROOT_FOLDER ||--o{ STORED_LIBRARY : contains ROOT_FOLDER ||--o{ LOADED_LIBRARY : contains ROOT_FOLDER ||--o{ USER : contains @@ -54,6 +53,7 @@ erDiagram ROOT_FOLDER ||--o{ ROLE : contains ROOT_FOLDER ||--o{ ROLE_ASSIGNMENT : contains ROOT_FOLDER_OR_DOMAIN ||--o{ EVIDENCE : contains + ROOT_FOLDER_OR_DOMAIN ||--o{ REFERENCE_CONTROL : contains ROOT_FOLDER_OR_DOMAIN ||--o{ APPLIED_CONTROL : contains ROOT_FOLDER_OR_DOMAIN ||--o{ RISK_ACCEPTANCE : contains ROOT_FOLDER_OR_DOMAIN ||--o{ ASSET : contains From be0e03c823bca47951d4ed7c3d182783151e40b6 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 12:21:36 +0200 Subject: [PATCH 04/16] Attempt to fix functional tests by making cost a string --- frontend/tests/functional/user-route.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/functional/user-route.test.ts b/frontend/tests/functional/user-route.test.ts index f761fd77e..5de56fd8d 100644 --- a/frontend/tests/functional/user-route.test.ts +++ b/frontend/tests/functional/user-route.test.ts @@ -110,7 +110,7 @@ test('user usual routine actions are working correctly', async ({ eta: '2025-01-01', link: 'https://intuitem.com/', effort: 'Large', - cost: 24.42, + cost: "24.42", folder: vars.folderName, reference_control: `${vars.folderName}/${vars.referenceControlName}` }); From fc9c1bc6e69e9c605e43107085b3305572639a4d Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 12:23:00 +0200 Subject: [PATCH 05/16] Formatter --- frontend/tests/functional/user-route.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/functional/user-route.test.ts b/frontend/tests/functional/user-route.test.ts index 5de56fd8d..85be0fc73 100644 --- a/frontend/tests/functional/user-route.test.ts +++ b/frontend/tests/functional/user-route.test.ts @@ -110,7 +110,7 @@ test('user usual routine actions are working correctly', async ({ eta: '2025-01-01', link: 'https://intuitem.com/', effort: 'Large', - cost: "24.42", + cost: '24.42', folder: vars.folderName, reference_control: `${vars.folderName}/${vars.referenceControlName}` }); From 24c0b8e2c602c8d6afca6fbc76379607f2752c65 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 12:28:13 +0200 Subject: [PATCH 06/16] Better fix --- frontend/tests/functional/user-route.test.ts | 2 +- frontend/tests/utils/form-content.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/tests/functional/user-route.test.ts b/frontend/tests/functional/user-route.test.ts index 85be0fc73..f761fd77e 100644 --- a/frontend/tests/functional/user-route.test.ts +++ b/frontend/tests/functional/user-route.test.ts @@ -110,7 +110,7 @@ test('user usual routine actions are working correctly', async ({ eta: '2025-01-01', link: 'https://intuitem.com/', effort: 'Large', - cost: '24.42', + cost: 24.42, folder: vars.folderName, reference_control: `${vars.folderName}/${vars.referenceControlName}` }); diff --git a/frontend/tests/utils/form-content.ts b/frontend/tests/utils/form-content.ts index fb4f05f87..64cf07485 100644 --- a/frontend/tests/utils/form-content.ts +++ b/frontend/tests/utils/form-content.ts @@ -114,6 +114,8 @@ export class FormContent { break; case FormFieldType.DATE: await field.locator.clear(); + case FormFieldType.NUMBER: + await field?.locator.fill(values[key].toString()); default: await field?.locator.fill(values[key]); break; From a9fb47628fb670daeb55b03737a8a6f29f882b2c Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 12:42:29 +0200 Subject: [PATCH 07/16] Fix migration conflict --- .../migrations/0025_appliedcontrol_cost.py | 21 ------------------- .../migrations/0026_appliedcontrol_cost.py | 18 ++++++++++++++++ 2 files changed, 18 insertions(+), 21 deletions(-) delete mode 100644 backend/core/migrations/0025_appliedcontrol_cost.py create mode 100644 backend/core/migrations/0026_appliedcontrol_cost.py diff --git a/backend/core/migrations/0025_appliedcontrol_cost.py b/backend/core/migrations/0025_appliedcontrol_cost.py deleted file mode 100644 index b008363b8..000000000 --- a/backend/core/migrations/0025_appliedcontrol_cost.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 5.1 on 2024-09-08 20:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("core", "0024_appliedcontrol_owner"), - ] - - operations = [ - migrations.AddField( - model_name="appliedcontrol", - name="cost", - field=models.FloatField( - help_text="Cost of the measure (using globally-chosen currency)", - null=True, - verbose_name="Cost", - ), - ), - ] diff --git a/backend/core/migrations/0026_appliedcontrol_cost.py b/backend/core/migrations/0026_appliedcontrol_cost.py new file mode 100644 index 000000000..8f0e10a4d --- /dev/null +++ b/backend/core/migrations/0026_appliedcontrol_cost.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2024-09-13 10:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0025_complianceassessment_folder_riskassessment_folder_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='appliedcontrol', + name='cost', + field=models.FloatField(help_text='Cost of the measure (using globally-chosen currency)', null=True, verbose_name='Cost'), + ), + ] From 6a53df26f82088b6ec8075b63c115ee884cac3f9 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 12:46:05 +0200 Subject: [PATCH 08/16] Formatter --- backend/core/migrations/0026_appliedcontrol_cost.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/core/migrations/0026_appliedcontrol_cost.py b/backend/core/migrations/0026_appliedcontrol_cost.py index 8f0e10a4d..84b21c7c4 100644 --- a/backend/core/migrations/0026_appliedcontrol_cost.py +++ b/backend/core/migrations/0026_appliedcontrol_cost.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('core', '0025_complianceassessment_folder_riskassessment_folder_and_more'), + ("core", "0025_complianceassessment_folder_riskassessment_folder_and_more"), ] operations = [ migrations.AddField( - model_name='appliedcontrol', - name='cost', - field=models.FloatField(help_text='Cost of the measure (using globally-chosen currency)', null=True, verbose_name='Cost'), + model_name="appliedcontrol", + name="cost", + field=models.FloatField( + help_text="Cost of the measure (using globally-chosen currency)", + null=True, + verbose_name="Cost", + ), ), ] From 75af5330e2b2838db07741a805eda96439b214d8 Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:51:51 +0200 Subject: [PATCH 09/16] Update test_utils.py remove debug code --- backend/app_tests/api/test_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index bf691cbb6..448c5073b 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -494,7 +494,6 @@ def get_object( json.loads(response_item[key]) == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" else: - print("coucou", type(value)) assert ( response_item[key] == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" From a0175ff5abf99e8ff26b70a218b31842479c0894 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 13:22:30 +0200 Subject: [PATCH 10/16] Accept floats up to 6-digit of precision in the NumberField for cost --- frontend/src/lib/utils/schemas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts index 32252f01a..344d1eff7 100644 --- a/frontend/src/lib/utils/schemas.ts +++ b/frontend/src/lib/utils/schemas.ts @@ -120,7 +120,7 @@ export const AppliedControlSchema = baseNamedObject({ expiry_date: z.string().optional().nullable(), link: z.string().url().optional().or(z.literal('')), effort: z.string().optional().nullable(), - cost: z.number().optional().nullable(), + cost: z.number().multipleOf(0.000001).optional().nullable(), folder: z.string(), reference_control: z.string().optional().nullable(), owner: z.string().uuid().optional().array().optional() From bc1725970dcd92fb4ee8b2b0d43f292ab6f10240 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 13:35:08 +0200 Subject: [PATCH 11/16] Add force option for number inputs in functional tests --- frontend/tests/utils/form-content.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/utils/form-content.ts b/frontend/tests/utils/form-content.ts index 64cf07485..552cdd06d 100644 --- a/frontend/tests/utils/form-content.ts +++ b/frontend/tests/utils/form-content.ts @@ -115,7 +115,7 @@ export class FormContent { case FormFieldType.DATE: await field.locator.clear(); case FormFieldType.NUMBER: - await field?.locator.fill(values[key].toString()); + await field?.locator.fill(values[key].toString(), { force: true }); default: await field?.locator.fill(values[key]); break; From fceee0a23ea42393bf691177ca31ae6cce7a02eb Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 14:31:05 +0200 Subject: [PATCH 12/16] Add forgotten break in form handler switch statement --- frontend/tests/utils/form-content.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/tests/utils/form-content.ts b/frontend/tests/utils/form-content.ts index 552cdd06d..987ddde8d 100644 --- a/frontend/tests/utils/form-content.ts +++ b/frontend/tests/utils/form-content.ts @@ -116,6 +116,7 @@ export class FormContent { await field.locator.clear(); case FormFieldType.NUMBER: await field?.locator.fill(values[key].toString(), { force: true }); + break; default: await field?.locator.fill(values[key]); break; From 5aa32cb056dd188019988462f5f3a0d99652164c Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Fri, 13 Sep 2024 14:44:16 +0200 Subject: [PATCH 13/16] Remove useless force option --- frontend/tests/utils/form-content.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/utils/form-content.ts b/frontend/tests/utils/form-content.ts index 987ddde8d..ca27eaca4 100644 --- a/frontend/tests/utils/form-content.ts +++ b/frontend/tests/utils/form-content.ts @@ -115,7 +115,7 @@ export class FormContent { case FormFieldType.DATE: await field.locator.clear(); case FormFieldType.NUMBER: - await field?.locator.fill(values[key].toString(), { force: true }); + await field?.locator.fill(values[key].toString()); break; default: await field?.locator.fill(values[key]); From fc4c891da8eae40b5609b3937bc4a8edc845dd25 Mon Sep 17 00:00:00 2001 From: Nassim Tabchiche Date: Fri, 13 Sep 2024 17:23:35 +0200 Subject: [PATCH 14/16] Fix potential information disclosure serializers.ValidationError is passed to the ViewSet and returned to the client. Displaying the message of the exception WILL cause unwanted information disclosure. --- backend/core/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/serializers.py b/backend/core/serializers.py index baaf1456e..349e4a3f2 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -86,7 +86,7 @@ def create(self, validated_data: Any): return object_created except Exception as e: logger.error(e) - raise serializers.ValidationError(e.args[0]) + raise serializers.ValidationError() class Meta: model: models.Model From 44f52370a256874d50dee0eb141d618aa345bf2b Mon Sep 17 00:00:00 2001 From: Nassim Tabchiche Date: Fri, 13 Sep 2024 19:31:53 +0200 Subject: [PATCH 15/16] chore: Make migrations --- ..._more.py => 0027_requirementassessment_answer_and_more.py} | 4 ++-- backend/tprm/migrations/0001_initial.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename backend/core/migrations/{0026_requirementassessment_answer_and_more.py => 0027_requirementassessment_answer_and_more.py} (79%) diff --git a/backend/core/migrations/0026_requirementassessment_answer_and_more.py b/backend/core/migrations/0027_requirementassessment_answer_and_more.py similarity index 79% rename from backend/core/migrations/0026_requirementassessment_answer_and_more.py rename to backend/core/migrations/0027_requirementassessment_answer_and_more.py index 3179ff5a9..1b8587a92 100644 --- a/backend/core/migrations/0026_requirementassessment_answer_and_more.py +++ b/backend/core/migrations/0027_requirementassessment_answer_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.1 on 2024-09-13 15:42 +# Generated by Django 5.1 on 2024-09-13 16:25 from django.db import migrations, models @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ('core', '0025_complianceassessment_folder_riskassessment_folder_and_more'), + ('core', '0026_appliedcontrol_cost'), ] operations = [ diff --git a/backend/tprm/migrations/0001_initial.py b/backend/tprm/migrations/0001_initial.py index 8665098dc..8cf11aade 100644 --- a/backend/tprm/migrations/0001_initial.py +++ b/backend/tprm/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.1 on 2024-09-13 15:42 +# Generated by Django 5.1 on 2024-09-13 16:25 import django.db.models.deletion import iam.models @@ -12,7 +12,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('core', '0026_requirementassessment_answer_and_more'), + ('core', '0027_requirementassessment_answer_and_more'), ('iam', '0007_alter_folder_content_type'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] From 973574fb81557c089cb61d77775eea5ed2b46bae Mon Sep 17 00:00:00 2001 From: Nassim Tabchiche Date: Fri, 13 Sep 2024 19:33:35 +0200 Subject: [PATCH 16/16] Add is_third_party field to User model --- .../iam/migrations/0008_user_is_third_party.py | 18 ++++++++++++++++++ backend/iam/models.py | 1 + 2 files changed, 19 insertions(+) create mode 100644 backend/iam/migrations/0008_user_is_third_party.py diff --git a/backend/iam/migrations/0008_user_is_third_party.py b/backend/iam/migrations/0008_user_is_third_party.py new file mode 100644 index 000000000..9ae460cdc --- /dev/null +++ b/backend/iam/migrations/0008_user_is_third_party.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2024-09-13 17:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('iam', '0007_alter_folder_content_type'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='is_third_party', + field=models.BooleanField(default=False), + ), + ] diff --git a/backend/iam/models.py b/backend/iam/models.py index 3bb6c84c4..017370abb 100644 --- a/backend/iam/models.py +++ b/backend/iam/models.py @@ -328,6 +328,7 @@ class User(AbstractBaseUser, AbstractBaseModel, FolderMixin): email = models.CharField(max_length=100, unique=True) first_login = models.BooleanField(default=True) is_sso = models.BooleanField(default=False) + is_third_party = models.BooleanField(default=False) is_active = models.BooleanField( _("active"), default=True,