ethyca-fides 2.64.0rc0__py2.py3-none-any.whl → 2.64.1b1__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.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/METADATA +2 -2
- {ethyca_fides-2.64.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/RECORD +107 -104
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/6a76a1fa4f3f_add_manual_task_instance_table.py +256 -0
- fides/api/db/base.py +4 -0
- fides/api/models/manual_tasks/__init__.py +7 -1
- fides/api/models/manual_tasks/manual_task.py +19 -3
- fides/api/models/manual_tasks/manual_task_config.py +39 -6
- fides/api/models/manual_tasks/manual_task_instance.py +187 -0
- fides/api/models/manual_tasks/manual_task_log.py +20 -7
- fides/api/schemas/manual_tasks/manual_task_schemas.py +42 -0
- fides/api/schemas/manual_tasks/manual_task_status.py +107 -46
- fides/api/service/connectors/postgres_connector.py +2 -2
- fides/service/manual_tasks/manual_task_config_service.py +17 -5
- fides/service/manual_tasks/manual_task_instance_service.py +285 -0
- fides/service/manual_tasks/manual_task_service.py +66 -10
- fides/ui-build/static/admin/404.html +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
- {ethyca_fides-2.64.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.64.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.64.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.64.0rc0.dist-info → ethyca_fides-2.64.1b1.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{lDN8BtGGiw3b60__SDnAa → zBkPKRGECPjwEx0G7BvHe}/_buildManifest.js +0 -0
- /fides/ui-build/static/admin/_next/static/{lDN8BtGGiw3b60__SDnAa → zBkPKRGECPjwEx0G7BvHe}/_ssgManifest.js +0 -0
@@ -15,6 +15,14 @@ from fides.api.schemas.manual_tasks.manual_task_config import (
|
|
15
15
|
from fides.service.manual_tasks.utils import validate_fields, with_task_logging
|
16
16
|
|
17
17
|
|
18
|
+
class ManualTaskConfigError(Exception):
|
19
|
+
"""Exception raised when a manual task config error occurs."""
|
20
|
+
|
21
|
+
def __init__(self, message: str):
|
22
|
+
self.message = message
|
23
|
+
super().__init__(self.message)
|
24
|
+
|
25
|
+
|
18
26
|
class ManualTaskConfigService:
|
19
27
|
def __init__(self, db: Session):
|
20
28
|
self.db = db
|
@@ -51,8 +59,8 @@ class ManualTaskConfigService:
|
|
51
59
|
"""
|
52
60
|
try:
|
53
61
|
ManualTaskConfigurationType(config_type)
|
54
|
-
except
|
55
|
-
raise
|
62
|
+
except ManualTaskConfigError:
|
63
|
+
raise ManualTaskConfigError(f"Invalid config type: {config_type}")
|
56
64
|
|
57
65
|
# Set all existing versions to non-current
|
58
66
|
if is_current:
|
@@ -96,7 +104,11 @@ class ManualTaskConfigService:
|
|
96
104
|
modified_keys = set(fields_to_remove or [])
|
97
105
|
|
98
106
|
if field_updates:
|
99
|
-
|
107
|
+
try:
|
108
|
+
validate_fields(field_updates, is_submission=False)
|
109
|
+
except ValueError as e:
|
110
|
+
raise ManualTaskConfigError(f"Invalid field updates: {e}") from e
|
111
|
+
|
100
112
|
fields_to_create = [
|
101
113
|
{
|
102
114
|
"task_id": config.task_id,
|
@@ -167,7 +179,7 @@ class ManualTaskConfigService:
|
|
167
179
|
)
|
168
180
|
|
169
181
|
if not config:
|
170
|
-
raise
|
182
|
+
raise ManualTaskConfigError(
|
171
183
|
f"No current config found for task {task.id} and type {config_type}"
|
172
184
|
)
|
173
185
|
return config
|
@@ -355,7 +367,7 @@ class ManualTaskConfigService:
|
|
355
367
|
"""
|
356
368
|
config = self.db.query(ManualTaskConfig).filter_by(id=config_id).first()
|
357
369
|
if not config:
|
358
|
-
raise
|
370
|
+
raise ManualTaskConfigError(f"Config with ID {config_id} not found")
|
359
371
|
|
360
372
|
log_data = self._create_log_data(
|
361
373
|
task.id,
|
@@ -0,0 +1,285 @@
|
|
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
|
+
)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any, Optional, cast
|
1
|
+
from typing import TYPE_CHECKING, Any, Optional, cast
|
2
2
|
|
3
3
|
from loguru import logger
|
4
4
|
from sqlalchemy import select
|
@@ -15,13 +15,31 @@ from fides.api.schemas.manual_tasks.manual_task_schemas import (
|
|
15
15
|
from fides.service.manual_tasks.manual_task_config_service import (
|
16
16
|
ManualTaskConfigService,
|
17
17
|
)
|
18
|
+
from fides.service.manual_tasks.manual_task_instance_service import (
|
19
|
+
ManualTaskInstanceService,
|
20
|
+
)
|
18
21
|
from fides.service.manual_tasks.utils import with_task_logging
|
19
22
|
|
23
|
+
if TYPE_CHECKING:
|
24
|
+
from fides.api.models.manual_tasks.manual_task_instance import (
|
25
|
+
ManualTaskInstance,
|
26
|
+
ManualTaskSubmission,
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
class ManualTaskError(Exception):
|
31
|
+
"""Exception raised when a manual task error occurs."""
|
32
|
+
|
33
|
+
def __init__(self, message: str):
|
34
|
+
self.message = message
|
35
|
+
super().__init__(self.message)
|
36
|
+
|
20
37
|
|
21
38
|
class ManualTaskService:
|
22
39
|
def __init__(self, db: Session):
|
23
40
|
self.db = db
|
24
41
|
self.config_service = ManualTaskConfigService(db)
|
42
|
+
self.instance_service = ManualTaskInstanceService(db)
|
25
43
|
|
26
44
|
def get_task(
|
27
45
|
self,
|
@@ -46,7 +64,7 @@ class ManualTaskService:
|
|
46
64
|
"""
|
47
65
|
if not any([task_id, parent_entity_id, parent_entity_type, task_type]):
|
48
66
|
logger.debug("No filters provided to get_task")
|
49
|
-
raise
|
67
|
+
raise ManualTaskError("No filters provided to get_task")
|
50
68
|
|
51
69
|
# Build filter conditions and a human-readable description
|
52
70
|
filters = []
|
@@ -72,7 +90,7 @@ class ManualTaskService:
|
|
72
90
|
task = self.db.execute(stmt).scalar_one_or_none()
|
73
91
|
if task is None:
|
74
92
|
logger.debug(f"No task found with filters: {filter_desc}")
|
75
|
-
raise
|
93
|
+
raise ManualTaskError(f"No task found with filters: {filter_desc}")
|
76
94
|
return task
|
77
95
|
|
78
96
|
@with_task_logging("Provided user IDs verified")
|
@@ -91,7 +109,7 @@ class ManualTaskService:
|
|
91
109
|
None
|
92
110
|
"""
|
93
111
|
if len(non_existent_user_ids) > 0:
|
94
|
-
raise
|
112
|
+
raise ManualTaskError(
|
95
113
|
f"User(s) {sorted(list(non_existent_user_ids))} do not exist"
|
96
114
|
)
|
97
115
|
|
@@ -128,11 +146,11 @@ class ManualTaskService:
|
|
128
146
|
error_key: Key to use for error details
|
129
147
|
|
130
148
|
Raises:
|
131
|
-
|
149
|
+
ManualTaskError: If no successful operations and users don't exist
|
132
150
|
"""
|
133
151
|
try:
|
134
152
|
self._non_existent_users(non_existent_users, task_id=task_id)
|
135
|
-
except
|
153
|
+
except ManualTaskError as e:
|
136
154
|
details[error_key] = sorted(non_existent_users)
|
137
155
|
if success_count == 0:
|
138
156
|
raise e
|
@@ -172,7 +190,7 @@ class ManualTaskService:
|
|
172
190
|
tuple: (processed_users, log_data)
|
173
191
|
"""
|
174
192
|
if not (user_ids := list(set(user_ids))):
|
175
|
-
raise
|
193
|
+
raise ManualTaskError(f"User ID is required for {operation_type}ment")
|
176
194
|
|
177
195
|
existing_users = set(
|
178
196
|
u.id
|
@@ -188,7 +206,7 @@ class ManualTaskService:
|
|
188
206
|
if non_existing := list(set(user_ids) - existing_users):
|
189
207
|
try:
|
190
208
|
self._non_existent_users(non_existing, task_id=task_id)
|
191
|
-
except
|
209
|
+
except ManualTaskError as e:
|
192
210
|
details[f"user_ids_not_{operation_type}ed"] = sorted(non_existing)
|
193
211
|
if not processed_users:
|
194
212
|
raise e
|
@@ -281,8 +299,8 @@ class ManualTaskService:
|
|
281
299
|
config: The config to delete
|
282
300
|
task_id: The task ID
|
283
301
|
Raises:
|
284
|
-
|
285
|
-
|
302
|
+
ManualTaskConfigError: If there are active instances using this configuration
|
303
|
+
ManualTaskError: If the task does not exist
|
286
304
|
|
287
305
|
Returns:
|
288
306
|
dict[str, Any]: The log details - intercepted by the `with_task_logging` decorator.
|
@@ -292,3 +310,41 @@ class ManualTaskService:
|
|
292
310
|
# Delete the configuration
|
293
311
|
config_id = config.id
|
294
312
|
self.config_service.delete_config(task, config_id)
|
313
|
+
|
314
|
+
def create_instance(
|
315
|
+
self, task_id: str, config_id: str, entity_id: str, entity_type: str
|
316
|
+
) -> "ManualTaskInstance":
|
317
|
+
"""Create a new instance for a task.
|
318
|
+
|
319
|
+
Args:
|
320
|
+
task_id: The task ID
|
321
|
+
config_id: The config ID
|
322
|
+
entity_id: The entity ID
|
323
|
+
entity_type: The entity type
|
324
|
+
|
325
|
+
Returns:
|
326
|
+
ManualTaskInstance: The new instance
|
327
|
+
"""
|
328
|
+
self.get_task(task_id=task_id)
|
329
|
+
instance = self.instance_service.create_instance(
|
330
|
+
task_id, config_id, entity_id, entity_type
|
331
|
+
)
|
332
|
+
return cast("ManualTaskInstance", instance)
|
333
|
+
|
334
|
+
def create_submission(
|
335
|
+
self, instance_id: str, field_id: str, data: dict[str, Any]
|
336
|
+
) -> "ManualTaskSubmission":
|
337
|
+
"""Create a new submission for a task.
|
338
|
+
|
339
|
+
Args:
|
340
|
+
instance_id: The instance ID
|
341
|
+
field_id: The field ID
|
342
|
+
data: The data for the submission
|
343
|
+
|
344
|
+
Returns:
|
345
|
+
ManualTaskSubmission: The new submission
|
346
|
+
"""
|
347
|
+
submission = self.instance_service.create_submission(
|
348
|
+
instance_id, field_id, data
|
349
|
+
)
|
350
|
+
return cast("ManualTaskSubmission", submission)
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/pages/404-ac2f0844e5c4b4cd.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/pages/404-ac2f0844e5c4b4cd.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><link rel="preload" href="/_next/static/css/92fc10cc7ed1aba3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/92fc10cc7ed1aba3.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/9278-9b1b5970f0702668.js" defer=""></script><script src="/_next/static/chunks/699-8ca44b0de9fa20f0.js" defer=""></script><script src="/_next/static/chunks/5277-e8a036319456127f.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/409-037cfc3f096150f0.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/9951-f9ab5cac7e2c05ab.js" defer=""></script><script src="/_next/static/chunks/1040-630c7f4284dc6f70.js" defer=""></script><script src="/_next/static/chunks/3450-bdaeb35442d810b4.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems/manual-0a5f2310ce6b1059.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><link rel="preload" href="/_next/static/css/92fc10cc7ed1aba3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/92fc10cc7ed1aba3.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/9278-9b1b5970f0702668.js" defer=""></script><script src="/_next/static/chunks/699-8ca44b0de9fa20f0.js" defer=""></script><script src="/_next/static/chunks/5277-e8a036319456127f.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/409-037cfc3f096150f0.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/9951-f9ab5cac7e2c05ab.js" defer=""></script><script src="/_next/static/chunks/1040-630c7f4284dc6f70.js" defer=""></script><script src="/_next/static/chunks/3450-bdaeb35442d810b4.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems/manual-0a5f2310ce6b1059.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/add-systems/manual","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/796-9a6b13c838e25538.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems/multiple-00cb904825aad7e3.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/796-9a6b13c838e25538.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems/multiple-00cb904825aad7e3.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/add-systems/multiple","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><link rel="preload" href="/_next/static/css/972dc7eef106ee7c.css" as="style"/><link rel="stylesheet" href="/_next/static/css/972dc7eef106ee7c.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems-587e21d14e0a5196.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><link rel="preload" href="/_next/static/css/972dc7eef106ee7c.css" as="style"/><link rel="stylesheet" href="/_next/static/css/972dc7eef106ee7c.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/pages/add-systems-587e21d14e0a5196.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/add-systems","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/796-9a6b13c838e25538.js" defer=""></script><script src="/_next/static/chunks/pages/consent/configure/add-vendors-fa7305b88c1afd20.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/796-9a6b13c838e25538.js" defer=""></script><script src="/_next/static/chunks/pages/consent/configure/add-vendors-fa7305b88c1afd20.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/consent/configure/add-vendors","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/pages/consent/configure-f140ec9d8e8a0f7a.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/401-fceaae662cfca5a5.js" defer=""></script><script src="/_next/static/chunks/3923-5d580fbb1dd6ae01.js" defer=""></script><script src="/_next/static/chunks/pages/consent/configure-f140ec9d8e8a0f7a.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/consent/configure","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/3662-f6a1ddca5ee42076.js" defer=""></script><script src="/_next/static/chunks/3670-2abd9b2f17770872.js" defer=""></script><script src="/_next/static/chunks/69-6889d6674c95e7b5.js" defer=""></script><script src="/_next/static/chunks/6277-3fb4c7fc790a6d20.js" defer=""></script><script src="/_next/static/chunks/1817-b4688ba5042ec687.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience/%5Bid%5D-0edb7c92518e7d21.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/3662-f6a1ddca5ee42076.js" defer=""></script><script src="/_next/static/chunks/3670-2abd9b2f17770872.js" defer=""></script><script src="/_next/static/chunks/69-6889d6674c95e7b5.js" defer=""></script><script src="/_next/static/chunks/6277-3fb4c7fc790a6d20.js" defer=""></script><script src="/_next/static/chunks/1817-b4688ba5042ec687.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience/%5Bid%5D-0edb7c92518e7d21.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/consent/privacy-experience/[id]","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/3662-f6a1ddca5ee42076.js" defer=""></script><script src="/_next/static/chunks/3670-2abd9b2f17770872.js" defer=""></script><script src="/_next/static/chunks/69-6889d6674c95e7b5.js" defer=""></script><script src="/_next/static/chunks/6277-3fb4c7fc790a6d20.js" defer=""></script><script src="/_next/static/chunks/1817-b4688ba5042ec687.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience/new-a0039f216fb3eb93.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/2858-0b44609b6be7850b.js" defer=""></script><script src="/_next/static/chunks/2866-a73888c17a195cbe.js" defer=""></script><script src="/_next/static/chunks/3662-f6a1ddca5ee42076.js" defer=""></script><script src="/_next/static/chunks/3670-2abd9b2f17770872.js" defer=""></script><script src="/_next/static/chunks/69-6889d6674c95e7b5.js" defer=""></script><script src="/_next/static/chunks/6277-3fb4c7fc790a6d20.js" defer=""></script><script src="/_next/static/chunks/1817-b4688ba5042ec687.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience/new-a0039f216fb3eb93.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/consent/privacy-experience/new","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/5277-e8a036319456127f.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/6853-a4097260e402980e.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience-d8d926f0735a2546.js" defer=""></script><script src="/_next/static/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/c693338e3bc8dcc6.css" as="style"/><link rel="stylesheet" href="/_next/static/css/c693338e3bc8dcc6.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-0a61b5bd21a41fe6.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-8ec6e466f3373ac0.js" defer=""></script><script src="/_next/static/chunks/c78d26b1-88a3e1bacb2a03c2.js" defer=""></script><script src="/_next/static/chunks/6060-cb1ab5be7067bf7b.js" defer=""></script><script src="/_next/static/chunks/5277-e8a036319456127f.js" defer=""></script><script src="/_next/static/chunks/7553-a95939c32d54b5b7.js" defer=""></script><script src="/_next/static/chunks/4481-f597a7cf03f8c9e1.js" defer=""></script><script src="/_next/static/chunks/6853-a4097260e402980e.js" defer=""></script><script src="/_next/static/chunks/pages/consent/privacy-experience-d8d926f0735a2546.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_buildManifest.js" defer=""></script><script src="/_next/static/zBkPKRGECPjwEx0G7BvHe/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/consent/privacy-experience","query":{},"buildId":"zBkPKRGECPjwEx0G7BvHe","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|