wbcompliance 2.2.1__py2.py3-none-any.whl
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/__init__.py +1 -0
- wbcompliance/admin/__init__.py +16 -0
- wbcompliance/admin/compliance_form.py +56 -0
- wbcompliance/admin/compliance_task.py +135 -0
- wbcompliance/admin/compliance_type.py +8 -0
- wbcompliance/admin/risk_management/__init__.py +3 -0
- wbcompliance/admin/risk_management/checks.py +7 -0
- wbcompliance/admin/risk_management/incidents.py +50 -0
- wbcompliance/admin/risk_management/rules.py +63 -0
- wbcompliance/admin/utils.py +46 -0
- wbcompliance/apps.py +14 -0
- wbcompliance/factories/__init__.py +21 -0
- wbcompliance/factories/compliance.py +246 -0
- wbcompliance/factories/risk_management/__init__.py +12 -0
- wbcompliance/factories/risk_management/backends.py +42 -0
- wbcompliance/factories/risk_management/checks.py +12 -0
- wbcompliance/factories/risk_management/incidents.py +84 -0
- wbcompliance/factories/risk_management/rules.py +100 -0
- wbcompliance/filters/__init__.py +2 -0
- wbcompliance/filters/compliances.py +189 -0
- wbcompliance/filters/risk_management/__init__.py +3 -0
- wbcompliance/filters/risk_management/checks.py +22 -0
- wbcompliance/filters/risk_management/incidents.py +113 -0
- wbcompliance/filters/risk_management/rules.py +110 -0
- wbcompliance/filters/risk_management/tables.py +112 -0
- wbcompliance/filters/risk_management/utils.py +3 -0
- wbcompliance/management/__init__.py +10 -0
- wbcompliance/migrations/0001_initial_squashed_squashed_0010_alter_checkedobjectincidentrelationship_resolved_by_and_more.py +1744 -0
- wbcompliance/migrations/0011_alter_riskrule_parameters.py +21 -0
- wbcompliance/migrations/0012_alter_compliancetype_options.py +20 -0
- wbcompliance/migrations/0013_alter_riskrule_unique_together.py +16 -0
- wbcompliance/migrations/0014_alter_reviewcompliancetask_year.py +27 -0
- wbcompliance/migrations/0015_auto_20240103_0957.py +43 -0
- wbcompliance/migrations/0016_checkedobjectincidentrelationship_report_details_and_more.py +37 -0
- wbcompliance/migrations/0017_alter_rulebackend_incident_report_template.py +20 -0
- wbcompliance/migrations/0018_alter_rulecheckedobjectrelationship_unique_together.py +39 -0
- wbcompliance/migrations/0019_rulegroup_riskrule_activation_date_and_more.py +60 -0
- wbcompliance/migrations/__init__.py +0 -0
- wbcompliance/models/__init__.py +20 -0
- wbcompliance/models/compliance_form.py +626 -0
- wbcompliance/models/compliance_task.py +800 -0
- wbcompliance/models/compliance_type.py +133 -0
- wbcompliance/models/enums.py +13 -0
- wbcompliance/models/risk_management/__init__.py +4 -0
- wbcompliance/models/risk_management/backend.py +139 -0
- wbcompliance/models/risk_management/checks.py +194 -0
- wbcompliance/models/risk_management/dispatch.py +41 -0
- wbcompliance/models/risk_management/incidents.py +619 -0
- wbcompliance/models/risk_management/mixins.py +115 -0
- wbcompliance/models/risk_management/rules.py +654 -0
- wbcompliance/permissions.py +32 -0
- wbcompliance/serializers/__init__.py +30 -0
- wbcompliance/serializers/compliance_form.py +320 -0
- wbcompliance/serializers/compliance_task.py +463 -0
- wbcompliance/serializers/compliance_type.py +26 -0
- wbcompliance/serializers/risk_management/__init__.py +19 -0
- wbcompliance/serializers/risk_management/checks.py +53 -0
- wbcompliance/serializers/risk_management/incidents.py +227 -0
- wbcompliance/serializers/risk_management/rules.py +158 -0
- wbcompliance/tasks.py +112 -0
- wbcompliance/tests/__init__.py +0 -0
- wbcompliance/tests/conftest.py +63 -0
- wbcompliance/tests/disable_signals.py +82 -0
- wbcompliance/tests/mixins.py +17 -0
- wbcompliance/tests/risk_management/__init__.py +0 -0
- wbcompliance/tests/risk_management/models/__init__.py +0 -0
- wbcompliance/tests/risk_management/models/test_backends.py +0 -0
- wbcompliance/tests/risk_management/models/test_checks.py +55 -0
- wbcompliance/tests/risk_management/models/test_incidents.py +327 -0
- wbcompliance/tests/risk_management/models/test_rules.py +255 -0
- wbcompliance/tests/signals.py +89 -0
- wbcompliance/tests/test_filters.py +23 -0
- wbcompliance/tests/test_models.py +57 -0
- wbcompliance/tests/test_serializers.py +48 -0
- wbcompliance/tests/test_views.py +377 -0
- wbcompliance/tests/tests.py +21 -0
- wbcompliance/urls.py +238 -0
- wbcompliance/viewsets/__init__.py +40 -0
- wbcompliance/viewsets/buttons/__init__.py +9 -0
- wbcompliance/viewsets/buttons/compliance_form.py +78 -0
- wbcompliance/viewsets/buttons/compliance_task.py +149 -0
- wbcompliance/viewsets/buttons/risk_managment/__init__.py +3 -0
- wbcompliance/viewsets/buttons/risk_managment/checks.py +11 -0
- wbcompliance/viewsets/buttons/risk_managment/incidents.py +51 -0
- wbcompliance/viewsets/buttons/risk_managment/rules.py +35 -0
- wbcompliance/viewsets/compliance_form.py +425 -0
- wbcompliance/viewsets/compliance_task.py +513 -0
- wbcompliance/viewsets/compliance_type.py +38 -0
- wbcompliance/viewsets/display/__init__.py +22 -0
- wbcompliance/viewsets/display/compliance_form.py +317 -0
- wbcompliance/viewsets/display/compliance_task.py +453 -0
- wbcompliance/viewsets/display/compliance_type.py +22 -0
- wbcompliance/viewsets/display/risk_managment/__init__.py +11 -0
- wbcompliance/viewsets/display/risk_managment/checks.py +46 -0
- wbcompliance/viewsets/display/risk_managment/incidents.py +155 -0
- wbcompliance/viewsets/display/risk_managment/rules.py +146 -0
- wbcompliance/viewsets/display/risk_managment/tables.py +51 -0
- wbcompliance/viewsets/endpoints/__init__.py +27 -0
- wbcompliance/viewsets/endpoints/compliance_form.py +207 -0
- wbcompliance/viewsets/endpoints/compliance_task.py +193 -0
- wbcompliance/viewsets/endpoints/compliance_type.py +9 -0
- wbcompliance/viewsets/endpoints/risk_managment/__init__.py +12 -0
- wbcompliance/viewsets/endpoints/risk_managment/checks.py +16 -0
- wbcompliance/viewsets/endpoints/risk_managment/incidents.py +36 -0
- wbcompliance/viewsets/endpoints/risk_managment/rules.py +32 -0
- wbcompliance/viewsets/endpoints/risk_managment/tables.py +14 -0
- wbcompliance/viewsets/menu/__init__.py +17 -0
- wbcompliance/viewsets/menu/compliance_form.py +49 -0
- wbcompliance/viewsets/menu/compliance_task.py +130 -0
- wbcompliance/viewsets/menu/compliance_type.py +17 -0
- wbcompliance/viewsets/menu/risk_management.py +56 -0
- wbcompliance/viewsets/risk_management/__init__.py +21 -0
- wbcompliance/viewsets/risk_management/checks.py +49 -0
- wbcompliance/viewsets/risk_management/incidents.py +204 -0
- wbcompliance/viewsets/risk_management/mixins.py +52 -0
- wbcompliance/viewsets/risk_management/rules.py +179 -0
- wbcompliance/viewsets/risk_management/tables.py +96 -0
- wbcompliance/viewsets/titles/__init__.py +17 -0
- wbcompliance/viewsets/titles/compliance_form.py +101 -0
- wbcompliance/viewsets/titles/compliance_task.py +60 -0
- wbcompliance/viewsets/titles/compliance_type.py +13 -0
- wbcompliance/viewsets/titles/risk_managment/__init__.py +1 -0
- wbcompliance/viewsets/titles/risk_managment/checks.py +0 -0
- wbcompliance/viewsets/titles/risk_managment/incidents.py +0 -0
- wbcompliance/viewsets/titles/risk_managment/rules.py +0 -0
- wbcompliance/viewsets/titles/risk_managment/tables.py +7 -0
- wbcompliance-2.2.1.dist-info/METADATA +7 -0
- wbcompliance-2.2.1.dist-info/RECORD +129 -0
- wbcompliance-2.2.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from django.db.models import Count, F, OuterRef, Q, Subquery
|
|
2
|
+
from django.db.models.functions import Coalesce
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
|
+
from wbcompliance.models.risk_management import RiskRule, RuleThreshold
|
|
5
|
+
from wbcore import filters as wb_filters
|
|
6
|
+
from wbcore.contrib.directory.models import Person
|
|
7
|
+
|
|
8
|
+
from ...models.risk_management.rules import RuleGroup
|
|
9
|
+
from .utils import get_default_handler
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RiskRuleFilterSet(wb_filters.FilterSet):
|
|
13
|
+
checked_object_relationships = wb_filters.MultipleChoiceContentTypeFilter(
|
|
14
|
+
label="Checked Objects",
|
|
15
|
+
field_name="checked_object_relationships",
|
|
16
|
+
distinct=True,
|
|
17
|
+
object_id_label="checked_object_relationships__checked_object_id",
|
|
18
|
+
content_type_label="checked_object_relationships__checked_object_content_type",
|
|
19
|
+
hidden=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
exclude_informational_rule = wb_filters.BooleanFilter(
|
|
23
|
+
method="filter_exclude_informational_rule", default=True, label=_("Exclude Informational Rule")
|
|
24
|
+
)
|
|
25
|
+
rule_group = wb_filters.ModelChoiceFilter(
|
|
26
|
+
label=_("Group"),
|
|
27
|
+
queryset=RuleGroup.objects.all(),
|
|
28
|
+
endpoint=RuleGroup.get_representation_endpoint(),
|
|
29
|
+
value_key=RuleGroup.get_representation_value_key(),
|
|
30
|
+
label_key=RuleGroup.get_representation_label_key(),
|
|
31
|
+
method="filter_rule_group",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def filter_rule_group(self, queryset, label, value):
|
|
35
|
+
if value:
|
|
36
|
+
return queryset.filter(Q(rule_backend__rule_group=value) | Q(rule_backend__rule_group__isnull=True))
|
|
37
|
+
return queryset
|
|
38
|
+
|
|
39
|
+
def filter_exclude_informational_rule(self, queryset, label, value):
|
|
40
|
+
if value:
|
|
41
|
+
queryset = queryset.annotate(
|
|
42
|
+
threshold_count=Coalesce(
|
|
43
|
+
Subquery(
|
|
44
|
+
RuleThreshold.objects.filter(rule=OuterRef("pk"))
|
|
45
|
+
.values("rule")
|
|
46
|
+
.annotate(c=Count("rule"))
|
|
47
|
+
.values("c")[:1]
|
|
48
|
+
),
|
|
49
|
+
0,
|
|
50
|
+
),
|
|
51
|
+
informational_count=Coalesce(
|
|
52
|
+
Subquery(
|
|
53
|
+
RuleThreshold.objects.filter(rule=OuterRef("pk"), severity__is_informational=True)
|
|
54
|
+
.values("rule")
|
|
55
|
+
.annotate(c=Count("rule"))
|
|
56
|
+
.values("c")[:1]
|
|
57
|
+
),
|
|
58
|
+
0,
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
return queryset.exclude(threshold_count=F("informational_count"))
|
|
62
|
+
return queryset
|
|
63
|
+
|
|
64
|
+
in_breach = wb_filters.ChoiceFilter(
|
|
65
|
+
method="filter_in_breach",
|
|
66
|
+
label=_("Open Incidents"),
|
|
67
|
+
choices=[("BREACH", "In Breach"), ("PASSED", "Passed"), ("INACTIVE", "Inactive")],
|
|
68
|
+
)
|
|
69
|
+
open_incidents_count = wb_filters.NumberFilter(
|
|
70
|
+
label=_("Opened Incident"), field_name="open_incidents_count", lookup_expr="exact"
|
|
71
|
+
)
|
|
72
|
+
open_incidents_count__lte = wb_filters.NumberFilter(
|
|
73
|
+
label=_("Opened Incident"), field_name="open_incidents_count", lookup_expr="lte"
|
|
74
|
+
)
|
|
75
|
+
open_incidents_count__gte = wb_filters.NumberFilter(
|
|
76
|
+
label=_("Opened Incident"), field_name="open_incidents_count", lookup_expr="gte"
|
|
77
|
+
)
|
|
78
|
+
notified_by = wb_filters.ModelChoiceFilter(
|
|
79
|
+
label=_("Notifed Users"),
|
|
80
|
+
default=get_default_handler,
|
|
81
|
+
queryset=Person.objects.all(),
|
|
82
|
+
endpoint=Person.get_representation_endpoint(),
|
|
83
|
+
value_key=Person.get_representation_value_key(),
|
|
84
|
+
label_key=Person.get_representation_label_key(),
|
|
85
|
+
method="filter_notified_by",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def filter_notified_by(self, queryset, name, value):
|
|
89
|
+
if value:
|
|
90
|
+
thresholds = RuleThreshold.objects.filter(
|
|
91
|
+
Q(notifiable_users=value) | Q(notifiable_groups__in=value.user_account.groups.all())
|
|
92
|
+
)
|
|
93
|
+
return queryset.filter(thresholds__in=thresholds).distinct()
|
|
94
|
+
return queryset
|
|
95
|
+
|
|
96
|
+
def filter_in_breach(self, queryset, name, value):
|
|
97
|
+
if value:
|
|
98
|
+
return queryset.filter(in_breach=value)
|
|
99
|
+
return queryset
|
|
100
|
+
|
|
101
|
+
class Meta:
|
|
102
|
+
model = RiskRule
|
|
103
|
+
fields = {
|
|
104
|
+
"rule_backend": ["exact"],
|
|
105
|
+
"is_enable": ["exact"],
|
|
106
|
+
"only_passive_check_allowed": ["exact"],
|
|
107
|
+
"is_silent": ["exact"],
|
|
108
|
+
"is_mandatory": ["exact"],
|
|
109
|
+
"automatically_close_incident": ["exact"],
|
|
110
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from django.contrib.contenttypes.models import ContentType
|
|
2
|
+
from django.db.models import Count, Q
|
|
3
|
+
from django.dispatch import receiver
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
from wbcompliance.models.risk_management import CheckedObjectIncidentRelationship
|
|
6
|
+
from wbcore import filters as wb_filters
|
|
7
|
+
from wbcore.signals.filters import add_filters
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_content_type_default(*args, **kwargs):
|
|
11
|
+
content_type_id = (
|
|
12
|
+
CheckedObjectIncidentRelationship.objects.values(
|
|
13
|
+
"rule_check__rule_checked_object_relationship__checked_object_content_type"
|
|
14
|
+
)
|
|
15
|
+
.annotate(c=Count("rule_check__rule_checked_object_relationship__checked_object_content_type"))
|
|
16
|
+
.order_by("c")
|
|
17
|
+
.first()["rule_check__rule_checked_object_relationship__checked_object_content_type"]
|
|
18
|
+
)
|
|
19
|
+
return ContentType.objects.get(id=content_type_id).id
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def filter_date_range(queryset, label, value):
|
|
23
|
+
if value:
|
|
24
|
+
return queryset.filter(
|
|
25
|
+
Q(rule_check__evaluation_date__gte=value.lower) & Q(rule_check__evaluation_date__lte=value.upper)
|
|
26
|
+
)
|
|
27
|
+
return queryset
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RiskManagementIncidentFilter(wb_filters.FilterSet):
|
|
31
|
+
incident_date_range = wb_filters.DateRangeFilter(label=_("Date Range"), method=filter_date_range)
|
|
32
|
+
only_open_incident = wb_filters.BooleanFilter(
|
|
33
|
+
default=True, method="filter_only_open_incident", label=_("Only open incidents")
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
checked_object_content_type = wb_filters.ModelChoiceFilter(
|
|
37
|
+
required=True,
|
|
38
|
+
method="filter_checked_object_content_type",
|
|
39
|
+
queryset=ContentType.objects.all(),
|
|
40
|
+
endpoint="wbcore:contenttyperepresentation-list",
|
|
41
|
+
value_key="id",
|
|
42
|
+
label_key="{{app_label}} | {{model}}",
|
|
43
|
+
label=_("Checked Object Type"),
|
|
44
|
+
default=get_content_type_default,
|
|
45
|
+
filter_params={"related_name_isnull": "risk_management_checked_objects"},
|
|
46
|
+
clearable=False,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def filter_checked_object_content_type(self, queryset, label, value):
|
|
50
|
+
if value:
|
|
51
|
+
return queryset.filter(rule_check__rule_checked_object_relationship__checked_object_content_type=value)
|
|
52
|
+
return queryset
|
|
53
|
+
|
|
54
|
+
def filter_only_open_incident(self, queryset, name, value):
|
|
55
|
+
if value:
|
|
56
|
+
return queryset.filter(status=CheckedObjectIncidentRelationship.Status.OPEN)
|
|
57
|
+
return queryset
|
|
58
|
+
|
|
59
|
+
class Meta:
|
|
60
|
+
model = CheckedObjectIncidentRelationship
|
|
61
|
+
fields = {
|
|
62
|
+
# "rule_backend": ["exact"],
|
|
63
|
+
# "is_enable": ["exact"],
|
|
64
|
+
# "only_passive_check_allowed": ["exact"],
|
|
65
|
+
# "is_silent": ["exact"],
|
|
66
|
+
# "is_mandatory": ["exact"],
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@receiver(add_filters, sender=RiskManagementIncidentFilter)
|
|
71
|
+
def add_checked_object_repr_filter(sender, request=None, *args, **kwargs):
|
|
72
|
+
content_type = None
|
|
73
|
+
if request and (content_type_id := request.GET.get("checked_object_content_type", None)):
|
|
74
|
+
content_type = ContentType.objects.get(id=content_type_id)
|
|
75
|
+
elif default_callback := getattr(sender, "default", None):
|
|
76
|
+
content_type = ContentType.objects.get(id=default_callback())
|
|
77
|
+
if content_type:
|
|
78
|
+
|
|
79
|
+
def filter_checked_object_repr(queryset, label, value):
|
|
80
|
+
if value:
|
|
81
|
+
return queryset.filter(rule_check__rule_checked_object_relationship__checked_object_id=value.id)
|
|
82
|
+
return queryset
|
|
83
|
+
|
|
84
|
+
model_class = content_type.model_class()
|
|
85
|
+
return {
|
|
86
|
+
"checked_object_repr": wb_filters.ModelChoiceFilter(
|
|
87
|
+
label=content_type.name,
|
|
88
|
+
field_name="checked_object_repr",
|
|
89
|
+
queryset=model_class.objects.all(),
|
|
90
|
+
endpoint=model_class.get_representation_endpoint(),
|
|
91
|
+
value_key=model_class.get_representation_value_key(),
|
|
92
|
+
label_key=model_class.get_representation_label_key(),
|
|
93
|
+
method=filter_checked_object_repr,
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
else:
|
|
97
|
+
|
|
98
|
+
def filter_checked_object_repr(queryset, label, value):
|
|
99
|
+
if value:
|
|
100
|
+
return queryset.filter(
|
|
101
|
+
rule_check__rule_checked_object_relationship__checked_object_repr__icontains=value
|
|
102
|
+
)
|
|
103
|
+
return queryset
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"checked_object_repr": wb_filters.CharFilter(
|
|
107
|
+
label=_("Checked Object Repr."),
|
|
108
|
+
method=filter_checked_object_repr,
|
|
109
|
+
lookup_expr="icontains",
|
|
110
|
+
field_name="checked_object_repr",
|
|
111
|
+
)
|
|
112
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from django.utils.module_loading import autodiscover_modules
|
|
2
|
+
from django.db import DEFAULT_DB_ALIAS
|
|
3
|
+
from django.apps import apps as global_apps
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def autodiscover_riskmanagement_backends(
|
|
7
|
+
app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, apps=global_apps, **kwargs
|
|
8
|
+
):
|
|
9
|
+
# we wrap the autodiscover into a post_migrate receiver because we expect db calls
|
|
10
|
+
autodiscover_modules("risk_management.backends")
|