ethyca-fides 2.70.2rc0__py2.py3-none-any.whl → 2.70.3b0__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.
Potentially problematic release.
This version of ethyca-fides might be problematic. Click here for more details.
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/METADATA +3 -3
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/RECORD +205 -199
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/a8e0c016afd_add_classification_benchmark_table.py +126 -0
- fides/api/alembic/migrations/versions/cd8649be3a2b_add_classifications_and_user_assigned_.py +74 -0
- fides/api/db/crud.py +30 -2
- fides/api/db/database.py +1 -1
- fides/api/db/safe_crud.py +377 -0
- fides/api/migrations/post_upgrade_index_creation.py +10 -0
- fides/api/models/conditional_dependency/__init__.py +0 -0
- fides/api/models/conditional_dependency/conditional_dependency_base.py +82 -0
- fides/api/models/detection_discovery/__init__.py +2 -0
- fides/api/models/detection_discovery/classification_benchmark.py +140 -0
- fides/api/models/detection_discovery/core.py +11 -0
- fides/api/models/manual_task/conditional_dependency.py +21 -77
- fides/api/models/policy.py +24 -0
- fides/api/models/privacy_notice.py +1 -1
- fides/api/models/privacy_request/privacy_request.py +68 -0
- fides/api/models/privacy_request/webhook.py +3 -1
- fides/api/oauth/roles.py +2 -0
- fides/api/schemas/privacy_request.py +4 -2
- fides/api/schemas/user.py +2 -2
- fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +2 -2
- fides/api/service/storage/streaming/smart_open_streaming_storage.py +36 -28
- fides/api/service/storage/util.py +11 -102
- fides/api/task/manual/manual_task_utils.py +5 -6
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/155-047c3806cc41295e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7476-0b6e114658b15eaa.js → 7476-d055aa931da47ac0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{7725-dd6736855807936a.js → 7725-fdc4298dfbea6f80.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-a4e3c999afb28ee7.js → _app-de41f80e35acbde0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-3d03cd31cd99fa07.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/{[id]-8b13bb5f7bee61c6.js → [id]-9f6c82e14ff2cad2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{integrations-6f109ef64304ef59.js → integrations-ebc9c90fe99ee68d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-8566e3b7b2a632fa.js → [id]-f8e3f63bea43db3b.js} +1 -1
- fides/ui-build/static/admin/_next/static/{PQ9WiwwY2urPTyN8wYqXb → uJYQK3qHPl-9P-RICNMQA}/_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/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/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/messaging-providers/[key].html +1 -1
- fides/ui-build/static/admin/settings/messaging-providers/new.html +1 -1
- fides/ui-build/static/admin/settings/messaging-providers.html +1 -1
- fides/ui-build/static/admin/settings/organization.html +1 -1
- fides/ui-build/static/admin/settings/privacy-requests.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/ui-build/static/admin/_next/static/chunks/155-88303b05c6e115a5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-b0e3f1886de28d66.js +0 -1
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.70.2rc0.dist-info → ethyca_fides-2.70.3b0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{1115-7888473b3dc28cda.js → 1115-90baef2a89f361ad.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{1817-ee9e29a6b8c4af50.js → 1817-dbde9966025d7970.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{2040-ab6212a3074f34f9.js → 2040-fdecc41a18e40bdc.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{3696-c25dc8d1b0e1aee1.js → 3696-90c8b336bbc46782.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{3700-dc3f05d21e2a5ff6.js → 3700-865408b36fbee782.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{3872-3514b712afd683c0.js → 3872-04d3afbfa41a7782.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{4608-b22905c65f61db15.js → 4608-a9941d0c236ebca1.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{502-a40d39e615f7b664.js → 502-d3ecae97b67befbd.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{5185-33f50cf9ae17b42e.js → 5185-51eaa78e3ed6bfb7.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{5574-b8c4cba5a6938c00.js → 5574-c31ea831371610d5.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{5783-8de76df87af55e98.js → 5783-8f5713517ebc35f3.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{6084-2cd165179c428a6f.js → 6084-dc473a58c3e2889b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{6416-264aadc6b336ee0a.js → 6416-0ccadfefcdad00cc.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{6882-447f15e87b8c48a5.js → 6882-10296485ec326e6b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{6954-599f2de2c902e9b2.js → 6954-4b24e1731c1cc3b3.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{7158-835ba42fd881d8dd.js → 7158-04745cc8d684b2e7.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{7630-e7ea13be69c118a1.js → 7630-d0d3a0fe3f95e971.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{796-e07ac2c543f569e3.js → 796-876998c86754da97.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{8002-25fd174aec9b077b.js → 8002-ed832921ad190832.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{9226-2f960b7ca530642a.js → 9226-4a7027057f55ca2a.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{9826-c02be5882205bbbc.js → 9826-ccedc28e978ca9e1.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-939253f8daf349b2.js → manual-16ecb33f09224fbb.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-83ed7da0bb90b0a5.js → multiple-2ca59996860a33c5.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-f90aa48500c1cbde.js → add-systems-caff552fce501f82.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-46b88bda3d7b15c5.js → add-vendors-7a258b7ecd6da4b8.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-c0db068d1863222f.js → configure-259ad2e10fe6f413.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-92a337ee96845af2.js → privacy-experience-7e78616b7b048978.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-1fd2cda8707314f6.js → [id]-9c23fbe813c997d0.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-2987e397445713c5.js → new-0e5e38bbcfe59fd2.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-59a8aff5935482ec.js → privacy-notices-3ff2fd2570f02f1c.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{consent-e5a33654a2dfaf35.js → consent-d2bf72508c3cad55.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-293c1f2d9aefb447.js → [resourceUrn]-06a08970907ed3f0.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-6a4b0d49dcbf17a8.js → [projectUrn]-4a1af12d2d7cd660.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-be7b385073f22414.js → projects-99573a1ee3ef8f4c.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-18501152fa1e4f40.js → [resourceUrn]-4c84d952bb1db690.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{resources-af80fdca3bbdc82f.js → resources-6e429b7511028d60.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-351caadeef03876a.js → data-catalog-56fd0f3e465e52b6.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/{[monitorId]-e8ec4080d9a3e22f.js → [monitorId]-b74dfaf4f4126e57.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{action-center-1554afcb8b9da2ab.js → action-center-040813022f0890c9.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-0497f3ffdb632516.js → [resourceUrn]-844a8de0d1b506e2.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-a780390da99f3e43.js → detection-11b07cf2d91b17ef.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-1901c26cdde820da.js → [resourceUrn]-65dc7f5a2ce3eae7.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-0cea22af5929c81f.js → discovery-4d378516817cf00b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-619f27c745188adb.js → datamap-4a05303416dcb657.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/{[...subfieldNames]-ef71f387fbbab425.js → [...subfieldNames]-d4031e438c363fff.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/{[collectionName]-d790553662caf5c3.js → [collectionName]-9463af37079762d0.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-cb63db8594fe8dc1.js → [datasetId]-60a4a9eb4aab4c11.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-78e052c8f95110c4.js → new-910e28bce6a98f3d.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-d6d7ee8bd8858a8a.js → dataset-108630926347724e.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-cc149157d290a94d.js → [id]-5119e6602507157f.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-4c9fb068a5561658.js → new-cda4e7b5b888e17c.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{datastore-connection-a832084ce294f8af.js → datastore-connection-223c2d1ded51bfb1.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{index-269b8f81546dad66.js → index-b74d1e8608ae5b5d.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-d8c5c03fb2f31d65.js → [id]-e8d2140787045acd.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-0e0c06e3c8aabe02.js → add-template-e3f93462a08251bf.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-3f15804cf9625f01.js → messaging-b5f7d6afdecd013d.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-e551fccfcaae76e7.js → table-migration-329333a88f3826eb.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-1b38b656807ed0cd.js → storage-648d775d0fce49dc.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-b00532a0ad4f6927.js → configure-8f577df28ebca869.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{privacy-requests-2c82cf73d20416f2.js → privacy-requests-1eeb320867dbebf4.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-322a01e2bceab3fb.js → [id]-57a75c7e9659271a.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-777ed2d73812043d.js → add-property-8964c2300206bc89.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{consent-55e36839d219a503.js → consent-1ae1257f5b388924.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-26ce8fc493993765.js → custom-fields-c2f1376aca192114.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-7ddf9d992fe714a6.js → domain-records-586505df9d853f1f.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-7c78ae51f0dd7102.js → domains-a3275554ffe8e640.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-05ffbda19ab894b9.js → email-templates-604790638c656fbd.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-77fb85bdd0be42b5.js → locations-be2a885150adc133.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{[key]-b0d93bf478bf63ee.js → [key]-8df31428446a6a96.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{new-084f9756b9987285.js → new-af1471bf4571d5d3.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{messaging-providers-6c51ffd46bb598e7.js → messaging-providers-8d92be437793c96f.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-44456bfe54ac4ad5.js → organization-3c86162afe9759df.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{privacy-requests-fbe7e8030d837aed.js → privacy-requests-8cbdfd08e0fa88fb.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-2866ac99faa5a542.js → regulations-4fe3b90747d885e5.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-a86bafe1b4e1205f.js → test-datasets-2deb6becece69d46.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-1895c6a13b543436.js → [id]-589952aa1a31c33d.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{systems-d266cc062b56beb2.js → systems-916238dcc0596957.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-07848c232d960f6a.js → taxonomy-616f5a7cbb99e46d.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-6304dad2c5fab694.js → new-629c88e90699369b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-ff4711db191099cd.js → [id]-98f737e735eaa0f0.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-82fcf1151e2fe2ba.js → user-management-562624e5461083ec.js} +0 -0
- /fides/ui-build/static/admin/_next/static/{PQ9WiwwY2urPTyN8wYqXb → uJYQK3qHPl-9P-RICNMQA}/_ssgManifest.js +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import TYPE_CHECKING, Optional, Union
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
3
2
|
|
|
4
|
-
from sqlalchemy import Column, ForeignKey, Index,
|
|
5
|
-
from sqlalchemy.dialects.postgresql import JSONB
|
|
3
|
+
from sqlalchemy import Column, ForeignKey, Index, String
|
|
6
4
|
from sqlalchemy.ext.declarative import declared_attr
|
|
7
5
|
from sqlalchemy.orm import Session, relationship
|
|
8
6
|
|
|
9
|
-
from fides.api.db.base_class import
|
|
10
|
-
from fides.api.
|
|
7
|
+
from fides.api.db.base_class import FidesBase
|
|
8
|
+
from fides.api.models.conditional_dependency.conditional_dependency_base import (
|
|
9
|
+
ConditionalDependencyBase,
|
|
10
|
+
ConditionalDependencyType,
|
|
11
|
+
)
|
|
11
12
|
from fides.api.task.conditional_dependencies.schemas import (
|
|
12
13
|
ConditionGroup,
|
|
13
14
|
ConditionLeaf,
|
|
@@ -17,42 +18,16 @@ if TYPE_CHECKING:
|
|
|
17
18
|
from fides.api.models.manual_task.manual_task import ManualTask
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
class
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
This enum defines the two types of nodes in a conditional dependency tree:
|
|
24
|
-
|
|
25
|
-
- leaf: A terminal node that represents a single condition (e.g., "user.age >= 18")
|
|
26
|
-
- group: A non-terminal node that groups multiple conditions with logical operators (AND/OR)
|
|
27
|
-
|
|
28
|
-
Examples:
|
|
29
|
-
leaf: Used for simple field comparisons like:
|
|
30
|
-
- "user.name exists"
|
|
31
|
-
- "user.age >= 18"
|
|
32
|
-
- "billing.subscription.status == 'active'"
|
|
33
|
-
|
|
34
|
-
group: Used to combine multiple conditions with logical operators:
|
|
35
|
-
- AND group: "user.age >= 18 AND user.active == true"
|
|
36
|
-
- OR group: "user.role == 'admin' OR user.verified == true"
|
|
37
|
-
- Nested groups: "(user.age >= 18 AND (user.role == 'admin' OR user.verified == true))"
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
leaf = "leaf"
|
|
41
|
-
group = "group"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class ManualTaskConditionalDependency(Base):
|
|
45
|
-
"""Model for storing conditional dependencies."""
|
|
21
|
+
class ManualTaskConditionalDependency(ConditionalDependencyBase):
|
|
22
|
+
"""Manual task conditional dependencies - single type hierarchy."""
|
|
46
23
|
|
|
47
24
|
@declared_attr
|
|
48
25
|
def __tablename__(cls) -> str:
|
|
49
|
-
"""Overriding base class method to set the table name."""
|
|
50
26
|
return "manual_task_conditional_dependency"
|
|
51
27
|
|
|
52
28
|
# We need to redefine it here so that self-referential relationships
|
|
53
29
|
# can properly reference the `id` column instead of the built-in Python function.
|
|
54
30
|
id = Column(String(255), primary_key=True, default=FidesBase.generate_uuid)
|
|
55
|
-
|
|
56
31
|
# Foreign key relationships
|
|
57
32
|
manual_task_id = Column(
|
|
58
33
|
String, ForeignKey("manual_task.id", ondelete="CASCADE"), nullable=False
|
|
@@ -63,18 +38,6 @@ class ManualTaskConditionalDependency(Base):
|
|
|
63
38
|
nullable=True,
|
|
64
39
|
)
|
|
65
40
|
|
|
66
|
-
# Condition metadata
|
|
67
|
-
condition_type = Column(
|
|
68
|
-
EnumColumn(ManualTaskConditionalDependencyType), nullable=False
|
|
69
|
-
) # leaf or group
|
|
70
|
-
field_address = Column(String, nullable=True) # For leaf conditions
|
|
71
|
-
operator = Column(String, nullable=True) # For leaf conditions
|
|
72
|
-
value = Column(JSONB, nullable=True) # For leaf conditions
|
|
73
|
-
logical_operator = Column(String, nullable=True) # 'and' or 'or' for groups
|
|
74
|
-
|
|
75
|
-
# Ordering
|
|
76
|
-
sort_order = Column(Integer, nullable=False, default=0)
|
|
77
|
-
|
|
78
41
|
__table_args__ = (
|
|
79
42
|
Index("ix_manual_task_conditional_dependency_manual_task_id", "manual_task_id"),
|
|
80
43
|
Index("ix_manual_task_conditional_dependency_parent_id", "parent_id"),
|
|
@@ -97,38 +60,20 @@ class ManualTaskConditionalDependency(Base):
|
|
|
97
60
|
foreign_keys=[parent_id],
|
|
98
61
|
)
|
|
99
62
|
|
|
100
|
-
def to_condition_leaf(self) -> ConditionLeaf:
|
|
101
|
-
"""Convert to ConditionLeaf if this is a leaf condition"""
|
|
102
|
-
if self.condition_type != "leaf":
|
|
103
|
-
raise ValueError("Cannot convert group condition to leaf")
|
|
104
|
-
|
|
105
|
-
return ConditionLeaf(
|
|
106
|
-
field_address=self.field_address, operator=self.operator, value=self.value
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
def to_condition_group(self) -> ConditionGroup:
|
|
110
|
-
"""Convert to ConditionGroup if this is a group condition"""
|
|
111
|
-
if self.condition_type != "group":
|
|
112
|
-
raise ValueError("Cannot convert leaf condition to group")
|
|
113
|
-
|
|
114
|
-
# Recursively build children
|
|
115
|
-
child_conditions = []
|
|
116
|
-
children_list = [child for child in self.children] # type: ignore[attr-defined]
|
|
117
|
-
for child in sorted(children_list, key=lambda x: x.sort_order):
|
|
118
|
-
if child.condition_type == "leaf":
|
|
119
|
-
child_conditions.append(child.to_condition_leaf())
|
|
120
|
-
else:
|
|
121
|
-
child_conditions.append(child.to_condition_group())
|
|
122
|
-
|
|
123
|
-
return ConditionGroup(
|
|
124
|
-
logical_operator=self.logical_operator, conditions=child_conditions
|
|
125
|
-
)
|
|
126
|
-
|
|
127
63
|
@classmethod
|
|
128
64
|
def get_root_condition(
|
|
129
|
-
cls, db: Session,
|
|
65
|
+
cls, db: Session, *args: Any, **kwargs: Any
|
|
130
66
|
) -> Optional[Union[ConditionLeaf, ConditionGroup]]:
|
|
131
|
-
"""Get the root condition for a
|
|
67
|
+
"""Get the root condition for a manual task
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
db: Database session
|
|
71
|
+
manual_task_id: ID of the manual task (first positional arg)
|
|
72
|
+
"""
|
|
73
|
+
if not args:
|
|
74
|
+
raise ValueError("manual_task_id is required as first positional argument")
|
|
75
|
+
|
|
76
|
+
manual_task_id = args[0]
|
|
132
77
|
root = (
|
|
133
78
|
db.query(cls)
|
|
134
79
|
.filter(cls.manual_task_id == manual_task_id, cls.parent_id.is_(None))
|
|
@@ -138,7 +83,6 @@ class ManualTaskConditionalDependency(Base):
|
|
|
138
83
|
if not root:
|
|
139
84
|
return None
|
|
140
85
|
|
|
141
|
-
if root.condition_type ==
|
|
86
|
+
if root.condition_type == ConditionalDependencyType.leaf:
|
|
142
87
|
return root.to_condition_leaf()
|
|
143
|
-
|
|
144
88
|
return root.to_condition_group()
|
fides/api/models/policy.py
CHANGED
|
@@ -177,6 +177,30 @@ class Policy(Base):
|
|
|
177
177
|
for category in node.get_data_categories()
|
|
178
178
|
)
|
|
179
179
|
|
|
180
|
+
def to_safe_dict(self) -> Dict[str, Any]:
|
|
181
|
+
"""
|
|
182
|
+
Returns a dictionary representation of the Policy, excluding sensitive information.
|
|
183
|
+
"""
|
|
184
|
+
return {
|
|
185
|
+
"id": self.id,
|
|
186
|
+
"name": self.name,
|
|
187
|
+
"key": self.key,
|
|
188
|
+
"drp_action": self.drp_action.value if self.drp_action else None, # type: ignore[attr-defined]
|
|
189
|
+
"execution_timeframe": self.execution_timeframe,
|
|
190
|
+
"client_id": self.client_id,
|
|
191
|
+
"rules": [
|
|
192
|
+
{
|
|
193
|
+
"id": rule.id,
|
|
194
|
+
"name": rule.name,
|
|
195
|
+
"key": rule.key,
|
|
196
|
+
"action_type": rule.action_type.value,
|
|
197
|
+
"masking_strategy": rule.masking_strategy,
|
|
198
|
+
"storage_destination_id": rule.storage_destination_id,
|
|
199
|
+
}
|
|
200
|
+
for rule in self.rules # type: ignore[attr-defined]
|
|
201
|
+
],
|
|
202
|
+
}
|
|
203
|
+
|
|
180
204
|
|
|
181
205
|
def _get_ref_from_taxonomy(
|
|
182
206
|
fides_key: FidesKey,
|
|
@@ -41,7 +41,7 @@ class UserConsentPreference(Enum):
|
|
|
41
41
|
tcf = "tcf" # Overall preference set for TCF where there are numerous preferences under the single notice
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
class ConsentMechanism(Enum):
|
|
44
|
+
class ConsentMechanism(str, Enum):
|
|
45
45
|
"""
|
|
46
46
|
Enum is not formalized in the DB because it may be subject to frequent change
|
|
47
47
|
"""
|
|
@@ -261,6 +261,12 @@ class PrivacyRequest(
|
|
|
261
261
|
foreign_keys=[reviewed_by],
|
|
262
262
|
)
|
|
263
263
|
|
|
264
|
+
submitter = relationship(
|
|
265
|
+
FidesUser,
|
|
266
|
+
backref=backref("submitted_privacy_requests", passive_deletes=True),
|
|
267
|
+
foreign_keys=[submitted_by],
|
|
268
|
+
)
|
|
269
|
+
|
|
264
270
|
pre_approval_webhook_replies = relationship(
|
|
265
271
|
PreApprovalWebhookReply,
|
|
266
272
|
back_populates="privacy_request",
|
|
@@ -355,6 +361,64 @@ class PrivacyRequest(
|
|
|
355
361
|
|
|
356
362
|
return super().create(db=db, data=data, check_name=check_name)
|
|
357
363
|
|
|
364
|
+
def to_safe_dict(self) -> Dict[str, Any]:
|
|
365
|
+
"""
|
|
366
|
+
Return a dict representation of the PrivacyRequest, excluding any fields
|
|
367
|
+
that may contain sensitive information.
|
|
368
|
+
"""
|
|
369
|
+
return {
|
|
370
|
+
"id": self.id,
|
|
371
|
+
"external_id": self.external_id,
|
|
372
|
+
"status": self.status.value,
|
|
373
|
+
"requested_at": (
|
|
374
|
+
self.requested_at.isoformat() if self.requested_at else None
|
|
375
|
+
),
|
|
376
|
+
"started_processing_at": (
|
|
377
|
+
self.started_processing_at.isoformat()
|
|
378
|
+
if self.started_processing_at
|
|
379
|
+
else None
|
|
380
|
+
),
|
|
381
|
+
"finished_processing_at": (
|
|
382
|
+
self.finished_processing_at.isoformat()
|
|
383
|
+
if self.finished_processing_at
|
|
384
|
+
else None
|
|
385
|
+
),
|
|
386
|
+
"reviewed_at": self.reviewed_at.isoformat() if self.reviewed_at else None,
|
|
387
|
+
"reviewed_by": self.reviewed_by,
|
|
388
|
+
"finalized_at": (
|
|
389
|
+
self.finalized_at.isoformat() if self.finalized_at else None
|
|
390
|
+
),
|
|
391
|
+
"finalized_by": self.finalized_by,
|
|
392
|
+
"submitted_by": self.submitted_by,
|
|
393
|
+
"custom_privacy_request_fields_approved_by": (
|
|
394
|
+
self.custom_privacy_request_fields_approved_by
|
|
395
|
+
),
|
|
396
|
+
"identity_verified_at": (
|
|
397
|
+
self.identity_verified_at.isoformat()
|
|
398
|
+
if self.identity_verified_at
|
|
399
|
+
else None
|
|
400
|
+
),
|
|
401
|
+
"custom_privacy_request_fields_approved_at": (
|
|
402
|
+
self.custom_privacy_request_fields_approved_at.isoformat()
|
|
403
|
+
if self.custom_privacy_request_fields_approved_at
|
|
404
|
+
else None
|
|
405
|
+
),
|
|
406
|
+
"client_id": self.client_id,
|
|
407
|
+
"origin": self.origin,
|
|
408
|
+
"policy_id": self.policy_id,
|
|
409
|
+
"policy": self.policy.to_safe_dict() if self.policy else None,
|
|
410
|
+
"property_id": self.property_id,
|
|
411
|
+
"cancel_reason": self.cancel_reason,
|
|
412
|
+
"canceled_at": self.canceled_at.isoformat() if self.canceled_at else None,
|
|
413
|
+
"consent_preferences": self.consent_preferences,
|
|
414
|
+
"source": self.source.value if self.source else None,
|
|
415
|
+
"paused_at": self.paused_at.isoformat() if self.paused_at else None,
|
|
416
|
+
"due_date": self.due_date.isoformat() if self.due_date else None,
|
|
417
|
+
"days_left": self.days_left,
|
|
418
|
+
"custom_fields": self.get_persisted_custom_privacy_request_fields() if self.custom_fields else None, # type: ignore[attr-defined]
|
|
419
|
+
"location": self.location,
|
|
420
|
+
}
|
|
421
|
+
|
|
358
422
|
def clear_cached_values(self) -> None:
|
|
359
423
|
"""
|
|
360
424
|
Clears all cached values associated with this privacy request from Redis.
|
|
@@ -903,6 +967,8 @@ class PrivacyRequest(
|
|
|
903
967
|
callback_type=CallbackType.pre_approval,
|
|
904
968
|
identity=self.get_cached_identity_data(),
|
|
905
969
|
policy_action=policy_action,
|
|
970
|
+
privacy_request=self.to_safe_dict(),
|
|
971
|
+
timestamp=datetime.utcnow(),
|
|
906
972
|
)
|
|
907
973
|
headers = {
|
|
908
974
|
"reply-to-approve": f"/privacy-request/{self.id}/pre-approve/eligible",
|
|
@@ -943,6 +1009,8 @@ class PrivacyRequest(
|
|
|
943
1009
|
callback_type=webhook.prefix,
|
|
944
1010
|
identity=self.get_cached_identity_data(),
|
|
945
1011
|
policy_action=policy_action,
|
|
1012
|
+
privacy_request=self.to_safe_dict(),
|
|
1013
|
+
timestamp=datetime.utcnow(),
|
|
946
1014
|
)
|
|
947
1015
|
|
|
948
1016
|
headers = {}
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from enum import Enum as EnumType
|
|
8
|
-
from typing import Optional
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
9
|
|
|
10
10
|
from pydantic import BaseModel, ConfigDict
|
|
11
11
|
|
|
@@ -51,6 +51,8 @@ class SecondPartyRequestFormat(BaseModel):
|
|
|
51
51
|
identity: Identity
|
|
52
52
|
policy_action: Optional[ActionType] = None
|
|
53
53
|
model_config = ConfigDict(use_enum_values=True)
|
|
54
|
+
privacy_request: Dict[str, Any]
|
|
55
|
+
timestamp: datetime
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
def generate_request_callback_resume_jwe(webhook: PolicyPreWebhook) -> str:
|
fides/api/oauth/roles.py
CHANGED
|
@@ -26,6 +26,7 @@ from fides.common.api.scope_registry import (
|
|
|
26
26
|
PRIVACY_EXPERIENCE_READ,
|
|
27
27
|
PRIVACY_NOTICE_READ,
|
|
28
28
|
PRIVACY_REQUEST_CALLBACK_RESUME,
|
|
29
|
+
PRIVACY_REQUEST_CREATE,
|
|
29
30
|
PRIVACY_REQUEST_DELETE,
|
|
30
31
|
PRIVACY_REQUEST_EMAIL_INTEGRATIONS_SEND,
|
|
31
32
|
PRIVACY_REQUEST_MANUAL_STEPS_RESPOND,
|
|
@@ -88,6 +89,7 @@ approver_scopes = [
|
|
|
88
89
|
PRIVACY_REQUEST_UPLOAD_DATA,
|
|
89
90
|
PRIVACY_REQUEST_VIEW_DATA,
|
|
90
91
|
PRIVACY_REQUEST_DELETE,
|
|
92
|
+
PRIVACY_REQUEST_CREATE, # allows approvers to create new privacy requests
|
|
91
93
|
USER_READ, # allows approver to view user management table and update their own password
|
|
92
94
|
PRIVACY_REQUEST_MANUAL_STEPS_REVIEW, # allows approvers to see all manual steps
|
|
93
95
|
]
|
|
@@ -14,7 +14,7 @@ from fides.api.schemas.base_class import FidesSchema
|
|
|
14
14
|
from fides.api.schemas.policy import ActionType, CurrentStep
|
|
15
15
|
from fides.api.schemas.policy import PolicyResponse as PolicySchema
|
|
16
16
|
from fides.api.schemas.redis_cache import CustomPrivacyRequestField, Identity
|
|
17
|
-
from fides.api.schemas.user import
|
|
17
|
+
from fides.api.schemas.user import PrivacyRequestUser
|
|
18
18
|
from fides.api.util.collection_util import Row
|
|
19
19
|
from fides.api.util.encryption.aes_gcm_encryption_scheme import verify_encryption_key
|
|
20
20
|
from fides.api.util.enums import ColumnSort
|
|
@@ -316,7 +316,9 @@ class PrivacyRequestResponse(FidesSchema):
|
|
|
316
316
|
started_processing_at: Optional[datetime] = None
|
|
317
317
|
reviewed_at: Optional[datetime] = None
|
|
318
318
|
reviewed_by: Optional[str] = None
|
|
319
|
-
|
|
319
|
+
submitted_by: Optional[str] = None
|
|
320
|
+
reviewer: Optional[PrivacyRequestUser] = None
|
|
321
|
+
submitter: Optional[PrivacyRequestUser] = None
|
|
320
322
|
finished_processing_at: Optional[datetime] = None
|
|
321
323
|
identity_verified_at: Optional[datetime] = None
|
|
322
324
|
paused_at: Optional[datetime] = None
|
fides/api/schemas/user.py
CHANGED
|
@@ -10,8 +10,8 @@ from fides.api.schemas.base_class import FidesSchema
|
|
|
10
10
|
from fides.api.schemas.oauth import AccessToken
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class
|
|
14
|
-
"""Data we can expose via
|
|
13
|
+
class PrivacyRequestUser(FidesSchema):
|
|
14
|
+
"""Data we can expose via PrivacyRequest user relations (reviewer, submitter, etc.)"""
|
|
15
15
|
|
|
16
16
|
id: str
|
|
17
17
|
username: str
|
|
@@ -26,7 +26,7 @@ from fides.api.service.storage.util import (
|
|
|
26
26
|
is_attachment_field,
|
|
27
27
|
process_attachment_naming,
|
|
28
28
|
process_attachments_contextually,
|
|
29
|
-
|
|
29
|
+
resolve_path_from_context,
|
|
30
30
|
)
|
|
31
31
|
from fides.api.util.storage_util import StorageJSONEncoder, format_size
|
|
32
32
|
from fides.config import CONFIG
|
|
@@ -226,7 +226,7 @@ class DSRReportBuilder:
|
|
|
226
226
|
file_size = format_attachment_size(attachment.get("file_size"))
|
|
227
227
|
|
|
228
228
|
# Determine the actual directory for this attachment based on its context
|
|
229
|
-
actual_directory =
|
|
229
|
+
actual_directory = resolve_path_from_context(attachment, directory)
|
|
230
230
|
|
|
231
231
|
# Generate attachment URL using shared utility with actual storage path
|
|
232
232
|
download_url = attachment.get("download_url")
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
import csv
|
|
5
5
|
import json
|
|
6
6
|
import time
|
|
7
|
+
from copy import deepcopy
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from io import BytesIO, StringIO
|
|
9
10
|
from itertools import chain
|
|
@@ -36,13 +37,11 @@ from fides.api.service.storage.streaming.schemas import (
|
|
|
36
37
|
)
|
|
37
38
|
from fides.api.service.storage.streaming.smart_open_client import SmartOpenStorageClient
|
|
38
39
|
from fides.api.service.storage.util import (
|
|
39
|
-
convert_processed_attachments_to_attachment_processing_info,
|
|
40
40
|
determine_dataset_name_from_path,
|
|
41
|
-
extract_storage_key_from_attachment,
|
|
42
41
|
get_unique_filename,
|
|
43
42
|
process_attachments_contextually,
|
|
44
43
|
resolve_attachment_storage_path,
|
|
45
|
-
|
|
44
|
+
resolve_path_from_context,
|
|
46
45
|
)
|
|
47
46
|
|
|
48
47
|
DEFAULT_ATTACHMENT_NAME = "attachment"
|
|
@@ -169,7 +168,9 @@ class SmartOpenStreamingStorage:
|
|
|
169
168
|
"""
|
|
170
169
|
try:
|
|
171
170
|
# Extract storage key using shared utility
|
|
172
|
-
storage_key =
|
|
171
|
+
storage_key = (
|
|
172
|
+
attachment.get("download_url") or attachment.get("file_name") or ""
|
|
173
|
+
)
|
|
173
174
|
if not storage_key:
|
|
174
175
|
return None
|
|
175
176
|
|
|
@@ -182,7 +183,7 @@ class SmartOpenStreamingStorage:
|
|
|
182
183
|
)
|
|
183
184
|
|
|
184
185
|
# Resolve base path using shared utility
|
|
185
|
-
base_path =
|
|
186
|
+
base_path = resolve_path_from_context(attachment)
|
|
186
187
|
|
|
187
188
|
# Create AttachmentProcessingInfo
|
|
188
189
|
processing_info = AttachmentProcessingInfo(
|
|
@@ -281,7 +282,11 @@ class SmartOpenStreamingStorage:
|
|
|
281
282
|
) from e
|
|
282
283
|
|
|
283
284
|
def _collect_and_validate_attachments(
|
|
284
|
-
self,
|
|
285
|
+
self,
|
|
286
|
+
data: dict,
|
|
287
|
+
used_filenames_data: set[str],
|
|
288
|
+
used_filenames_attachments: set[str],
|
|
289
|
+
processed_attachments: dict[tuple[str, str], str],
|
|
285
290
|
) -> list[AttachmentProcessingInfo]:
|
|
286
291
|
"""Collect and validate attachments using the same contextual approach as DSR report builder.
|
|
287
292
|
|
|
@@ -294,26 +299,30 @@ class SmartOpenStreamingStorage:
|
|
|
294
299
|
Returns:
|
|
295
300
|
List of validated AttachmentProcessingInfo objects
|
|
296
301
|
"""
|
|
297
|
-
|
|
298
|
-
used_filenames_data: set[str] = set()
|
|
299
|
-
used_filenames_attachments: set[str] = set()
|
|
300
|
-
processed_attachments: dict[tuple[str, str], str] = {}
|
|
302
|
+
validated_attachments = []
|
|
301
303
|
|
|
302
304
|
# Use the shared contextual processing function
|
|
303
305
|
# Note: This method should only be used when DSR report builder is not available
|
|
304
306
|
# For HTML format, use _collect_and_validate_attachments_from_dsr_builder instead
|
|
305
307
|
processed_attachments_list = process_attachments_contextually(
|
|
306
|
-
data,
|
|
307
|
-
used_filenames_data,
|
|
308
|
-
used_filenames_attachments,
|
|
309
|
-
processed_attachments,
|
|
310
|
-
enable_streaming=True,
|
|
308
|
+
data=data,
|
|
309
|
+
used_filenames_data=used_filenames_data,
|
|
310
|
+
used_filenames_attachments=used_filenames_attachments,
|
|
311
|
+
processed_attachments=processed_attachments,
|
|
312
|
+
enable_streaming=True,
|
|
311
313
|
)
|
|
312
314
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
for processed_attachment in processed_attachments_list:
|
|
316
|
+
# Add context information to the attachment data
|
|
317
|
+
attachment_with_context = deepcopy(processed_attachment["attachment"])
|
|
318
|
+
attachment_with_context["_context"] = processed_attachment["context"]
|
|
319
|
+
|
|
320
|
+
# Validate and convert to AttachmentProcessingInfo
|
|
321
|
+
validated = self._validate_attachment(attachment_with_context)
|
|
322
|
+
if validated:
|
|
323
|
+
validated_attachments.append(validated)
|
|
324
|
+
|
|
325
|
+
return validated_attachments
|
|
317
326
|
|
|
318
327
|
def _collect_and_validate_attachments_from_dsr_builder(
|
|
319
328
|
self, data: dict, dsr_builder: "DSRReportBuilder"
|
|
@@ -342,17 +351,11 @@ class SmartOpenStreamingStorage:
|
|
|
342
351
|
else:
|
|
343
352
|
used_filenames_data.update(filenames)
|
|
344
353
|
|
|
345
|
-
|
|
354
|
+
return self._collect_and_validate_attachments(
|
|
346
355
|
data,
|
|
347
356
|
used_filenames_data,
|
|
348
357
|
used_filenames_attachments,
|
|
349
358
|
dsr_builder.processed_attachments,
|
|
350
|
-
enable_streaming=True, # Always use streaming mode for storage
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
# Convert to AttachmentProcessingInfo objects using shared utility
|
|
354
|
-
return convert_processed_attachments_to_attachment_processing_info(
|
|
355
|
-
processed_attachments_list, self._validate_attachment
|
|
356
359
|
)
|
|
357
360
|
|
|
358
361
|
@retry_cloud_storage_operation(
|
|
@@ -374,7 +377,7 @@ class SmartOpenStreamingStorage:
|
|
|
374
377
|
"""Upload data to cloud storage using smart-open streaming for memory efficiency.
|
|
375
378
|
|
|
376
379
|
This function leverages smart-open's streaming capabilities while maintaining
|
|
377
|
-
our DSR-specific business logic for package
|
|
380
|
+
our DSR-specific business logic for package and attachment processing.
|
|
378
381
|
All data is streamed directly from source to destination without local storage.
|
|
379
382
|
|
|
380
383
|
Args:
|
|
@@ -627,7 +630,12 @@ class SmartOpenStreamingStorage:
|
|
|
627
630
|
resp_format: Response format (csv, json)
|
|
628
631
|
"""
|
|
629
632
|
# Collect and validate all attachments using shared contextual processing
|
|
630
|
-
all_attachments = self._collect_and_validate_attachments(
|
|
633
|
+
all_attachments = self._collect_and_validate_attachments(
|
|
634
|
+
data=data,
|
|
635
|
+
used_filenames_data=set(),
|
|
636
|
+
used_filenames_attachments=set(),
|
|
637
|
+
processed_attachments={},
|
|
638
|
+
)
|
|
631
639
|
|
|
632
640
|
if not all_attachments:
|
|
633
641
|
# No attachments, just upload the data
|
|
@@ -544,31 +544,9 @@ def _process_attachment_list(
|
|
|
544
544
|
return processed_attachments_list
|
|
545
545
|
|
|
546
546
|
|
|
547
|
-
def
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
This function provides a consistent way to extract storage keys from
|
|
552
|
-
attachment dictionaries across different components.
|
|
553
|
-
|
|
554
|
-
Args:
|
|
555
|
-
attachment: The attachment dictionary
|
|
556
|
-
|
|
557
|
-
Returns:
|
|
558
|
-
The storage key (URL or filename) for the attachment
|
|
559
|
-
"""
|
|
560
|
-
if original_url := attachment.get("original_download_url"):
|
|
561
|
-
return original_url
|
|
562
|
-
|
|
563
|
-
if download_url := attachment.get("download_url"):
|
|
564
|
-
return download_url
|
|
565
|
-
|
|
566
|
-
file_name = attachment.get("file_name")
|
|
567
|
-
return file_name if file_name is not None else ""
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
def resolve_base_path_from_context(
|
|
571
|
-
attachment: dict[str, Any], default_base_path: str = "attachments"
|
|
547
|
+
def resolve_path_from_context(
|
|
548
|
+
attachment: dict[str, Any],
|
|
549
|
+
default_path: str = "attachments",
|
|
572
550
|
) -> str:
|
|
573
551
|
"""
|
|
574
552
|
Resolve the base path for an attachment based on its context.
|
|
@@ -578,93 +556,24 @@ def resolve_base_path_from_context(
|
|
|
578
556
|
|
|
579
557
|
Args:
|
|
580
558
|
attachment: The attachment dictionary
|
|
581
|
-
|
|
559
|
+
default_path: Default path if no context is found
|
|
582
560
|
|
|
583
561
|
Returns:
|
|
584
|
-
The resolved
|
|
562
|
+
The resolved path for the attachment
|
|
585
563
|
"""
|
|
586
564
|
if not attachment.get("_context"):
|
|
587
|
-
return
|
|
565
|
+
return default_path
|
|
588
566
|
|
|
589
567
|
context = attachment["_context"]
|
|
590
568
|
context_type = context.get("type")
|
|
591
569
|
|
|
592
|
-
if context_type
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
return f"data/{
|
|
570
|
+
if context_type in ["direct", "nested"]:
|
|
571
|
+
dataset = context.get("dataset", "")
|
|
572
|
+
collection = context.get("collection", "")
|
|
573
|
+
return f"data/{dataset}/{collection}/attachments"
|
|
596
574
|
if context_type == "top_level":
|
|
597
575
|
return "attachments"
|
|
598
|
-
# Handle old context format
|
|
599
576
|
if context.get("key") and context.get("item_id"):
|
|
600
577
|
return f"{context['key']}/{context['item_id']}/attachments"
|
|
601
|
-
# Fallback for unknown context types
|
|
602
|
-
return "unknown/unknown/attachments"
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
def resolve_directory_from_context(
|
|
606
|
-
attachment: dict[str, Any], default_directory: str = "attachments"
|
|
607
|
-
) -> str:
|
|
608
|
-
"""
|
|
609
|
-
Resolve the directory path for an attachment based on its context.
|
|
610
|
-
|
|
611
|
-
This function provides consistent directory resolution logic for DSR report builder.
|
|
612
|
-
|
|
613
|
-
Args:
|
|
614
|
-
attachment: The attachment dictionary
|
|
615
|
-
default_directory: Default directory if no context is found
|
|
616
|
-
|
|
617
|
-
Returns:
|
|
618
|
-
The resolved directory path for the attachment
|
|
619
|
-
"""
|
|
620
|
-
if not attachment.get("_context"):
|
|
621
|
-
return default_directory
|
|
622
|
-
|
|
623
|
-
context = attachment["_context"]
|
|
624
|
-
context_type = context.get("type")
|
|
625
|
-
|
|
626
|
-
if context_type == "direct":
|
|
627
|
-
return f"data/{context['dataset']}/{context['collection']}"
|
|
628
|
-
if context_type == "nested":
|
|
629
|
-
return f"data/{context['dataset']}/{context['collection']}"
|
|
630
|
-
if context_type == "top_level":
|
|
631
|
-
return "attachments"
|
|
632
|
-
if context.get("key") and context.get("item_id"):
|
|
633
|
-
return f"{context['key']}/{context['item_id']}"
|
|
634
|
-
|
|
635
|
-
return default_directory
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
def convert_processed_attachments_to_attachment_processing_info(
|
|
639
|
-
processed_attachments_list: list[dict[str, Any]], validate_attachment_func: Callable
|
|
640
|
-
) -> list[Any]:
|
|
641
|
-
"""
|
|
642
|
-
Convert processed attachments list to AttachmentProcessingInfo objects.
|
|
643
|
-
|
|
644
|
-
This is a shared utility function to avoid duplication between different
|
|
645
|
-
attachment collection methods.
|
|
646
|
-
|
|
647
|
-
Args:
|
|
648
|
-
processed_attachments_list: List of processed attachment dictionaries
|
|
649
|
-
validate_attachment_func: Function to validate individual attachments
|
|
650
|
-
Signature: validate_attachment_func(attachment_with_context) -> AttachmentProcessingInfo | None
|
|
651
|
-
|
|
652
|
-
Returns:
|
|
653
|
-
List of validated AttachmentProcessingInfo objects
|
|
654
|
-
"""
|
|
655
|
-
validated_attachments = []
|
|
656
|
-
|
|
657
|
-
for processed_attachment in processed_attachments_list:
|
|
658
|
-
attachment_data = processed_attachment["attachment"]
|
|
659
|
-
|
|
660
|
-
# Add context information to the attachment data
|
|
661
|
-
attachment_with_context = attachment_data.copy()
|
|
662
|
-
attachment_with_context["_context"] = processed_attachment["context"]
|
|
663
|
-
|
|
664
|
-
# Validate and convert to AttachmentProcessingInfo
|
|
665
|
-
if validate_attachment_func is not None:
|
|
666
|
-
validated = validate_attachment_func(attachment_with_context)
|
|
667
|
-
if validated:
|
|
668
|
-
validated_attachments.append(validated)
|
|
669
578
|
|
|
670
|
-
return
|
|
579
|
+
return default_path
|
|
@@ -9,14 +9,13 @@ from fides.api.graph.config import (
|
|
|
9
9
|
GraphDataset,
|
|
10
10
|
ScalarField,
|
|
11
11
|
)
|
|
12
|
-
from fides.api.models.connectionconfig import ConnectionConfig
|
|
13
12
|
|
|
14
13
|
# Import application models
|
|
15
|
-
from fides.api.models.
|
|
16
|
-
|
|
17
|
-
ManualTaskConditionalDependencyType,
|
|
18
|
-
ManualTaskConfigurationType,
|
|
14
|
+
from fides.api.models.conditional_dependency.conditional_dependency_base import (
|
|
15
|
+
ConditionalDependencyType,
|
|
19
16
|
)
|
|
17
|
+
from fides.api.models.connectionconfig import ConnectionConfig
|
|
18
|
+
from fides.api.models.manual_task import ManualTask, ManualTaskConfigurationType
|
|
20
19
|
from fides.api.task.manual.manual_task_address import ManualTaskAddress
|
|
21
20
|
|
|
22
21
|
PRIVACY_REQUEST_CONFIG_TYPES = {
|
|
@@ -135,7 +134,7 @@ def create_collection_for_connection_key(
|
|
|
135
134
|
conditional_field_addresses: set[str] = {
|
|
136
135
|
dependency.field_address
|
|
137
136
|
for dependency in manual_task.conditional_dependencies
|
|
138
|
-
if dependency.condition_type ==
|
|
137
|
+
if dependency.condition_type == ConditionalDependencyType.leaf
|
|
139
138
|
and dependency.field_address is not None
|
|
140
139
|
}
|
|
141
140
|
|