wbcompliance 1.59.0__py2.py3-none-any.whl → 1.59.2__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/migrations/0022_riskincident_precheck.py +39 -0
- wbcompliance/models/risk_management/checks.py +87 -4
- wbcompliance/models/risk_management/incidents.py +15 -4
- wbcompliance/models/risk_management/rules.py +3 -67
- wbcompliance/tests/risk_management/models/test_incidents.py +9 -7
- {wbcompliance-1.59.0.dist-info → wbcompliance-1.59.2.dist-info}/METADATA +1 -1
- {wbcompliance-1.59.0.dist-info → wbcompliance-1.59.2.dist-info}/RECORD +8 -7
- {wbcompliance-1.59.0.dist-info → wbcompliance-1.59.2.dist-info}/WHEEL +0 -0
|
@@ -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
|
+
]
|
|
@@ -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):
|
|
@@ -103,9 +106,13 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
103
106
|
self.rule.checked_object_relationships.filter(
|
|
104
107
|
checked_object_content_type=self.checked_object_content_type, checked_object_id=self.checked_object_id
|
|
105
108
|
).exists()
|
|
106
|
-
or self.
|
|
109
|
+
or self.precheck
|
|
107
110
|
)
|
|
108
111
|
|
|
112
|
+
@property
|
|
113
|
+
def precheck(self) -> bool:
|
|
114
|
+
return self.activator_id is not None
|
|
115
|
+
|
|
109
116
|
@property
|
|
110
117
|
def previous_check(self) -> Self | None:
|
|
111
118
|
"""
|
|
@@ -130,6 +137,20 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
130
137
|
self.checked_object_repr = str(self.checked_object)
|
|
131
138
|
super().save(*args, **kwargs)
|
|
132
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
|
+
|
|
133
154
|
def compute_str(self) -> str:
|
|
134
155
|
return _("{} - {}").format(
|
|
135
156
|
self.checked_object,
|
|
@@ -167,7 +188,7 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
167
188
|
# If the check is passive, we aggregated incident per breached object and return it for further processing
|
|
168
189
|
if self.needs_incident:
|
|
169
190
|
report = report_template.render(Context({"report_details": incident_result.report_details}))
|
|
170
|
-
incident, created = self.
|
|
191
|
+
incident, created = self.get_or_create_incident(
|
|
171
192
|
self.evaluation_date,
|
|
172
193
|
incident_result.severity,
|
|
173
194
|
incident_result.breached_object,
|
|
@@ -195,6 +216,68 @@ class RiskCheck(ComplexToStringMixin, WBModel):
|
|
|
195
216
|
self.save()
|
|
196
217
|
return incidents
|
|
197
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
|
+
|
|
198
281
|
class Meta:
|
|
199
282
|
verbose_name = "Risk Check"
|
|
200
283
|
verbose_name_plural = "Risk Checks"
|
|
@@ -112,9 +112,7 @@ class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin)
|
|
|
112
112
|
incident = models.ForeignKey(
|
|
113
113
|
to="wbcompliance.RiskIncident",
|
|
114
114
|
related_name="checked_object_relationships",
|
|
115
|
-
|
|
116
|
-
blank=True,
|
|
117
|
-
on_delete=models.SET_NULL,
|
|
115
|
+
on_delete=models.CASCADE,
|
|
118
116
|
)
|
|
119
117
|
|
|
120
118
|
rule_check = models.ForeignKey(
|
|
@@ -248,8 +246,12 @@ class CheckedObjectIncidentRelationship(ComplexToStringMixin, RiskIncidentMixin)
|
|
|
248
246
|
|
|
249
247
|
|
|
250
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
|
+
|
|
251
253
|
def get_queryset(self):
|
|
252
|
-
|
|
254
|
+
qs = (
|
|
253
255
|
super()
|
|
254
256
|
.get_queryset()
|
|
255
257
|
.annotate(
|
|
@@ -259,6 +261,9 @@ class RiskIncidentDefaultManager(models.Manager):
|
|
|
259
261
|
ignore_until=TruncDate("ignore_until_time"),
|
|
260
262
|
)
|
|
261
263
|
)
|
|
264
|
+
if self.only_passive_checks:
|
|
265
|
+
qs = qs.filter(precheck=False)
|
|
266
|
+
return qs
|
|
262
267
|
|
|
263
268
|
|
|
264
269
|
class RiskIncident(ComplexToStringMixin, RiskIncidentMixin):
|
|
@@ -297,6 +302,11 @@ class RiskIncident(ComplexToStringMixin, RiskIncidentMixin):
|
|
|
297
302
|
ignore_duration = models.DurationField(
|
|
298
303
|
blank=True, null=True, help_text=_("If set, will ignore the forthcoming incidents for the specified duration")
|
|
299
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
|
+
)
|
|
300
310
|
|
|
301
311
|
def get_ignore_until_date(self) -> date | None:
|
|
302
312
|
if self.last_ignored_date and self.ignore_duration:
|
|
@@ -367,6 +377,7 @@ class RiskIncident(ComplexToStringMixin, RiskIncidentMixin):
|
|
|
367
377
|
return dict()
|
|
368
378
|
|
|
369
379
|
objects = RiskIncidentDefaultManager()
|
|
380
|
+
all_objects = RiskIncidentDefaultManager(only_passive_checks=False)
|
|
370
381
|
|
|
371
382
|
class Meta:
|
|
372
383
|
verbose_name = "Risk Incident"
|
|
@@ -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
|
|
|
@@ -511,69 +510,6 @@ class RiskRule(PermissionObjectModelMixin, WBModel):
|
|
|
511
510
|
|
|
512
511
|
return permissions
|
|
513
512
|
|
|
514
|
-
def get_or_create_incident(
|
|
515
|
-
self,
|
|
516
|
-
evaluation_date: date,
|
|
517
|
-
incident_severity: "RiskIncidentType",
|
|
518
|
-
breached_object: Any,
|
|
519
|
-
breached_object_repr: str,
|
|
520
|
-
) -> tuple[RiskIncident, bool]:
|
|
521
|
-
"""
|
|
522
|
-
Utility function to get or create incident base on the given breached object
|
|
523
|
-
|
|
524
|
-
Args:
|
|
525
|
-
rule: The rule this incident happens
|
|
526
|
-
evaluation_date: The incident date
|
|
527
|
-
incident_severity: The incident severity
|
|
528
|
-
breached_object: The breached object (i.e. the object that triggers the incident)
|
|
529
|
-
breached_object_repr: Its string representation
|
|
530
|
-
|
|
531
|
-
Returns:
|
|
532
|
-
A tuple (incident, is_created)
|
|
533
|
-
"""
|
|
534
|
-
|
|
535
|
-
# Consider that if an incident happens one business day in the future or past, it is continue
|
|
536
|
-
date_range = DateRange( # type: ignore
|
|
537
|
-
(evaluation_date - BDay(1)).date(), (evaluation_date + BDay(1)).date(), "[]"
|
|
538
|
-
)
|
|
539
|
-
incidents = RiskIncident.objects.filter(rule=self, date_range__overlap=date_range)
|
|
540
|
-
if breached_object:
|
|
541
|
-
# If a breached_object is provided, we lookup over it
|
|
542
|
-
incidents = incidents.filter(
|
|
543
|
-
breached_content_type=ContentType.objects.get_for_model(breached_object),
|
|
544
|
-
breached_object_id=breached_object.id,
|
|
545
|
-
)
|
|
546
|
-
else:
|
|
547
|
-
# Otherwise, we lookup over its string representation. Might need to change as this is not very robust
|
|
548
|
-
incidents = incidents.filter(
|
|
549
|
-
breached_object_repr=breached_object_repr,
|
|
550
|
-
)
|
|
551
|
-
if incident := incidents.first():
|
|
552
|
-
incident.date_range = DateRange(
|
|
553
|
-
lower=incident.date_range.lower, upper=(evaluation_date + timedelta(days=1))
|
|
554
|
-
) # type: ignore
|
|
555
|
-
if self.automatically_close_incident:
|
|
556
|
-
incident.status = RiskIncident.Status.CLOSED
|
|
557
|
-
incident.save()
|
|
558
|
-
return incident, False
|
|
559
|
-
else:
|
|
560
|
-
return (
|
|
561
|
-
RiskIncident.objects.create(
|
|
562
|
-
rule=self,
|
|
563
|
-
date_range=DateRange(lower=evaluation_date, upper=(evaluation_date + timedelta(days=1))), # type: ignore
|
|
564
|
-
breached_content_type=ContentType.objects.get_for_model(breached_object)
|
|
565
|
-
if breached_object
|
|
566
|
-
else None,
|
|
567
|
-
breached_object_id=breached_object.id if breached_object else None,
|
|
568
|
-
breached_object_repr=breached_object_repr,
|
|
569
|
-
severity=incident_severity,
|
|
570
|
-
status=RiskIncident.Status.CLOSED
|
|
571
|
-
if self.automatically_close_incident
|
|
572
|
-
else RiskIncident.Status.OPEN,
|
|
573
|
-
),
|
|
574
|
-
True,
|
|
575
|
-
)
|
|
576
|
-
|
|
577
513
|
def notify(self, evaluation_date: date):
|
|
578
514
|
"""
|
|
579
515
|
Create the notification for this rule relationship and all implied persons
|
|
@@ -662,7 +598,7 @@ class RiskRule(PermissionObjectModelMixin, WBModel):
|
|
|
662
598
|
def pre_save_risk_threshold(sender, instance, **kwargs):
|
|
663
599
|
with suppress(RuleThreshold.DoesNotExist):
|
|
664
600
|
pre_save_instance = RuleThreshold.objects.get(id=instance.id)
|
|
665
|
-
RiskIncident.
|
|
601
|
+
RiskIncident.all_objects.filter(rule=instance.rule, severity=pre_save_instance.severity).update(
|
|
666
602
|
severity=instance.severity
|
|
667
603
|
)
|
|
668
604
|
CheckedObjectIncidentRelationship.objects.filter(
|
|
@@ -672,7 +608,7 @@ def pre_save_risk_threshold(sender, instance, **kwargs):
|
|
|
672
608
|
|
|
673
609
|
@receiver(pre_delete, sender="wbcompliance.RuleThreshold")
|
|
674
610
|
def pre_delete_risk_threshold(sender, instance, **kwargs):
|
|
675
|
-
RiskIncident.
|
|
611
|
+
RiskIncident.all_objects.filter(rule=instance.rule, severity=instance.severity).delete()
|
|
676
612
|
CheckedObjectIncidentRelationship.objects.filter(incident__rule=instance.rule, severity=instance.severity).delete()
|
|
677
613
|
|
|
678
614
|
|
|
@@ -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,
|
|
@@ -47,6 +47,7 @@ wbcompliance/migrations/0018_alter_rulecheckedobjectrelationship_unique_together
|
|
|
47
47
|
wbcompliance/migrations/0019_rulegroup_riskrule_activation_date_and_more.py,sha256=OZsIfILAl1u2dTLd_kffTov5US3HWOtkeoXyHodjQQ0,2011
|
|
48
48
|
wbcompliance/migrations/0020_rename_trigger_content_type_riskcheck_checked_object_content_type_and_more.py,sha256=XZVSSrk-71tSp9_VO6M0S9jaFJy5azyJEMYvO7e_Ut8,3135
|
|
49
49
|
wbcompliance/migrations/0021_riskcheck_passive_check.py,sha256=8P0ELPz-_UmnBOY_AyjkAtRJyXD9AOqYUhUB_9FW27Y,836
|
|
50
|
+
wbcompliance/migrations/0022_riskincident_precheck.py,sha256=H2l9REAsogn7EsUMWcE_A7ldZ6QUZ9UnfhhJpioyyhk,1756
|
|
50
51
|
wbcompliance/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
52
|
wbcompliance/models/__init__.py,sha256=gk3D0yZ3ZpJh1Nl-Kyc1PWm67t0Gj7t47Jl2xm9Lisk,534
|
|
52
53
|
wbcompliance/models/compliance_form.py,sha256=6xWJ5cEt0mfNsZjLYXI8GcP1Jb4MsFsvPhtVITmE0yI,24879
|
|
@@ -55,11 +56,11 @@ wbcompliance/models/compliance_type.py,sha256=Euevn9BRt7_R7lv49kTDlkMoL1uTQuUKWn
|
|
|
55
56
|
wbcompliance/models/enums.py,sha256=id1m8trG7b6Sw3Sa9VrLgD104GC2nG9A8ngJzaRqIIQ,424
|
|
56
57
|
wbcompliance/models/risk_management/__init__.py,sha256=DJXoHheA5REDpPYP0uyRmFWyNKP-ir_z5YB61CN6N-E,247
|
|
57
58
|
wbcompliance/models/risk_management/backend.py,sha256=pbszChXMxA36JjK0nIkrz0k7w9ImKUTGMVlokgA1R-w,4736
|
|
58
|
-
wbcompliance/models/risk_management/checks.py,sha256=
|
|
59
|
+
wbcompliance/models/risk_management/checks.py,sha256=cVDSiHd41y0HBp6ujNvRqvWcruYmi_gByZdj3CEYMIA,12143
|
|
59
60
|
wbcompliance/models/risk_management/dispatch.py,sha256=cLi63vSGbk9xhCoVgr4UmVk2kfYmGiyohKINSvCodb0,1423
|
|
60
|
-
wbcompliance/models/risk_management/incidents.py,sha256=
|
|
61
|
+
wbcompliance/models/risk_management/incidents.py,sha256=4xKTDvhfruWJEZ7axgnKW2_sbUbtchjnLerjZVq4Uzg,24267
|
|
61
62
|
wbcompliance/models/risk_management/mixins.py,sha256=KsdjpM1Cl235z8h57USVcYSBKtO2VRH1S0FCuJOEMH0,3762
|
|
62
|
-
wbcompliance/models/risk_management/rules.py,sha256=
|
|
63
|
+
wbcompliance/models/risk_management/rules.py,sha256=ra7XkBuDCPknTCamEIdRhxSs6Fo1P9tJnvhjTT7xZ8g,25660
|
|
63
64
|
wbcompliance/serializers/__init__.py,sha256=OhRIuUrexqQePCISpu-BKry9dfioYGfpO8RwlcwhHtI,1122
|
|
64
65
|
wbcompliance/serializers/compliance_form.py,sha256=OxPILlup_CP4Qwvu864oMqz7QUZsk2QOkOGFifWP3gM,11615
|
|
65
66
|
wbcompliance/serializers/compliance_task.py,sha256=euTQya2LdexoRblew9zMkv40kU7wkW9nU2uLTI-lwow,17035
|
|
@@ -86,7 +87,7 @@ wbcompliance/tests/risk_management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
|
86
87
|
wbcompliance/tests/risk_management/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
88
|
wbcompliance/tests/risk_management/models/test_backends.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
89
|
wbcompliance/tests/risk_management/models/test_checks.py,sha256=F4Pbn7q4PBmWx5fjvkwEclioG1mEt2M53maegSI9hYU,2467
|
|
89
|
-
wbcompliance/tests/risk_management/models/test_incidents.py,sha256=
|
|
90
|
+
wbcompliance/tests/risk_management/models/test_incidents.py,sha256=BYhBbD6M83poo5VrLzULG9xXpbtOlw9ObhzLwm31KAE,15107
|
|
90
91
|
wbcompliance/tests/risk_management/models/test_rules.py,sha256=j3g2gK6SV0F9a7U2eh2bEzPLI2wtZZoueQpzH6NTxpw,11177
|
|
91
92
|
wbcompliance/viewsets/__init__.py,sha256=JVv3mT5i-9dSYIC_lrvJqcFCPI92KQp9AZ21lR-eqEg,1498
|
|
92
93
|
wbcompliance/viewsets/compliance_form.py,sha256=2DKB72gzHQ9W3P3n7Al50awVLhMKBfkEEUZeMHASfGw,17295
|
|
@@ -137,6 +138,6 @@ wbcompliance/viewsets/titles/risk_managment/checks.py,sha256=47DEQpj8HBSa-_TImW-
|
|
|
137
138
|
wbcompliance/viewsets/titles/risk_managment/incidents.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
139
|
wbcompliance/viewsets/titles/risk_managment/rules.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
139
140
|
wbcompliance/viewsets/titles/risk_managment/tables.py,sha256=x_9mr6JWZ9GVNAEvfdNCeFZtGGYSG0-sXrR9pwTyocU,256
|
|
140
|
-
wbcompliance-1.59.
|
|
141
|
-
wbcompliance-1.59.
|
|
142
|
-
wbcompliance-1.59.
|
|
141
|
+
wbcompliance-1.59.2.dist-info/METADATA,sha256=sJhCLSF5pLurkOr1QX4OWQ_FpidTrpJdF4gs1d8Tb-8,196
|
|
142
|
+
wbcompliance-1.59.2.dist-info/WHEEL,sha256=aha0VrrYvgDJ3Xxl3db_g_MDIW-ZexDdrc_m-Hk8YY4,105
|
|
143
|
+
wbcompliance-1.59.2.dist-info/RECORD,,
|
|
File without changes
|