ethyca-fides 2.64.1b2__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.
Files changed (110) hide show
  1. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/METADATA +2 -2
  2. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/RECORD +106 -110
  3. fides/_version.py +3 -3
  4. fides/api/db/base.py +0 -4
  5. fides/api/models/connectionconfig.py +0 -11
  6. fides/api/models/manual_tasks/__init__.py +1 -7
  7. fides/api/models/manual_tasks/manual_task.py +3 -19
  8. fides/api/models/manual_tasks/manual_task_config.py +6 -39
  9. fides/api/models/manual_tasks/manual_task_log.py +7 -20
  10. fides/api/schemas/manual_tasks/manual_task_schemas.py +0 -42
  11. fides/api/schemas/manual_tasks/manual_task_status.py +46 -107
  12. fides/common/api/v1/urn_registry.py +0 -4
  13. fides/service/manual_tasks/manual_task_config_service.py +5 -17
  14. fides/service/manual_tasks/manual_task_service.py +10 -66
  15. fides/ui-build/static/admin/404.html +1 -1
  16. fides/ui-build/static/admin/_next/static/chunks/{6662-cb11881dcaabe5e2.js → 6662-6a6b90fc8f11558f.js} +1 -1
  17. fides/ui-build/static/admin/_next/static/{xYqpgK9yFhQK_wL_F_kAF → hCJxUAFBWobWrps6RkP0K}/_buildManifest.js +1 -1
  18. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  19. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  20. fides/ui-build/static/admin/add-systems.html +1 -1
  21. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  22. fides/ui-build/static/admin/consent/configure.html +1 -1
  23. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  24. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  25. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  26. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  27. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  28. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  29. fides/ui-build/static/admin/consent/properties.html +1 -1
  30. fides/ui-build/static/admin/consent/reporting.html +1 -1
  31. fides/ui-build/static/admin/consent.html +1 -1
  32. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  33. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  34. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  35. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  36. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  37. fides/ui-build/static/admin/data-catalog.html +1 -1
  38. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  39. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  40. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  41. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  42. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  43. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  44. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  45. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  46. fides/ui-build/static/admin/datamap.html +1 -1
  47. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  48. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  49. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  50. fides/ui-build/static/admin/dataset/new.html +1 -1
  51. fides/ui-build/static/admin/dataset.html +1 -1
  52. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  53. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  54. fides/ui-build/static/admin/datastore-connection.html +1 -1
  55. fides/ui-build/static/admin/index.html +1 -1
  56. fides/ui-build/static/admin/integrations/[id].html +1 -1
  57. fides/ui-build/static/admin/integrations.html +1 -1
  58. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  59. fides/ui-build/static/admin/lib/fides-preview.js +1 -1
  60. fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
  61. fides/ui-build/static/admin/lib/fides.js +2 -2
  62. fides/ui-build/static/admin/login/[provider].html +1 -1
  63. fides/ui-build/static/admin/login.html +1 -1
  64. fides/ui-build/static/admin/messaging/[id].html +1 -1
  65. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  66. fides/ui-build/static/admin/messaging.html +1 -1
  67. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  68. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  69. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  70. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  71. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  72. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  73. fides/ui-build/static/admin/poc/forms.html +1 -1
  74. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  75. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  76. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  77. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  78. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  79. fides/ui-build/static/admin/privacy-requests.html +1 -1
  80. fides/ui-build/static/admin/properties/[id].html +1 -1
  81. fides/ui-build/static/admin/properties/add-property.html +1 -1
  82. fides/ui-build/static/admin/properties.html +1 -1
  83. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  84. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  85. fides/ui-build/static/admin/settings/about.html +1 -1
  86. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  87. fides/ui-build/static/admin/settings/consent.html +1 -1
  88. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  89. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  90. fides/ui-build/static/admin/settings/domains.html +1 -1
  91. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  92. fides/ui-build/static/admin/settings/locations.html +1 -1
  93. fides/ui-build/static/admin/settings/organization.html +1 -1
  94. fides/ui-build/static/admin/settings/regulations.html +1 -1
  95. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  96. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  97. fides/ui-build/static/admin/systems.html +1 -1
  98. fides/ui-build/static/admin/taxonomy.html +1 -1
  99. fides/ui-build/static/admin/user-management/new.html +1 -1
  100. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  101. fides/ui-build/static/admin/user-management.html +1 -1
  102. fides/api/alembic/migrations/versions/6a76a1fa4f3f_add_manual_task_instance_table.py +0 -256
  103. fides/api/alembic/migrations/versions/aadfe83c5644_add_manual_task_to_connectiontype_enum.py +0 -46
  104. fides/api/models/manual_tasks/manual_task_instance.py +0 -187
  105. fides/service/manual_tasks/manual_task_instance_service.py +0 -285
  106. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/WHEEL +0 -0
  107. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/entry_points.txt +0 -0
  108. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/licenses/LICENSE +0 -0
  109. {ethyca_fides-2.64.1b2.dist-info → ethyca_fides-2.64.1rc0.dist-info}/top_level.txt +0 -0
  110. /fides/ui-build/static/admin/_next/static/{xYqpgK9yFhQK_wL_F_kAF → 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
- )