wbcompliance 1.54.19__tar.gz → 1.59.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/PKG-INFO +1 -1
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/checks.py +8 -0
- wbcompliance-1.59.2/wbcompliance/migrations/0022_riskincident_precheck.py +39 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/compliance_task.py +5 -5
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/enums.py +1 -1
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/checks.py +92 -6
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/incidents.py +23 -7
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/mixins.py +2 -2
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/rules.py +9 -70
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/risk_management/checks.py +1 -1
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/disable_signals.py +11 -10
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/models/test_incidents.py +9 -7
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/test_views.py +1 -1
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/compliance_form.py +3 -3
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/compliance_task.py +14 -14
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/checks.py +14 -3
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/mixins.py +1 -1
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/.gitignore +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/pyproject.toml +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/risk_management/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/risk_management/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/risk_management/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/admin/utils.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/apps.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/compliance.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/risk_management/backends.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/risk_management/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/risk_management/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/factories/risk_management/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/compliances.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/tables.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/filters/risk_management/utils.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/fixtures/compliance.yaml +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/de/LC_MESSAGES/django.mo +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/de/LC_MESSAGES/django.po +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/en/LC_MESSAGES/django.mo +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/en/LC_MESSAGES/django.po +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/fr/LC_MESSAGES/django.mo +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/locale/fr/LC_MESSAGES/django.po +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0001_initial_squashed_squashed_0010_alter_checkedobjectincidentrelationship_resolved_by_and_more.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0011_alter_riskrule_parameters.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0012_alter_compliancetype_options.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0013_alter_riskrule_unique_together.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0014_alter_reviewcompliancetask_year.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0015_auto_20240103_0957.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0016_checkedobjectincidentrelationship_report_details_and_more.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0017_alter_rulebackend_incident_report_template.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0018_alter_rulecheckedobjectrelationship_unique_together.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0019_rulegroup_riskrule_activation_date_and_more.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0020_rename_trigger_content_type_riskcheck_checked_object_content_type_and_more.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/0021_riskcheck_passive_check.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/migrations/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/backend.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/dispatch.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/permissions.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/risk_management/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/risk_management/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tasks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/templates/compliance/compliance_form.html +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/templates/compliance/review_compliance_task_report.html +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/templates/risk_management/incident_notification.html +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/templates/risk_management/incident_report.html +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/conftest.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/mixins.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/models/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/models/test_backends.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/models/test_checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/risk_management/models/test_rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/signals.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/test_filters.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/test_models.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/test_serializers.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/tests/tests.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/urls.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/risk_managment/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/risk_managment/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/risk_managment/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/risk_managment/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/risk_managment/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/risk_managment/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/risk_managment/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/risk_managment/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/display/risk_managment/tables.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/risk_managment/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/risk_managment/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/risk_managment/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/risk_managment/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/endpoints/risk_managment/tables.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/menu/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/menu/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/menu/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/menu/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/menu/risk_management.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/risk_management/tables.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/compliance_form.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/compliance_task.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/compliance_type.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/risk_managment/__init__.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/risk_managment/checks.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/risk_managment/incidents.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/risk_managment/rules.py +0 -0
- {wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/titles/risk_managment/tables.py +0 -0
|
@@ -12,6 +12,14 @@ class RiskCheckFilterSet(wb_filters.FilterSet):
|
|
|
12
12
|
distinct=True,
|
|
13
13
|
hidden=True,
|
|
14
14
|
)
|
|
15
|
+
activators = wb_filters.MultipleChoiceContentTypeFilter(
|
|
16
|
+
label="Activators",
|
|
17
|
+
field_name="activators",
|
|
18
|
+
object_id_label="activator_id",
|
|
19
|
+
content_type_label="activator_content_type",
|
|
20
|
+
distinct=True,
|
|
21
|
+
hidden=True,
|
|
22
|
+
)
|
|
15
23
|
passive_check = wb_filters.BooleanFilter(initial=True, required=True, label="Passive")
|
|
16
24
|
|
|
17
25
|
class Meta:
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-11-28 09:18
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
from django.db.models import Exists, OuterRef
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def handle_data(apps, schema_editor):
|
|
9
|
+
CheckedObjectIncidentRelationship = apps.get_model('wbcompliance', 'CheckedObjectIncidentRelationship')
|
|
10
|
+
RiskIncident = apps.get_model('wbcompliance', 'RiskIncident')
|
|
11
|
+
CheckedObjectIncidentRelationship.objects.filter(incident__isnull=True).delete()
|
|
12
|
+
RiskIncident.objects.filter(checked_object_relationships__isnull=True).delete()
|
|
13
|
+
RiskIncident.objects.annotate(
|
|
14
|
+
is_precheck=Exists(CheckedObjectIncidentRelationship.objects.filter(incident=OuterRef("id"), rule_check__activator_id__isnull=False))
|
|
15
|
+
).filter(is_precheck=True).update(precheck=True)
|
|
16
|
+
|
|
17
|
+
class Migration(migrations.Migration):
|
|
18
|
+
|
|
19
|
+
dependencies = [
|
|
20
|
+
('wbcompliance', '0021_riskcheck_passive_check'),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
operations = [
|
|
24
|
+
migrations.AddField(
|
|
25
|
+
model_name='riskincident',
|
|
26
|
+
name='precheck',
|
|
27
|
+
field=models.BooleanField(default=False, help_text='If true, this incident was created during a precheck evaluation', verbose_name='Precheck Incident'),
|
|
28
|
+
),
|
|
29
|
+
migrations.RunSQL(sql="SET CONSTRAINTS ALL IMMEDIATE;"),
|
|
30
|
+
migrations.RunPython(handle_data),
|
|
31
|
+
migrations.RunSQL(sql="SET CONSTRAINTS ALL DEFERRED;"),
|
|
32
|
+
migrations.AlterField(
|
|
33
|
+
model_name='checkedobjectincidentrelationship',
|
|
34
|
+
name='incident',
|
|
35
|
+
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE,
|
|
36
|
+
related_name='checked_object_relationships', to='wbcompliance.riskincident'),
|
|
37
|
+
preserve_default=False,
|
|
38
|
+
),
|
|
39
|
+
]
|
|
@@ -75,7 +75,7 @@ class ComplianceTask(WBModel):
|
|
|
75
75
|
@classmethod
|
|
76
76
|
def get_color_map(cls) -> list:
|
|
77
77
|
colors = [WBColor.GREEN_LIGHT.value, WBColor.YELLOW_LIGHT.value, WBColor.RED_LIGHT.value]
|
|
78
|
-
return [choice for choice in zip(cls, colors)]
|
|
78
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
79
79
|
|
|
80
80
|
title = models.CharField(max_length=255, verbose_name=_("Title"))
|
|
81
81
|
description = models.TextField(default="", blank=True, verbose_name=_("Description"))
|
|
@@ -171,7 +171,7 @@ class ComplianceTaskInstance(models.Model):
|
|
|
171
171
|
WBColor.BLUE_LIGHT.value,
|
|
172
172
|
WBColor.RED_LIGHT.value,
|
|
173
173
|
]
|
|
174
|
-
return [choice for choice in zip(cls, colors)]
|
|
174
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
175
175
|
|
|
176
176
|
task = models.ForeignKey(
|
|
177
177
|
on_delete=models.CASCADE,
|
|
@@ -235,7 +235,7 @@ class ComplianceAction(models.Model):
|
|
|
235
235
|
@classmethod
|
|
236
236
|
def get_color_map(cls) -> list:
|
|
237
237
|
colors = [WBColor.GREY.value, WBColor.YELLOW_LIGHT.value, WBColor.GREEN_LIGHT.value]
|
|
238
|
-
return [choice for choice in zip(cls, colors)]
|
|
238
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
239
239
|
|
|
240
240
|
title = models.CharField(max_length=255, verbose_name=_("Title"))
|
|
241
241
|
description = models.TextField(
|
|
@@ -310,7 +310,7 @@ class ComplianceEvent(models.Model):
|
|
|
310
310
|
@classmethod
|
|
311
311
|
def get_color_map(cls) -> list:
|
|
312
312
|
colors = [WBColor.GREY.value, WBColor.BLUE_LIGHT.value]
|
|
313
|
-
return [choice for choice in zip(cls, colors)]
|
|
313
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
314
314
|
|
|
315
315
|
type_event = models.CharField(
|
|
316
316
|
max_length=32,
|
|
@@ -414,7 +414,7 @@ class ReviewComplianceTask(ComplianceDocumentMixin, ComplexToStringMixin, WBMode
|
|
|
414
414
|
WBColor.YELLOW_LIGHT.value,
|
|
415
415
|
WBColor.GREEN_LIGHT.value,
|
|
416
416
|
]
|
|
417
|
-
return [choice for choice in zip(cls, colors)]
|
|
417
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
418
418
|
|
|
419
419
|
class Meta:
|
|
420
420
|
verbose_name = "Review Compliance Task"
|
|
@@ -10,4 +10,4 @@ class IncidentSeverity(models.TextChoices):
|
|
|
10
10
|
@classmethod
|
|
11
11
|
def get_color_map(cls) -> list:
|
|
12
12
|
colors = [WBColor.GREEN_LIGHT.value, WBColor.YELLOW_LIGHT.value, WBColor.RED_LIGHT.value]
|
|
13
|
-
return [choice for choice in zip(cls, colors)]
|
|
13
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from contextlib import suppress
|
|
2
|
+
from datetime import date, timedelta
|
|
2
3
|
from types import DynamicClassAttribute
|
|
3
|
-
from typing import Self
|
|
4
|
+
from typing import Any, Self
|
|
4
5
|
|
|
5
6
|
from celery import shared_task
|
|
6
7
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
@@ -8,12 +9,14 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
8
9
|
from django.db import models
|
|
9
10
|
from django.template import Context, Template
|
|
10
11
|
from django.utils.translation import gettext_lazy as _
|
|
12
|
+
from pandas._libs.tslibs.offsets import BDay
|
|
13
|
+
from psycopg.types.range import DateRange
|
|
11
14
|
from wbcore.contrib.color.enums import WBColor
|
|
12
15
|
from wbcore.contrib.icons import WBIcon
|
|
13
16
|
from wbcore.models import WBModel
|
|
14
17
|
from wbcore.utils.models import ComplexToStringMixin
|
|
15
18
|
|
|
16
|
-
from .incidents import CheckedObjectIncidentRelationship
|
|
19
|
+
from .incidents import CheckedObjectIncidentRelationship, RiskIncident, RiskIncidentType
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class RiskCheckManager(models.Manager):
|
|
@@ -99,9 +102,16 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
99
102
|
@property
|
|
100
103
|
def needs_incident(self) -> bool:
|
|
101
104
|
# if the there is a similar checked object relationship, we needs to create a general incident if the check evaluates to a breach
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
return (
|
|
106
|
+
self.rule.checked_object_relationships.filter(
|
|
107
|
+
checked_object_content_type=self.checked_object_content_type, checked_object_id=self.checked_object_id
|
|
108
|
+
).exists()
|
|
109
|
+
or self.precheck
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def precheck(self) -> bool:
|
|
114
|
+
return self.activator_id is not None
|
|
105
115
|
|
|
106
116
|
@property
|
|
107
117
|
def previous_check(self) -> Self | None:
|
|
@@ -127,6 +137,20 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
127
137
|
self.checked_object_repr = str(self.checked_object)
|
|
128
138
|
super().save(*args, **kwargs)
|
|
129
139
|
|
|
140
|
+
def delete(self, *args, **kwargs):
|
|
141
|
+
incidents = RiskIncident.all_objects.filter(
|
|
142
|
+
id__in=list(
|
|
143
|
+
CheckedObjectIncidentRelationship.objects.filter(rule_check_id=self.id).values_list(
|
|
144
|
+
"incident", flat=True
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
super().delete(*args, **kwargs)
|
|
149
|
+
# ensure that incident without subincidents are deleted automatically
|
|
150
|
+
for incident in incidents:
|
|
151
|
+
if not incident.checked_object_relationships.exists():
|
|
152
|
+
incident.delete()
|
|
153
|
+
|
|
130
154
|
def compute_str(self) -> str:
|
|
131
155
|
return _("{} - {}").format(
|
|
132
156
|
self.checked_object,
|
|
@@ -164,7 +188,7 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
164
188
|
# If the check is passive, we aggregated incident per breached object and return it for further processing
|
|
165
189
|
if self.needs_incident:
|
|
166
190
|
report = report_template.render(Context({"report_details": incident_result.report_details}))
|
|
167
|
-
incident, created = self.
|
|
191
|
+
incident, created = self.get_or_create_incident(
|
|
168
192
|
self.evaluation_date,
|
|
169
193
|
incident_result.severity,
|
|
170
194
|
incident_result.breached_object,
|
|
@@ -192,6 +216,68 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
192
216
|
self.save()
|
|
193
217
|
return incidents
|
|
194
218
|
|
|
219
|
+
def get_or_create_incident(
|
|
220
|
+
self,
|
|
221
|
+
evaluation_date: date,
|
|
222
|
+
incident_severity: "RiskIncidentType",
|
|
223
|
+
breached_object: Any,
|
|
224
|
+
breached_object_repr: str,
|
|
225
|
+
) -> tuple[RiskIncident, bool]:
|
|
226
|
+
"""
|
|
227
|
+
Utility function to get or create incident base on the given breached object
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
evaluation_date: The incident date
|
|
231
|
+
incident_severity: The incident severity
|
|
232
|
+
breached_object: The breached object (i.e. the object that triggers the incident)
|
|
233
|
+
breached_object_repr: Its string representation
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
A tuple (incident, is_created)
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
# Consider that if an incident happens one business day in the future or past, it is continue
|
|
240
|
+
date_range = DateRange( # type: ignore
|
|
241
|
+
(evaluation_date - BDay(1)).date(), (evaluation_date + BDay(1)).date(), "[]"
|
|
242
|
+
)
|
|
243
|
+
incidents = RiskIncident.objects.filter(rule=self.rule, date_range__overlap=date_range, precheck=self.precheck)
|
|
244
|
+
if breached_object:
|
|
245
|
+
# If a breached_object is provided, we lookup over it
|
|
246
|
+
incidents = incidents.filter(
|
|
247
|
+
breached_content_type=ContentType.objects.get_for_model(breached_object),
|
|
248
|
+
breached_object_id=breached_object.id,
|
|
249
|
+
)
|
|
250
|
+
else:
|
|
251
|
+
# Otherwise, we lookup over its string representation. Might need to change as this is not very robust
|
|
252
|
+
incidents = incidents.filter(
|
|
253
|
+
breached_object_repr=breached_object_repr,
|
|
254
|
+
)
|
|
255
|
+
created = False
|
|
256
|
+
if incident := incidents.first():
|
|
257
|
+
incident.date_range = DateRange( # type: ignore
|
|
258
|
+
lower=incident.date_range.lower, upper=(evaluation_date + timedelta(days=1))
|
|
259
|
+
)
|
|
260
|
+
incident.severity = incident_severity
|
|
261
|
+
else:
|
|
262
|
+
incident = RiskIncident(
|
|
263
|
+
rule=self.rule,
|
|
264
|
+
date_range=DateRange(lower=evaluation_date, upper=(evaluation_date + timedelta(days=1))), # type: ignore
|
|
265
|
+
breached_content_type=ContentType.objects.get_for_model(breached_object) if breached_object else None,
|
|
266
|
+
breached_object_id=breached_object.id if breached_object else None,
|
|
267
|
+
breached_object_repr=breached_object_repr,
|
|
268
|
+
severity=incident_severity,
|
|
269
|
+
status=RiskIncident.Status.OPEN,
|
|
270
|
+
)
|
|
271
|
+
created = True
|
|
272
|
+
|
|
273
|
+
if self.rule.automatically_close_incident:
|
|
274
|
+
incident.status = RiskIncident.Status.CLOSED
|
|
275
|
+
elif self.precheck:
|
|
276
|
+
incident.status = RiskIncident.Status.IGNORED
|
|
277
|
+
incident.precheck = self.precheck
|
|
278
|
+
incident.save()
|
|
279
|
+
return incident, created
|
|
280
|
+
|
|
195
281
|
class Meta:
|
|
196
282
|
verbose_name = "Risk Check"
|
|
197
283
|
verbose_name_plural = "Risk Checks"
|
{wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/models/risk_management/incidents.py
RENAMED
|
@@ -29,7 +29,6 @@ from wbcore.metadata.configs.buttons import ActionButton, ButtonDefaultColor
|
|
|
29
29
|
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
30
30
|
create_simple_display,
|
|
31
31
|
)
|
|
32
|
-
from wbcore.models import WBModel
|
|
33
32
|
from wbcore.utils.models import ComplexToStringMixin
|
|
34
33
|
|
|
35
34
|
User: BaseUser = get_user_model()
|
|
@@ -109,13 +108,11 @@ class RiskIncidentMixin(models.Model):
|
|
|
109
108
|
abstract = True
|
|
110
109
|
|
|
111
110
|
|
|
112
|
-
class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin
|
|
111
|
+
class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin):
|
|
113
112
|
incident = models.ForeignKey(
|
|
114
113
|
to="wbcompliance.RiskIncident",
|
|
115
114
|
related_name="checked_object_relationships",
|
|
116
|
-
|
|
117
|
-
blank=True,
|
|
118
|
-
on_delete=models.SET_NULL,
|
|
115
|
+
on_delete=models.CASCADE,
|
|
119
116
|
)
|
|
120
117
|
|
|
121
118
|
rule_check = models.ForeignKey(
|
|
@@ -229,6 +226,9 @@ class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin,
|
|
|
229
226
|
models.Index(fields=["incident", "rule_check"]),
|
|
230
227
|
]
|
|
231
228
|
|
|
229
|
+
def __str__(self) -> str:
|
|
230
|
+
return super().__str__()
|
|
231
|
+
|
|
232
232
|
def compute_str(self) -> str:
|
|
233
233
|
return _("{} {} Sub Incident for checked_object {}").format(self.status, self.severity, self.rule_check)
|
|
234
234
|
|
|
@@ -246,8 +246,12 @@ class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin,
|
|
|
246
246
|
|
|
247
247
|
|
|
248
248
|
class RiskIncidentDefaultManager(models.Manager):
|
|
249
|
+
def __init__(self, only_passive_checks: bool = True):
|
|
250
|
+
self.only_passive_checks = only_passive_checks
|
|
251
|
+
super().__init__()
|
|
252
|
+
|
|
249
253
|
def get_queryset(self):
|
|
250
|
-
|
|
254
|
+
qs = (
|
|
251
255
|
super()
|
|
252
256
|
.get_queryset()
|
|
253
257
|
.annotate(
|
|
@@ -257,9 +261,12 @@ class RiskIncidentDefaultManager(models.Manager):
|
|
|
257
261
|
ignore_until=TruncDate("ignore_until_time"),
|
|
258
262
|
)
|
|
259
263
|
)
|
|
264
|
+
if self.only_passive_checks:
|
|
265
|
+
qs = qs.filter(precheck=False)
|
|
266
|
+
return qs
|
|
260
267
|
|
|
261
268
|
|
|
262
|
-
class RiskIncident(ComplexToStringMixin, RiskIncidentMixin
|
|
269
|
+
class RiskIncident(ComplexToStringMixin, RiskIncidentMixin):
|
|
263
270
|
"""
|
|
264
271
|
Instance defining the incident that has happened during a check initiated by a certain rule
|
|
265
272
|
"""
|
|
@@ -295,6 +302,11 @@ class RiskIncident(ComplexToStringMixin, RiskIncidentMixin, WBModel):
|
|
|
295
302
|
ignore_duration = models.DurationField(
|
|
296
303
|
blank=True, null=True, help_text=_("If set, will ignore the forthcoming incidents for the specified duration")
|
|
297
304
|
)
|
|
305
|
+
precheck = models.BooleanField(
|
|
306
|
+
default=False,
|
|
307
|
+
verbose_name=_("Precheck Incident"),
|
|
308
|
+
help_text="If true, this incident was created during a precheck evaluation",
|
|
309
|
+
)
|
|
298
310
|
|
|
299
311
|
def get_ignore_until_date(self) -> date | None:
|
|
300
312
|
if self.last_ignored_date and self.ignore_duration:
|
|
@@ -365,6 +377,7 @@ class RiskIncident(ComplexToStringMixin, RiskIncidentMixin, WBModel):
|
|
|
365
377
|
return dict()
|
|
366
378
|
|
|
367
379
|
objects = RiskIncidentDefaultManager()
|
|
380
|
+
all_objects = RiskIncidentDefaultManager(only_passive_checks=False)
|
|
368
381
|
|
|
369
382
|
class Meta:
|
|
370
383
|
verbose_name = "Risk Incident"
|
|
@@ -382,6 +395,9 @@ class RiskIncident(ComplexToStringMixin, RiskIncidentMixin, WBModel):
|
|
|
382
395
|
)
|
|
383
396
|
]
|
|
384
397
|
|
|
398
|
+
def __str__(self) -> str:
|
|
399
|
+
return super().__str__()
|
|
400
|
+
|
|
385
401
|
def save(self, *args, **kwargs):
|
|
386
402
|
if not self.breached_object_repr:
|
|
387
403
|
self.breached_object_repr = str(self.breached_content_object)
|
|
@@ -97,8 +97,8 @@ class RiskCheckMixin(models.Model):
|
|
|
97
97
|
)[0]
|
|
98
98
|
if asynchronously:
|
|
99
99
|
transaction.on_commit(
|
|
100
|
-
lambda: evaluate_as_task.delay(
|
|
101
|
-
|
|
100
|
+
lambda check_id=check.id: evaluate_as_task.delay(
|
|
101
|
+
check_id, *dto, override_incident=True, ignore_informational_threshold=True
|
|
102
102
|
)
|
|
103
103
|
)
|
|
104
104
|
else:
|
|
@@ -22,7 +22,6 @@ from django.template.loader import get_template
|
|
|
22
22
|
from django.utils.functional import cached_property
|
|
23
23
|
from django.utils.translation import gettext_lazy as _
|
|
24
24
|
from pandas.tseries.offsets import BDay
|
|
25
|
-
from psycopg.types.range import DateRange
|
|
26
25
|
from rest_framework.reverse import reverse
|
|
27
26
|
from wbcore.contrib.directory.models import Person
|
|
28
27
|
from wbcore.contrib.guardian.models.mixins import PermissionObjectModelMixin
|
|
@@ -33,7 +32,7 @@ from wbcore.utils.rrules import convert_rrulestr_to_dict
|
|
|
33
32
|
|
|
34
33
|
from .backend import AbstractRuleBackend
|
|
35
34
|
from .checks import RiskCheck
|
|
36
|
-
from .incidents import CheckedObjectIncidentRelationship, RiskIncident
|
|
35
|
+
from .incidents import CheckedObjectIncidentRelationship, RiskIncident
|
|
37
36
|
|
|
38
37
|
User: BaseUser = get_user_model()
|
|
39
38
|
|
|
@@ -47,6 +46,9 @@ class RuleGroup(models.Model):
|
|
|
47
46
|
self.name = self.key.title()
|
|
48
47
|
super().save(*args, **kwargs)
|
|
49
48
|
|
|
49
|
+
def __str__(self) -> str:
|
|
50
|
+
return self.name
|
|
51
|
+
|
|
50
52
|
@classmethod
|
|
51
53
|
def get_representation_endpoint(cls) -> str:
|
|
52
54
|
return "wbcompliance:rulegrouprepresentation-list"
|
|
@@ -60,7 +62,7 @@ class RuleGroup(models.Model):
|
|
|
60
62
|
return "{{name}}"
|
|
61
63
|
|
|
62
64
|
|
|
63
|
-
class RuleCheckedObjectRelationship(ComplexToStringMixin
|
|
65
|
+
class RuleCheckedObjectRelationship(ComplexToStringMixin):
|
|
64
66
|
rule = models.ForeignKey(
|
|
65
67
|
to="wbcompliance.RiskRule", related_name="checked_object_relationships", on_delete=models.CASCADE
|
|
66
68
|
)
|
|
@@ -261,7 +263,7 @@ class RuleBackend(models.Model):
|
|
|
261
263
|
return "{{name}}"
|
|
262
264
|
|
|
263
265
|
|
|
264
|
-
class RuleThreshold(ComplexToStringMixin
|
|
266
|
+
class RuleThreshold(ComplexToStringMixin):
|
|
265
267
|
"""
|
|
266
268
|
Represent the list of threshold and its associated severity link to a certain rule
|
|
267
269
|
"""
|
|
@@ -447,7 +449,7 @@ class RiskRule(PermissionObjectModelMixin, WBModel):
|
|
|
447
449
|
def checked_object_representation(self) -> str:
|
|
448
450
|
try:
|
|
449
451
|
backend_class = self.rule_backend.backend_class
|
|
450
|
-
checked_object_repr =
|
|
452
|
+
checked_object_repr = backend_class.OBJECT_FIELD_NAME.title()
|
|
451
453
|
except AttributeError:
|
|
452
454
|
checked_object_repr = "Object"
|
|
453
455
|
return checked_object_repr
|
|
@@ -508,69 +510,6 @@ class RiskRule(PermissionObjectModelMixin, WBModel):
|
|
|
508
510
|
|
|
509
511
|
return permissions
|
|
510
512
|
|
|
511
|
-
def get_or_create_incident(
|
|
512
|
-
self,
|
|
513
|
-
evaluation_date: date,
|
|
514
|
-
incident_severity: "RiskIncidentType",
|
|
515
|
-
breached_object: Any,
|
|
516
|
-
breached_object_repr: str,
|
|
517
|
-
) -> tuple[RiskIncident, bool]:
|
|
518
|
-
"""
|
|
519
|
-
Utility function to get or create incident base on the given breached object
|
|
520
|
-
|
|
521
|
-
Args:
|
|
522
|
-
rule: The rule this incident happens
|
|
523
|
-
evaluation_date: The incident date
|
|
524
|
-
incident_severity: The incident severity
|
|
525
|
-
breached_object: The breached object (i.e. the object that triggers the incident)
|
|
526
|
-
breached_object_repr: Its string representation
|
|
527
|
-
|
|
528
|
-
Returns:
|
|
529
|
-
A tuple (incident, is_created)
|
|
530
|
-
"""
|
|
531
|
-
|
|
532
|
-
# Consider that if an incident happens one business day in the future or past, it is continue
|
|
533
|
-
date_range = DateRange( # type: ignore
|
|
534
|
-
(evaluation_date - BDay(1)).date(), (evaluation_date + BDay(1)).date(), "[]"
|
|
535
|
-
)
|
|
536
|
-
incidents = RiskIncident.objects.filter(rule=self, date_range__overlap=date_range)
|
|
537
|
-
if breached_object:
|
|
538
|
-
# If a breached_object is provided, we lookup over it
|
|
539
|
-
incidents = incidents.filter(
|
|
540
|
-
breached_content_type=ContentType.objects.get_for_model(breached_object),
|
|
541
|
-
breached_object_id=breached_object.id,
|
|
542
|
-
)
|
|
543
|
-
else:
|
|
544
|
-
# Otherwise, we lookup over its string representation. Might need to change as this is not very robust
|
|
545
|
-
incidents = incidents.filter(
|
|
546
|
-
breached_object_repr=breached_object_repr,
|
|
547
|
-
)
|
|
548
|
-
if incident := incidents.first():
|
|
549
|
-
incident.date_range = DateRange(
|
|
550
|
-
lower=incident.date_range.lower, upper=(evaluation_date + timedelta(days=1))
|
|
551
|
-
) # type: ignore
|
|
552
|
-
if self.automatically_close_incident:
|
|
553
|
-
incident.status = RiskIncident.Status.CLOSED
|
|
554
|
-
incident.save()
|
|
555
|
-
return incident, False
|
|
556
|
-
else:
|
|
557
|
-
return (
|
|
558
|
-
RiskIncident.objects.create(
|
|
559
|
-
rule=self,
|
|
560
|
-
date_range=DateRange(lower=evaluation_date, upper=(evaluation_date + timedelta(days=1))), # type: ignore
|
|
561
|
-
breached_content_type=ContentType.objects.get_for_model(breached_object)
|
|
562
|
-
if breached_object
|
|
563
|
-
else None,
|
|
564
|
-
breached_object_id=breached_object.id if breached_object else None,
|
|
565
|
-
breached_object_repr=breached_object_repr,
|
|
566
|
-
severity=incident_severity,
|
|
567
|
-
status=RiskIncident.Status.CLOSED
|
|
568
|
-
if self.automatically_close_incident
|
|
569
|
-
else RiskIncident.Status.OPEN,
|
|
570
|
-
),
|
|
571
|
-
True,
|
|
572
|
-
)
|
|
573
|
-
|
|
574
513
|
def notify(self, evaluation_date: date):
|
|
575
514
|
"""
|
|
576
515
|
Create the notification for this rule relationship and all implied persons
|
|
@@ -659,7 +598,7 @@ class RiskRule(PermissionObjectModelMixin, WBModel):
|
|
|
659
598
|
def pre_save_risk_threshold(sender, instance, **kwargs):
|
|
660
599
|
with suppress(RuleThreshold.DoesNotExist):
|
|
661
600
|
pre_save_instance = RuleThreshold.objects.get(id=instance.id)
|
|
662
|
-
RiskIncident.
|
|
601
|
+
RiskIncident.all_objects.filter(rule=instance.rule, severity=pre_save_instance.severity).update(
|
|
663
602
|
severity=instance.severity
|
|
664
603
|
)
|
|
665
604
|
CheckedObjectIncidentRelationship.objects.filter(
|
|
@@ -669,7 +608,7 @@ def pre_save_risk_threshold(sender, instance, **kwargs):
|
|
|
669
608
|
|
|
670
609
|
@receiver(pre_delete, sender="wbcompliance.RuleThreshold")
|
|
671
610
|
def pre_delete_risk_threshold(sender, instance, **kwargs):
|
|
672
|
-
RiskIncident.
|
|
611
|
+
RiskIncident.all_objects.filter(rule=instance.rule, severity=instance.severity).delete()
|
|
673
612
|
CheckedObjectIncidentRelationship.objects.filter(incident__rule=instance.rule, severity=instance.severity).delete()
|
|
674
613
|
|
|
675
614
|
|
{wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/serializers/risk_management/checks.py
RENAMED
|
@@ -17,7 +17,7 @@ class RiskCheckModelSerializer(wb_serializers.ModelSerializer):
|
|
|
17
17
|
_rule = RiskRuleRepresentationSerializer(source="rule")
|
|
18
18
|
_checked_object_content_type = ContentTypeRepresentationSerializer(source="checked_object_content_type")
|
|
19
19
|
|
|
20
|
-
incident_reports = wb_serializers.TextField()
|
|
20
|
+
incident_reports = wb_serializers.TextField(read_only=True)
|
|
21
21
|
status_icon = IconSelectField(read_only=True)
|
|
22
22
|
|
|
23
23
|
@wb_serializers.register_resource()
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
2
|
|
|
3
|
-
from django.db.models.signals import
|
|
3
|
+
from django.db.models.signals import (
|
|
4
|
+
post_delete,
|
|
5
|
+
post_init,
|
|
6
|
+
post_migrate,
|
|
7
|
+
post_save,
|
|
8
|
+
pre_delete,
|
|
9
|
+
pre_init,
|
|
10
|
+
pre_migrate,
|
|
11
|
+
pre_save,
|
|
12
|
+
)
|
|
4
13
|
|
|
5
14
|
|
|
6
15
|
class DisableSignals(object):
|
|
@@ -50,7 +59,7 @@ class DisableSignals(object):
|
|
|
50
59
|
# self.disconnect(signal)
|
|
51
60
|
|
|
52
61
|
|
|
53
|
-
class
|
|
62
|
+
class TempDisconnectSignal:
|
|
54
63
|
"""Temporarily disconnect a model from a signal"""
|
|
55
64
|
|
|
56
65
|
def __init__(self, signal, receiver, sender, dispatch_uid=None):
|
|
@@ -72,11 +81,3 @@ class temp_disconnect_signal:
|
|
|
72
81
|
sender=self.sender,
|
|
73
82
|
dispatch_uid=self.dispatch_uid,
|
|
74
83
|
)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class DisableSignalsNotification(temp_disconnect_signal):
|
|
78
|
-
def __init__(self, dispatch_uid=None):
|
|
79
|
-
self.signal = post_save
|
|
80
|
-
self.receiver = post_create_notification
|
|
81
|
-
self.sender = Notification
|
|
82
|
-
self.dispatch_uid = dispatch_uid
|
|
@@ -85,7 +85,7 @@ class TestRiskIncidentFactory:
|
|
|
85
85
|
(fake.date_object(), False),
|
|
86
86
|
],
|
|
87
87
|
)
|
|
88
|
-
def test_get_or_create_incident(self,
|
|
88
|
+
def test_get_or_create_incident(self, risk_check, risk_incident_type, evaluation_date, is_breached_object):
|
|
89
89
|
if is_breached_object:
|
|
90
90
|
breached_object = get_anonymous_user()
|
|
91
91
|
breached_object_repr = str(get_anonymous_user())
|
|
@@ -94,11 +94,11 @@ class TestRiskIncidentFactory:
|
|
|
94
94
|
breached_object_repr = fake.text(max_nb_chars=125)
|
|
95
95
|
|
|
96
96
|
assert not RiskIncident.objects.exists()
|
|
97
|
-
|
|
97
|
+
risk_check.get_or_create_incident(evaluation_date, risk_incident_type, breached_object, breached_object_repr)
|
|
98
98
|
if breached_object:
|
|
99
99
|
assert (
|
|
100
100
|
RiskIncident.objects.filter(
|
|
101
|
-
rule=
|
|
101
|
+
rule=risk_check.rule,
|
|
102
102
|
date_range__contains=evaluation_date,
|
|
103
103
|
breached_content_type=ContentType.objects.get_for_model(breached_object),
|
|
104
104
|
breached_object_id=breached_object.id,
|
|
@@ -108,19 +108,21 @@ class TestRiskIncidentFactory:
|
|
|
108
108
|
else:
|
|
109
109
|
assert (
|
|
110
110
|
RiskIncident.objects.filter(
|
|
111
|
-
rule=
|
|
111
|
+
rule=risk_check.rule,
|
|
112
|
+
date_range__contains=evaluation_date,
|
|
113
|
+
breached_object_repr=breached_object_repr,
|
|
112
114
|
).count()
|
|
113
115
|
== 1
|
|
114
116
|
)
|
|
115
117
|
assert RiskIncident.objects.count() == 1
|
|
116
118
|
# Check if we reevaluate this incident one business day later, the incident is consider the same
|
|
117
|
-
|
|
119
|
+
risk_check.get_or_create_incident(
|
|
118
120
|
(evaluation_date + BDay(1)).date(), risk_incident_type, breached_object, breached_object_repr
|
|
119
121
|
)
|
|
120
122
|
assert RiskIncident.objects.count() == 1
|
|
121
123
|
|
|
122
124
|
# Check if we reevaluate this incident three business day later, the incident is consider the discontinue, and then a new incident is created
|
|
123
|
-
|
|
125
|
+
risk_check.get_or_create_incident(
|
|
124
126
|
(evaluation_date + BDay(3)).date(), risk_incident_type, breached_object, breached_object_repr
|
|
125
127
|
)
|
|
126
128
|
|
|
@@ -135,7 +137,7 @@ class TestRiskIncidentFactory:
|
|
|
135
137
|
risk_incident.save()
|
|
136
138
|
assert risk_incident.status == RiskIncident.Status.RESOLVED
|
|
137
139
|
new_evaluation_date = subincident.rule_check.evaluation_date + timedelta(days=1)
|
|
138
|
-
incident, created =
|
|
140
|
+
incident, created = subincident.rule_check.get_or_create_incident(
|
|
139
141
|
new_evaluation_date,
|
|
140
142
|
subincident.severity,
|
|
141
143
|
risk_incident.breached_content_object,
|
|
@@ -342,7 +342,7 @@ class TestSpecificViewsets(UserTestMixin):
|
|
|
342
342
|
assert response.data.get("results")
|
|
343
343
|
|
|
344
344
|
@pytest.mark.parametrize("mvs", [ComplianceTaskMatrixPandasViewSet])
|
|
345
|
-
def
|
|
345
|
+
def test_pandasapiview(self, mvs, compliance_task_factory, compliance_task_instance_factory):
|
|
346
346
|
request = APIRequestFactory().get("")
|
|
347
347
|
request.user = get_or_create_superuser()
|
|
348
348
|
|
{wbcompliance-1.54.19 → wbcompliance-1.59.2}/wbcompliance/viewsets/buttons/compliance_form.py
RENAMED
|
@@ -20,9 +20,9 @@ class AbstractComplianceDocumentButtonConfig:
|
|
|
20
20
|
return bt.ActionButton(
|
|
21
21
|
method=RequestType.PATCH,
|
|
22
22
|
key="regenerate_document",
|
|
23
|
-
action_label=_("
|
|
24
|
-
title=_("
|
|
25
|
-
label=_("
|
|
23
|
+
action_label=_("PDF Document is being generated"),
|
|
24
|
+
title=_("Generate PDF Document"),
|
|
25
|
+
label=_("Generate PDF Document"),
|
|
26
26
|
icon=WBIcon.DOCUMENT.icon,
|
|
27
27
|
serializer=ComplianceDocumentSerializer,
|
|
28
28
|
instance_display=create_simple_display([["send_email"]]),
|