ethyca-fides 2.64.1b1__py2.py3-none-any.whl → 2.64.1rc0__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.
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/METADATA +2 -2
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/RECORD +104 -107
- fides/_version.py +3 -3
- fides/api/db/base.py +0 -4
- fides/api/models/manual_tasks/__init__.py +1 -7
- fides/api/models/manual_tasks/manual_task.py +3 -19
- fides/api/models/manual_tasks/manual_task_config.py +6 -39
- fides/api/models/manual_tasks/manual_task_log.py +7 -20
- fides/api/schemas/manual_tasks/manual_task_schemas.py +0 -42
- fides/api/schemas/manual_tasks/manual_task_status.py +46 -107
- fides/service/manual_tasks/manual_task_config_service.py +5 -17
- fides/service/manual_tasks/manual_task_service.py +10 -66
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6662-cb11881dcaabe5e2.js → 6662-6a6b90fc8f11558f.js} +1 -1
- fides/ui-build/static/admin/_next/static/{zBkPKRGECPjwEx0G7BvHe → hCJxUAFBWobWrps6RkP0K}/_buildManifest.js +1 -1
- fides/ui-build/static/admin/add-systems/manual.html +1 -1
- fides/ui-build/static/admin/add-systems/multiple.html +1 -1
- fides/ui-build/static/admin/add-systems.html +1 -1
- fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
- fides/ui-build/static/admin/consent/configure.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
- fides/ui-build/static/admin/consent/properties.html +1 -1
- fides/ui-build/static/admin/consent/reporting.html +1 -1
- fides/ui-build/static/admin/consent.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
- fides/ui-build/static/admin/data-catalog.html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
- fides/ui-build/static/admin/data-discovery/activity.html +1 -1
- fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/detection.html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
- fides/ui-build/static/admin/datamap.html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
- fides/ui-build/static/admin/dataset/new.html +1 -1
- fides/ui-build/static/admin/dataset.html +1 -1
- fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
- fides/ui-build/static/admin/datastore-connection/new.html +1 -1
- fides/ui-build/static/admin/datastore-connection.html +1 -1
- fides/ui-build/static/admin/index.html +1 -1
- fides/ui-build/static/admin/integrations/[id].html +1 -1
- fides/ui-build/static/admin/integrations.html +1 -1
- fides/ui-build/static/admin/lib/fides-headless.js +1 -1
- fides/ui-build/static/admin/lib/fides-preview.js +1 -1
- fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
- fides/ui-build/static/admin/lib/fides.js +2 -2
- fides/ui-build/static/admin/login/[provider].html +1 -1
- fides/ui-build/static/admin/login.html +1 -1
- fides/ui-build/static/admin/messaging/[id].html +1 -1
- fides/ui-build/static/admin/messaging/add-template.html +1 -1
- fides/ui-build/static/admin/messaging.html +1 -1
- fides/ui-build/static/admin/poc/ant-components.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
- fides/ui-build/static/admin/poc/forms.html +1 -1
- fides/ui-build/static/admin/poc/table-migration.html +1 -1
- fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
- fides/ui-build/static/admin/privacy-requests.html +1 -1
- fides/ui-build/static/admin/properties/[id].html +1 -1
- fides/ui-build/static/admin/properties/add-property.html +1 -1
- fides/ui-build/static/admin/properties.html +1 -1
- fides/ui-build/static/admin/reporting/datamap.html +1 -1
- fides/ui-build/static/admin/settings/about/alpha.html +1 -1
- fides/ui-build/static/admin/settings/about.html +1 -1
- fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
- fides/ui-build/static/admin/settings/consent.html +1 -1
- fides/ui-build/static/admin/settings/custom-fields.html +1 -1
- fides/ui-build/static/admin/settings/domain-records.html +1 -1
- fides/ui-build/static/admin/settings/domains.html +1 -1
- fides/ui-build/static/admin/settings/email-templates.html +1 -1
- fides/ui-build/static/admin/settings/locations.html +1 -1
- fides/ui-build/static/admin/settings/organization.html +1 -1
- fides/ui-build/static/admin/settings/regulations.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id].html +1 -1
- fides/ui-build/static/admin/systems.html +1 -1
- fides/ui-build/static/admin/taxonomy.html +1 -1
- fides/ui-build/static/admin/user-management/new.html +1 -1
- fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
- fides/ui-build/static/admin/user-management.html +1 -1
- fides/api/alembic/migrations/versions/6a76a1fa4f3f_add_manual_task_instance_table.py +0 -256
- fides/api/models/manual_tasks/manual_task_instance.py +0 -187
- fides/service/manual_tasks/manual_task_instance_service.py +0 -285
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.64.1b1.dist-info → ethyca_fides-2.64.1rc0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{zBkPKRGECPjwEx0G7BvHe → hCJxUAFBWobWrps6RkP0K}/_ssgManifest.js +0 -0
@@ -1,285 +0,0 @@
|
|
1
|
-
from typing import Any, Optional
|
2
|
-
|
3
|
-
from loguru import logger
|
4
|
-
from sqlalchemy.orm import Session
|
5
|
-
|
6
|
-
from fides.api.models.attachment import Attachment
|
7
|
-
from fides.api.models.manual_tasks.manual_task_config import ManualTaskConfigField
|
8
|
-
from fides.api.models.manual_tasks.manual_task_instance import (
|
9
|
-
ManualTaskInstance,
|
10
|
-
ManualTaskSubmission,
|
11
|
-
)
|
12
|
-
from fides.api.schemas.manual_tasks.manual_task_status import (
|
13
|
-
StatusTransitionNotAllowed,
|
14
|
-
StatusType,
|
15
|
-
)
|
16
|
-
from fides.service.manual_tasks.utils import validate_fields, with_task_logging
|
17
|
-
|
18
|
-
|
19
|
-
class ManualTaskInstanceError(Exception):
|
20
|
-
"""Exception raised when a manual task instance error occurs."""
|
21
|
-
|
22
|
-
def __init__(self, message: str):
|
23
|
-
self.message = message
|
24
|
-
super().__init__(self.message)
|
25
|
-
|
26
|
-
|
27
|
-
class ManualTaskSubmissionError(Exception):
|
28
|
-
"""Exception raised when a manual task submission error occurs."""
|
29
|
-
|
30
|
-
def __init__(self, message: str):
|
31
|
-
self.message = message
|
32
|
-
super().__init__(self.message)
|
33
|
-
|
34
|
-
|
35
|
-
class ManualTaskInstanceService:
|
36
|
-
def __init__(self, db: Session):
|
37
|
-
self.db = db
|
38
|
-
|
39
|
-
def _create_log_data(
|
40
|
-
self,
|
41
|
-
task_id: str,
|
42
|
-
config_id: str,
|
43
|
-
instance_id: str,
|
44
|
-
details: dict[str, Any],
|
45
|
-
) -> dict[str, Any]:
|
46
|
-
"""Create standard log data structure."""
|
47
|
-
return {
|
48
|
-
"task_id": task_id,
|
49
|
-
"config_id": config_id,
|
50
|
-
"instance_id": instance_id,
|
51
|
-
"details": details,
|
52
|
-
}
|
53
|
-
|
54
|
-
def _get_instance(
|
55
|
-
self, instance_id: str, allow_completed: bool = False
|
56
|
-
) -> ManualTaskInstance:
|
57
|
-
"""Get and validate instance."""
|
58
|
-
instance = self.db.query(ManualTaskInstance).filter_by(id=instance_id).first()
|
59
|
-
if not instance:
|
60
|
-
raise ManualTaskInstanceError(f"Instance with ID {instance_id} not found")
|
61
|
-
|
62
|
-
if not allow_completed and instance.status == StatusType.completed:
|
63
|
-
raise StatusTransitionNotAllowed(
|
64
|
-
"Instance is already completed, no further changes allowed"
|
65
|
-
)
|
66
|
-
|
67
|
-
return instance
|
68
|
-
|
69
|
-
def _get_field(
|
70
|
-
self, field_id: str, validate_data: Optional[dict[str, Any]] = None
|
71
|
-
) -> ManualTaskConfigField:
|
72
|
-
"""Get and validate field."""
|
73
|
-
field = ManualTaskConfigField.get_by_key_or_id(
|
74
|
-
db=self.db, data={"id": field_id}
|
75
|
-
)
|
76
|
-
if not field:
|
77
|
-
raise ManualTaskInstanceError(f"Field with ID {field_id} not found")
|
78
|
-
|
79
|
-
if validate_data:
|
80
|
-
try:
|
81
|
-
validate_fields([validate_data], is_submission=True)
|
82
|
-
except ValueError as e:
|
83
|
-
raise ManualTaskInstanceError(f"Invalid field data: {e}") from e
|
84
|
-
|
85
|
-
return field
|
86
|
-
|
87
|
-
def _update_instance_status(
|
88
|
-
self,
|
89
|
-
instance: ManualTaskInstance,
|
90
|
-
new_status: Optional[StatusType] = None,
|
91
|
-
user_id: Optional[str] = None,
|
92
|
-
silent: bool = False,
|
93
|
-
) -> None:
|
94
|
-
"""Update instance status with optional error suppression."""
|
95
|
-
try:
|
96
|
-
if not new_status:
|
97
|
-
new_status = (
|
98
|
-
StatusType.in_progress
|
99
|
-
if instance.submissions
|
100
|
-
else StatusType.pending
|
101
|
-
)
|
102
|
-
instance.update_status(self.db, new_status, user_id)
|
103
|
-
except StatusTransitionNotAllowed as e:
|
104
|
-
if not silent:
|
105
|
-
raise
|
106
|
-
logger.info(f"Status not transitioning: {e}")
|
107
|
-
|
108
|
-
@with_task_logging("Created task instance")
|
109
|
-
def create_instance(
|
110
|
-
self, task_id: str, config_id: str, entity_id: str, entity_type: str
|
111
|
-
) -> tuple[ManualTaskInstance, dict[str, Any]]:
|
112
|
-
"""Create a new instance for an entity."""
|
113
|
-
instance = ManualTaskInstance.create(
|
114
|
-
self.db,
|
115
|
-
data={
|
116
|
-
"task_id": task_id,
|
117
|
-
"config_id": config_id,
|
118
|
-
"entity_id": entity_id,
|
119
|
-
"entity_type": entity_type,
|
120
|
-
},
|
121
|
-
)
|
122
|
-
return instance, self._create_log_data(
|
123
|
-
task_id, config_id, instance.id, {"entity_type": entity_type}
|
124
|
-
)
|
125
|
-
|
126
|
-
def get_submission_for_field(
|
127
|
-
self, instance_id: str, field_id: str
|
128
|
-
) -> Optional[ManualTaskSubmission]:
|
129
|
-
"""Get the submission for a specific field."""
|
130
|
-
return self._get_instance(instance_id).get_submission_for_field(field_id)
|
131
|
-
|
132
|
-
@with_task_logging("Updated task instance status")
|
133
|
-
def update_status(
|
134
|
-
self,
|
135
|
-
instance_id: str,
|
136
|
-
new_status: Optional[StatusType] = None,
|
137
|
-
user_id: Optional[str] = None,
|
138
|
-
) -> tuple[ManualTaskInstance, dict[str, Any]]:
|
139
|
-
"""Update instance status with logging."""
|
140
|
-
instance = self._get_instance(instance_id)
|
141
|
-
previous_status = instance.status
|
142
|
-
self._update_instance_status(instance, new_status, user_id)
|
143
|
-
|
144
|
-
return instance, self._create_log_data(
|
145
|
-
instance.task_id,
|
146
|
-
instance.config_id,
|
147
|
-
instance.id,
|
148
|
-
{
|
149
|
-
"previous_status": previous_status,
|
150
|
-
"new_status": instance.status,
|
151
|
-
"user_id": user_id,
|
152
|
-
},
|
153
|
-
)
|
154
|
-
|
155
|
-
@with_task_logging("Created task submission")
|
156
|
-
def create_submission(
|
157
|
-
self,
|
158
|
-
instance_id: str,
|
159
|
-
field_id: str,
|
160
|
-
data: dict[str, Any],
|
161
|
-
) -> tuple[ManualTaskSubmission, dict[str, Any]]:
|
162
|
-
"""Create a new submission for a field."""
|
163
|
-
instance = self._get_instance(instance_id)
|
164
|
-
field = self._get_field(field_id, data)
|
165
|
-
|
166
|
-
if instance.get_submission_for_field(field_id):
|
167
|
-
raise ManualTaskInstanceError(
|
168
|
-
f"Submission for field {field.field_key} already exists for instance {instance.id}"
|
169
|
-
)
|
170
|
-
|
171
|
-
submission = ManualTaskSubmission.create(
|
172
|
-
self.db,
|
173
|
-
data={
|
174
|
-
"task_id": instance.task_id,
|
175
|
-
"config_id": instance.config_id,
|
176
|
-
"instance_id": instance.id,
|
177
|
-
"field_id": field.id,
|
178
|
-
"data": data,
|
179
|
-
},
|
180
|
-
)
|
181
|
-
|
182
|
-
# Update instance status to in_progress
|
183
|
-
self._update_instance_status(instance, StatusType.in_progress, silent=True)
|
184
|
-
|
185
|
-
return submission, self._create_log_data(
|
186
|
-
instance.task_id,
|
187
|
-
instance.config_id,
|
188
|
-
instance.id,
|
189
|
-
{
|
190
|
-
"field_key": field.field_key,
|
191
|
-
"field_type": field.field_type,
|
192
|
-
},
|
193
|
-
)
|
194
|
-
|
195
|
-
@with_task_logging("Updated task submission")
|
196
|
-
def update_submission(
|
197
|
-
self,
|
198
|
-
instance_id: str,
|
199
|
-
submission_id: str,
|
200
|
-
data: dict[str, Any],
|
201
|
-
) -> tuple[ManualTaskSubmission, dict[str, Any]]:
|
202
|
-
"""Update a submission for a field."""
|
203
|
-
instance = self._get_instance(instance_id)
|
204
|
-
submission = next(
|
205
|
-
(s for s in instance.submissions if s.id == submission_id),
|
206
|
-
None,
|
207
|
-
)
|
208
|
-
if not submission or not submission.field_id:
|
209
|
-
raise ManualTaskSubmissionError(
|
210
|
-
f"Valid submission with ID {submission_id} not found"
|
211
|
-
)
|
212
|
-
|
213
|
-
field = self._get_field(submission.field_id, data)
|
214
|
-
submission.update(self.db, data={"data": data})
|
215
|
-
self._update_instance_status(instance, silent=True)
|
216
|
-
|
217
|
-
return submission, self._create_log_data(
|
218
|
-
instance.task_id,
|
219
|
-
instance.config_id,
|
220
|
-
instance.id,
|
221
|
-
{
|
222
|
-
"field_key": field.field_key,
|
223
|
-
"field_type": field.field_type,
|
224
|
-
},
|
225
|
-
)
|
226
|
-
|
227
|
-
@with_task_logging("Delete task attachment")
|
228
|
-
def delete_attachment_by_id(
|
229
|
-
self,
|
230
|
-
submission_id: str,
|
231
|
-
attachment_id: str,
|
232
|
-
) -> None:
|
233
|
-
"""Delete an attachment for a field."""
|
234
|
-
submission = (
|
235
|
-
self.db.query(ManualTaskSubmission).filter_by(id=submission_id).first()
|
236
|
-
)
|
237
|
-
if not submission:
|
238
|
-
raise ManualTaskSubmissionError(
|
239
|
-
f"Submission with ID {submission_id} does not exist"
|
240
|
-
)
|
241
|
-
|
242
|
-
self._get_instance(
|
243
|
-
submission.instance_id
|
244
|
-
) # Validates instance is not completed
|
245
|
-
|
246
|
-
attachment = self.db.query(Attachment).filter_by(id=attachment_id).first()
|
247
|
-
if not attachment or attachment not in submission.attachments:
|
248
|
-
raise ManualTaskSubmissionError(
|
249
|
-
f"Attachment {attachment_id} not found in submission {submission_id}"
|
250
|
-
)
|
251
|
-
|
252
|
-
# Delete attachment and optionally submission
|
253
|
-
if (
|
254
|
-
len(submission.attachments) == 1
|
255
|
-
and submission.field.field_type == "attachment"
|
256
|
-
):
|
257
|
-
attachment.delete(self.db)
|
258
|
-
submission.delete(self.db)
|
259
|
-
else:
|
260
|
-
attachment.delete(self.db)
|
261
|
-
|
262
|
-
@with_task_logging("Completed task instance")
|
263
|
-
def complete_task_instance(
|
264
|
-
self, task_id: str, config_id: str, instance_id: str, user_id: str
|
265
|
-
) -> tuple[ManualTaskInstance, dict[str, Any]]:
|
266
|
-
"""Complete a task instance."""
|
267
|
-
instance = self._get_instance(instance_id)
|
268
|
-
|
269
|
-
missing_fields = [
|
270
|
-
field.field_key
|
271
|
-
for field in instance.required_fields
|
272
|
-
if not instance.get_submission_for_field(field.id)
|
273
|
-
]
|
274
|
-
if missing_fields:
|
275
|
-
raise StatusTransitionNotAllowed(
|
276
|
-
f"Cannot complete task instance. Missing required fields: {', '.join(missing_fields)}"
|
277
|
-
)
|
278
|
-
|
279
|
-
instance.update_status(self.db, StatusType.completed, user_id)
|
280
|
-
instance.completed_by_id = user_id
|
281
|
-
instance.save(self.db)
|
282
|
-
|
283
|
-
return instance, self._create_log_data(
|
284
|
-
task_id, config_id, instance_id, {"completed_by": user_id}
|
285
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|