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.
Files changed (129) hide show
  1. wbcompliance/__init__.py +1 -0
  2. wbcompliance/admin/__init__.py +16 -0
  3. wbcompliance/admin/compliance_form.py +56 -0
  4. wbcompliance/admin/compliance_task.py +135 -0
  5. wbcompliance/admin/compliance_type.py +8 -0
  6. wbcompliance/admin/risk_management/__init__.py +3 -0
  7. wbcompliance/admin/risk_management/checks.py +7 -0
  8. wbcompliance/admin/risk_management/incidents.py +50 -0
  9. wbcompliance/admin/risk_management/rules.py +63 -0
  10. wbcompliance/admin/utils.py +46 -0
  11. wbcompliance/apps.py +14 -0
  12. wbcompliance/factories/__init__.py +21 -0
  13. wbcompliance/factories/compliance.py +246 -0
  14. wbcompliance/factories/risk_management/__init__.py +12 -0
  15. wbcompliance/factories/risk_management/backends.py +42 -0
  16. wbcompliance/factories/risk_management/checks.py +12 -0
  17. wbcompliance/factories/risk_management/incidents.py +84 -0
  18. wbcompliance/factories/risk_management/rules.py +100 -0
  19. wbcompliance/filters/__init__.py +2 -0
  20. wbcompliance/filters/compliances.py +189 -0
  21. wbcompliance/filters/risk_management/__init__.py +3 -0
  22. wbcompliance/filters/risk_management/checks.py +22 -0
  23. wbcompliance/filters/risk_management/incidents.py +113 -0
  24. wbcompliance/filters/risk_management/rules.py +110 -0
  25. wbcompliance/filters/risk_management/tables.py +112 -0
  26. wbcompliance/filters/risk_management/utils.py +3 -0
  27. wbcompliance/management/__init__.py +10 -0
  28. wbcompliance/migrations/0001_initial_squashed_squashed_0010_alter_checkedobjectincidentrelationship_resolved_by_and_more.py +1744 -0
  29. wbcompliance/migrations/0011_alter_riskrule_parameters.py +21 -0
  30. wbcompliance/migrations/0012_alter_compliancetype_options.py +20 -0
  31. wbcompliance/migrations/0013_alter_riskrule_unique_together.py +16 -0
  32. wbcompliance/migrations/0014_alter_reviewcompliancetask_year.py +27 -0
  33. wbcompliance/migrations/0015_auto_20240103_0957.py +43 -0
  34. wbcompliance/migrations/0016_checkedobjectincidentrelationship_report_details_and_more.py +37 -0
  35. wbcompliance/migrations/0017_alter_rulebackend_incident_report_template.py +20 -0
  36. wbcompliance/migrations/0018_alter_rulecheckedobjectrelationship_unique_together.py +39 -0
  37. wbcompliance/migrations/0019_rulegroup_riskrule_activation_date_and_more.py +60 -0
  38. wbcompliance/migrations/__init__.py +0 -0
  39. wbcompliance/models/__init__.py +20 -0
  40. wbcompliance/models/compliance_form.py +626 -0
  41. wbcompliance/models/compliance_task.py +800 -0
  42. wbcompliance/models/compliance_type.py +133 -0
  43. wbcompliance/models/enums.py +13 -0
  44. wbcompliance/models/risk_management/__init__.py +4 -0
  45. wbcompliance/models/risk_management/backend.py +139 -0
  46. wbcompliance/models/risk_management/checks.py +194 -0
  47. wbcompliance/models/risk_management/dispatch.py +41 -0
  48. wbcompliance/models/risk_management/incidents.py +619 -0
  49. wbcompliance/models/risk_management/mixins.py +115 -0
  50. wbcompliance/models/risk_management/rules.py +654 -0
  51. wbcompliance/permissions.py +32 -0
  52. wbcompliance/serializers/__init__.py +30 -0
  53. wbcompliance/serializers/compliance_form.py +320 -0
  54. wbcompliance/serializers/compliance_task.py +463 -0
  55. wbcompliance/serializers/compliance_type.py +26 -0
  56. wbcompliance/serializers/risk_management/__init__.py +19 -0
  57. wbcompliance/serializers/risk_management/checks.py +53 -0
  58. wbcompliance/serializers/risk_management/incidents.py +227 -0
  59. wbcompliance/serializers/risk_management/rules.py +158 -0
  60. wbcompliance/tasks.py +112 -0
  61. wbcompliance/tests/__init__.py +0 -0
  62. wbcompliance/tests/conftest.py +63 -0
  63. wbcompliance/tests/disable_signals.py +82 -0
  64. wbcompliance/tests/mixins.py +17 -0
  65. wbcompliance/tests/risk_management/__init__.py +0 -0
  66. wbcompliance/tests/risk_management/models/__init__.py +0 -0
  67. wbcompliance/tests/risk_management/models/test_backends.py +0 -0
  68. wbcompliance/tests/risk_management/models/test_checks.py +55 -0
  69. wbcompliance/tests/risk_management/models/test_incidents.py +327 -0
  70. wbcompliance/tests/risk_management/models/test_rules.py +255 -0
  71. wbcompliance/tests/signals.py +89 -0
  72. wbcompliance/tests/test_filters.py +23 -0
  73. wbcompliance/tests/test_models.py +57 -0
  74. wbcompliance/tests/test_serializers.py +48 -0
  75. wbcompliance/tests/test_views.py +377 -0
  76. wbcompliance/tests/tests.py +21 -0
  77. wbcompliance/urls.py +238 -0
  78. wbcompliance/viewsets/__init__.py +40 -0
  79. wbcompliance/viewsets/buttons/__init__.py +9 -0
  80. wbcompliance/viewsets/buttons/compliance_form.py +78 -0
  81. wbcompliance/viewsets/buttons/compliance_task.py +149 -0
  82. wbcompliance/viewsets/buttons/risk_managment/__init__.py +3 -0
  83. wbcompliance/viewsets/buttons/risk_managment/checks.py +11 -0
  84. wbcompliance/viewsets/buttons/risk_managment/incidents.py +51 -0
  85. wbcompliance/viewsets/buttons/risk_managment/rules.py +35 -0
  86. wbcompliance/viewsets/compliance_form.py +425 -0
  87. wbcompliance/viewsets/compliance_task.py +513 -0
  88. wbcompliance/viewsets/compliance_type.py +38 -0
  89. wbcompliance/viewsets/display/__init__.py +22 -0
  90. wbcompliance/viewsets/display/compliance_form.py +317 -0
  91. wbcompliance/viewsets/display/compliance_task.py +453 -0
  92. wbcompliance/viewsets/display/compliance_type.py +22 -0
  93. wbcompliance/viewsets/display/risk_managment/__init__.py +11 -0
  94. wbcompliance/viewsets/display/risk_managment/checks.py +46 -0
  95. wbcompliance/viewsets/display/risk_managment/incidents.py +155 -0
  96. wbcompliance/viewsets/display/risk_managment/rules.py +146 -0
  97. wbcompliance/viewsets/display/risk_managment/tables.py +51 -0
  98. wbcompliance/viewsets/endpoints/__init__.py +27 -0
  99. wbcompliance/viewsets/endpoints/compliance_form.py +207 -0
  100. wbcompliance/viewsets/endpoints/compliance_task.py +193 -0
  101. wbcompliance/viewsets/endpoints/compliance_type.py +9 -0
  102. wbcompliance/viewsets/endpoints/risk_managment/__init__.py +12 -0
  103. wbcompliance/viewsets/endpoints/risk_managment/checks.py +16 -0
  104. wbcompliance/viewsets/endpoints/risk_managment/incidents.py +36 -0
  105. wbcompliance/viewsets/endpoints/risk_managment/rules.py +32 -0
  106. wbcompliance/viewsets/endpoints/risk_managment/tables.py +14 -0
  107. wbcompliance/viewsets/menu/__init__.py +17 -0
  108. wbcompliance/viewsets/menu/compliance_form.py +49 -0
  109. wbcompliance/viewsets/menu/compliance_task.py +130 -0
  110. wbcompliance/viewsets/menu/compliance_type.py +17 -0
  111. wbcompliance/viewsets/menu/risk_management.py +56 -0
  112. wbcompliance/viewsets/risk_management/__init__.py +21 -0
  113. wbcompliance/viewsets/risk_management/checks.py +49 -0
  114. wbcompliance/viewsets/risk_management/incidents.py +204 -0
  115. wbcompliance/viewsets/risk_management/mixins.py +52 -0
  116. wbcompliance/viewsets/risk_management/rules.py +179 -0
  117. wbcompliance/viewsets/risk_management/tables.py +96 -0
  118. wbcompliance/viewsets/titles/__init__.py +17 -0
  119. wbcompliance/viewsets/titles/compliance_form.py +101 -0
  120. wbcompliance/viewsets/titles/compliance_task.py +60 -0
  121. wbcompliance/viewsets/titles/compliance_type.py +13 -0
  122. wbcompliance/viewsets/titles/risk_managment/__init__.py +1 -0
  123. wbcompliance/viewsets/titles/risk_managment/checks.py +0 -0
  124. wbcompliance/viewsets/titles/risk_managment/incidents.py +0 -0
  125. wbcompliance/viewsets/titles/risk_managment/rules.py +0 -0
  126. wbcompliance/viewsets/titles/risk_managment/tables.py +7 -0
  127. wbcompliance-2.2.1.dist-info/METADATA +7 -0
  128. wbcompliance-2.2.1.dist-info/RECORD +129 -0
  129. 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,3 @@
1
+ def get_default_handler(field, request, view, **kwargs):
2
+ if not request.user.is_superuser and (profile := request.user.profile):
3
+ return profile.id
@@ -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")