ethyca-fides 2.70.0rc5__py2.py3-none-any.whl → 2.70.1b0__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.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/METADATA +4 -4
- {ethyca_fides-2.70.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/RECORD +196 -195
- fides/_version.py +3 -3
- fides/api/api/v1/endpoints/system.py +5 -1
- fides/api/db/crud.py +30 -2
- fides/api/db/safe_crud.py +377 -0
- fides/api/models/policy.py +24 -0
- fides/api/models/privacy_notice.py +1 -1
- fides/api/models/privacy_request/privacy_request.py +62 -0
- fides/api/models/privacy_request/webhook.py +3 -1
- fides/api/schemas/connection_configuration/connection_secrets_mongodb.py +14 -2
- fides/api/service/connectors/mongodb_connector.py +74 -9
- fides/service/system/system_service.py +17 -2
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/{YDIHw7NCpEulNqL5G--Yh → 6oPWh0EXUTEVS_OTLA_S1}/_buildManifest.js +1 -1
- fides/ui-build/static/admin/_next/static/chunks/155-047c3806cc41295e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3700-865408b36fbee782.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7725-dd6736855807936a.js → 7725-fdc4298dfbea6f80.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7929-0fd0d4948bc8d70e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-e08a732e348aa667.js → _app-91cae6157e6f09b5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-3ff2fd2570f02f1c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-09be5455ba85db39.js → reporting-ae4909cad9b67822.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/data-discovery/action-center/{[monitorId]-0e4d9ff89c63793c.js → [monitorId]-b74dfaf4f4126e57.js} +1 -1
- 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/reporting/datamap-5b423687e227ad4d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-916238dcc0596957.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-616f5a7cbb99e46d.js +1 -0
- fides/ui-build/static/admin/_next/static/css/1866822702989bb3.css +1 -0
- 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/3700-2a7094f112a1608a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7929-919e2dff24e40397.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-8fb92df30e8d496a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-758d51b4d37dbd09.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-0afb12096a35ab78.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-ae3f3470e2734933.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-1b9c4b2749e3ece4.js +0 -1
- fides/ui-build/static/admin/_next/static/css/018c12b58ee7f861.css +0 -1
- {ethyca_fides-2.70.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.70.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.70.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.70.0rc5.dist-info → ethyca_fides-2.70.1b0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{YDIHw7NCpEulNqL5G--Yh → 6oPWh0EXUTEVS_OTLA_S1}/_ssgManifest.js +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/{3872-3514b712afd683c0.js → 3872-04d3afbfa41a7782.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{4608-96f480766541124b.js → 4608-63fbb1f4f258a66e.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-18d438ff85d807f8.js → 6416-39d12ffc78833cb1.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/{7476-0b6e114658b15eaa.js → 7476-c709d0610ebf7e2e.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-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-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/{[id]-8566e3b7b2a632fa.js → [id]-989c77898de2da75.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-65f0d5672041a202.js → privacy-requests-14a2efa72f0d4d12.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/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/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-09-
|
|
11
|
+
"date": "2025-09-17T11:54:23-0700",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.70.
|
|
14
|
+
"full-revisionid": "f42db9940a5b753019726d317e93e58db908e929",
|
|
15
|
+
"version": "2.70.1b0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Annotated, Dict, List, Optional, Union
|
|
1
|
+
from typing import Annotated, Dict, List, Literal, Optional, Union
|
|
2
2
|
|
|
3
3
|
from fastapi import Depends, HTTPException, Query, Response, Security
|
|
4
4
|
from fastapi_pagination import Page, Params
|
|
@@ -509,6 +509,8 @@ async def ls( # pylint: disable=invalid-name
|
|
|
509
509
|
data_categories: Optional[List[FidesKey]] = Query(None),
|
|
510
510
|
data_subjects: Optional[List[FidesKey]] = Query(None),
|
|
511
511
|
show_deleted: bool = Query(False),
|
|
512
|
+
sort_by: Optional[List[Literal["name"]]] = Query(None),
|
|
513
|
+
sort_asc: Optional[bool] = Query(True),
|
|
512
514
|
) -> Union[List[System], Page[System]]:
|
|
513
515
|
"""Get a list of all of the Systems.
|
|
514
516
|
If any parameters or filters are provided the response will be paginated and/or filtered.
|
|
@@ -524,6 +526,8 @@ async def ls( # pylint: disable=invalid-name
|
|
|
524
526
|
size=size,
|
|
525
527
|
page=page,
|
|
526
528
|
show_deleted=show_deleted,
|
|
529
|
+
sort_by=sort_by,
|
|
530
|
+
sort_asc=sort_asc,
|
|
527
531
|
)
|
|
528
532
|
|
|
529
533
|
|
fides/api/db/crud.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
DEPRECATED: This module uses manual transaction handling which can
|
|
3
|
+
lead to unexpected behavior. Use fides.api.db.safe_crud instead.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from collections import defaultdict
|
|
@@ -18,6 +18,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
18
18
|
from sqlalchemy.future import select
|
|
19
19
|
from sqlalchemy.sql import Select
|
|
20
20
|
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
|
21
|
+
from typing_extensions import deprecated
|
|
21
22
|
|
|
22
23
|
from fides.api.models.sql_models import ( # type: ignore[attr-defined]
|
|
23
24
|
CustomField,
|
|
@@ -32,6 +33,9 @@ T = TypeVar("T", bound="FidesBase")
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
# CRUD Functions
|
|
36
|
+
@deprecated(
|
|
37
|
+
"This function uses a manual session.begin() which can lead to unexpected transaction handling. Use create_resource from safe_crud instead."
|
|
38
|
+
)
|
|
35
39
|
async def create_resource(
|
|
36
40
|
sql_model: Type[T], resource_dict: Dict, async_session: AsyncSession
|
|
37
41
|
) -> T:
|
|
@@ -66,6 +70,9 @@ async def create_resource(
|
|
|
66
70
|
return await get_resource(sql_model, resource_dict["fides_key"], async_session)
|
|
67
71
|
|
|
68
72
|
|
|
73
|
+
@deprecated(
|
|
74
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use get_custom_fields_filtered from safe_crud instead."
|
|
75
|
+
)
|
|
69
76
|
async def get_custom_fields_filtered(
|
|
70
77
|
async_session: AsyncSession,
|
|
71
78
|
resource_types_to_ids: Dict[ResourceTypes, List[str]] = defaultdict(list),
|
|
@@ -111,6 +118,9 @@ async def get_custom_fields_filtered(
|
|
|
111
118
|
raise sa_error
|
|
112
119
|
|
|
113
120
|
|
|
121
|
+
@deprecated(
|
|
122
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use get_resource from safe_crud instead."
|
|
123
|
+
)
|
|
114
124
|
async def get_resource(
|
|
115
125
|
sql_model: Type[T],
|
|
116
126
|
fides_key: str,
|
|
@@ -142,6 +152,9 @@ async def get_resource(
|
|
|
142
152
|
return sql_resource
|
|
143
153
|
|
|
144
154
|
|
|
155
|
+
@deprecated(
|
|
156
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use get_resource_with_custom_fields from safe_crud instead."
|
|
157
|
+
)
|
|
145
158
|
async def get_resource_with_custom_fields(
|
|
146
159
|
sql_model: Type[T], fides_key: str, async_session: AsyncSession
|
|
147
160
|
) -> Dict[str, Any]:
|
|
@@ -193,6 +206,9 @@ async def get_resource_with_custom_fields(
|
|
|
193
206
|
return resource_dict
|
|
194
207
|
|
|
195
208
|
|
|
209
|
+
@deprecated(
|
|
210
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use list_resource from safe_crud instead."
|
|
211
|
+
)
|
|
196
212
|
async def list_resource(sql_model: Type[T], async_session: AsyncSession) -> List[T]:
|
|
197
213
|
"""
|
|
198
214
|
Get a list of all of the resources of this type from the database.
|
|
@@ -203,6 +219,9 @@ async def list_resource(sql_model: Type[T], async_session: AsyncSession) -> List
|
|
|
203
219
|
return await list_resource_query(async_session, query, sql_model)
|
|
204
220
|
|
|
205
221
|
|
|
222
|
+
@deprecated(
|
|
223
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use list_resource_query from safe_crud instead."
|
|
224
|
+
)
|
|
206
225
|
async def list_resource_query(
|
|
207
226
|
async_session: AsyncSession, query: Select, sql_model: Type[T]
|
|
208
227
|
) -> List[T]:
|
|
@@ -225,6 +244,9 @@ async def list_resource_query(
|
|
|
225
244
|
return sql_resources
|
|
226
245
|
|
|
227
246
|
|
|
247
|
+
@deprecated(
|
|
248
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use update_resource from safe_crud instead."
|
|
249
|
+
)
|
|
228
250
|
async def update_resource(
|
|
229
251
|
sql_model: Type[T], resource_dict: Dict, async_session: AsyncSession
|
|
230
252
|
) -> Dict:
|
|
@@ -251,6 +273,9 @@ async def update_resource(
|
|
|
251
273
|
return await get_resource(sql_model, resource_dict["fides_key"], async_session)
|
|
252
274
|
|
|
253
275
|
|
|
276
|
+
@deprecated(
|
|
277
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use upsert_resources from safe_crud instead."
|
|
278
|
+
)
|
|
254
279
|
async def upsert_resources(
|
|
255
280
|
sql_model: Type[T], resource_dicts: List[Dict], async_session: AsyncSession
|
|
256
281
|
) -> Tuple[int, int]:
|
|
@@ -300,6 +325,9 @@ async def upsert_resources(
|
|
|
300
325
|
raise sa_error
|
|
301
326
|
|
|
302
327
|
|
|
328
|
+
@deprecated(
|
|
329
|
+
"This function uses manual session.begin() which can lead to unexpected transaction handling. Use delete_resource from safe_crud instead."
|
|
330
|
+
)
|
|
303
331
|
async def delete_resource(
|
|
304
332
|
sql_model: Type[T], fides_key: str, async_session: AsyncSession
|
|
305
333
|
) -> T:
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains "safe" versions of CRUD operations that do NOT
|
|
3
|
+
manually manage database transactions. Transaction management is left
|
|
4
|
+
to the calling code (endpoints, services) to handle at the appropriate
|
|
5
|
+
boundary.
|
|
6
|
+
|
|
7
|
+
Use functions from this module instead of fides.api.db.crud
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
from typing import Any, Dict, List, Tuple, Type, TypeVar
|
|
12
|
+
|
|
13
|
+
from fastapi import HTTPException
|
|
14
|
+
from loguru import logger as log
|
|
15
|
+
from sqlalchemy import and_, column
|
|
16
|
+
from sqlalchemy import delete as _delete
|
|
17
|
+
from sqlalchemy import or_
|
|
18
|
+
from sqlalchemy import update as _update
|
|
19
|
+
from sqlalchemy.dialects.postgresql import Insert as _insert
|
|
20
|
+
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
|
21
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
22
|
+
from sqlalchemy.future import select
|
|
23
|
+
from sqlalchemy.sql import Select
|
|
24
|
+
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
|
25
|
+
|
|
26
|
+
from fides.api.models.sql_models import ( # type: ignore[attr-defined]
|
|
27
|
+
CustomField,
|
|
28
|
+
CustomFieldDefinition,
|
|
29
|
+
FidesBase,
|
|
30
|
+
ResourceTypes,
|
|
31
|
+
)
|
|
32
|
+
from fides.api.util import errors
|
|
33
|
+
|
|
34
|
+
# Helps return type be linked to the type of the parameter
|
|
35
|
+
T = TypeVar("T", bound="FidesBase")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# CRUD Functions
|
|
39
|
+
async def create_resource(
|
|
40
|
+
sql_model: Type[T], resource_dict: Dict, async_session: AsyncSession
|
|
41
|
+
) -> T:
|
|
42
|
+
"""
|
|
43
|
+
Create a resource in the database.
|
|
44
|
+
|
|
45
|
+
This version does NOT manually manage transactions - transaction management
|
|
46
|
+
is left to the calling code.
|
|
47
|
+
"""
|
|
48
|
+
with log.contextualize(
|
|
49
|
+
sql_model=sql_model.__name__, fides_key=resource_dict["fides_key"]
|
|
50
|
+
):
|
|
51
|
+
|
|
52
|
+
existing_resource = await get_resource(
|
|
53
|
+
sql_model, resource_dict["fides_key"], async_session, raise_not_found=False
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if existing_resource is not None:
|
|
57
|
+
already_exists_error = errors.AlreadyExistsError(
|
|
58
|
+
sql_model.__name__, resource_dict["fides_key"]
|
|
59
|
+
)
|
|
60
|
+
log.bind(error=already_exists_error.detail["error"]).info( # type: ignore[index]
|
|
61
|
+
"Failed to insert resource"
|
|
62
|
+
)
|
|
63
|
+
raise already_exists_error
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
log.debug("Creating resource")
|
|
67
|
+
query = _insert(sql_model.__table__).values(resource_dict)
|
|
68
|
+
await async_session.execute(query)
|
|
69
|
+
except SQLAlchemyError as e:
|
|
70
|
+
log.exception(f"Failed to create resource with error: '{e}'")
|
|
71
|
+
sa_error = errors.QueryError()
|
|
72
|
+
raise sa_error
|
|
73
|
+
|
|
74
|
+
return await get_resource(sql_model, resource_dict["fides_key"], async_session)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def get_custom_fields_filtered(
|
|
78
|
+
async_session: AsyncSession,
|
|
79
|
+
resource_types_to_ids: Dict[ResourceTypes, List[str]] = defaultdict(list),
|
|
80
|
+
) -> FidesBase:
|
|
81
|
+
"""
|
|
82
|
+
Utility function to construct a filtered query for custom field values based on provided mapping of
|
|
83
|
+
resource types to resource IDs.
|
|
84
|
+
|
|
85
|
+
Only custom fields with an "active" CustomFieldDefinition are returned.
|
|
86
|
+
|
|
87
|
+
This is for use in bulk querying of custom fields, to avoid multiple round trips to the db.
|
|
88
|
+
"""
|
|
89
|
+
with log.contextualize(model=CustomField):
|
|
90
|
+
try:
|
|
91
|
+
log.debug("Fetching resource")
|
|
92
|
+
query = select(
|
|
93
|
+
CustomField.resource_id,
|
|
94
|
+
CustomField.value,
|
|
95
|
+
CustomFieldDefinition.resource_type,
|
|
96
|
+
CustomFieldDefinition.name,
|
|
97
|
+
CustomFieldDefinition.field_type,
|
|
98
|
+
).join(
|
|
99
|
+
CustomFieldDefinition,
|
|
100
|
+
CustomFieldDefinition.id == CustomField.custom_field_definition_id,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
criteria = [
|
|
104
|
+
and_(
|
|
105
|
+
CustomFieldDefinition.resource_type == resource_type.value,
|
|
106
|
+
CustomField.resource_id.in_(resource_ids),
|
|
107
|
+
# pylint: disable=singleton-comparison
|
|
108
|
+
CustomFieldDefinition.active == True,
|
|
109
|
+
)
|
|
110
|
+
for resource_type, resource_ids in resource_types_to_ids.items()
|
|
111
|
+
]
|
|
112
|
+
query = query.where(or_(False, *criteria))
|
|
113
|
+
result = await async_session.execute(query)
|
|
114
|
+
return result.mappings().all()
|
|
115
|
+
except SQLAlchemyError as e:
|
|
116
|
+
sa_error = errors.QueryError()
|
|
117
|
+
log.exception(f"Failed to fetch custom fields with error: '{e}'")
|
|
118
|
+
raise sa_error
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def get_resource(
|
|
122
|
+
sql_model: Type[T],
|
|
123
|
+
fides_key: str,
|
|
124
|
+
async_session: AsyncSession,
|
|
125
|
+
raise_not_found: bool = True,
|
|
126
|
+
) -> T:
|
|
127
|
+
"""
|
|
128
|
+
Get a resource from the database by its FidesKey.
|
|
129
|
+
|
|
130
|
+
Returns a SQLAlchemy model of that resource.
|
|
131
|
+
|
|
132
|
+
This version does NOT manually manage transactions - transaction management
|
|
133
|
+
is left to the calling code.
|
|
134
|
+
"""
|
|
135
|
+
with log.contextualize(sql_model=sql_model.__name__, fides_key=fides_key):
|
|
136
|
+
try:
|
|
137
|
+
log.debug("Fetching resource")
|
|
138
|
+
query = select(sql_model).where(sql_model.fides_key == fides_key)
|
|
139
|
+
result = await async_session.execute(query)
|
|
140
|
+
except SQLAlchemyError as e:
|
|
141
|
+
sa_error = errors.QueryError()
|
|
142
|
+
log.exception(f"Failed to fetch resource with error: '{e}'")
|
|
143
|
+
raise sa_error
|
|
144
|
+
|
|
145
|
+
sql_resource = result.scalars().first()
|
|
146
|
+
if sql_resource is None and raise_not_found:
|
|
147
|
+
not_found_error = errors.NotFoundError(sql_model.__name__, fides_key)
|
|
148
|
+
log.bind(error=not_found_error.detail["error"]).info("Resource not found") # type: ignore[index]
|
|
149
|
+
raise not_found_error
|
|
150
|
+
|
|
151
|
+
return sql_resource
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
async def get_resource_with_custom_fields(
|
|
155
|
+
sql_model: Type[T], fides_key: str, async_session: AsyncSession
|
|
156
|
+
) -> Dict[str, Any]:
|
|
157
|
+
"""Get a resource from the database by its FidesKey including it's custom fields.
|
|
158
|
+
|
|
159
|
+
Returns a dictionary of that resource.
|
|
160
|
+
|
|
161
|
+
This version does NOT manually manage transactions - transaction management
|
|
162
|
+
is left to the calling code.
|
|
163
|
+
"""
|
|
164
|
+
resource: T = await get_resource(sql_model, fides_key, async_session)
|
|
165
|
+
resource_dict = resource.__dict__
|
|
166
|
+
resource_dict.pop("_sa_instance_state", None)
|
|
167
|
+
|
|
168
|
+
with log.contextualize(sql_model=sql_model.__name__, fides_key=fides_key):
|
|
169
|
+
try:
|
|
170
|
+
log.debug("Fetching custom fields for resource")
|
|
171
|
+
query = (
|
|
172
|
+
select(CustomFieldDefinition.name, CustomField.value)
|
|
173
|
+
.join(
|
|
174
|
+
CustomField,
|
|
175
|
+
CustomField.custom_field_definition_id == CustomFieldDefinition.id,
|
|
176
|
+
)
|
|
177
|
+
.where(
|
|
178
|
+
(CustomField.resource_id == resource.fides_key)
|
|
179
|
+
& ( # pylint: disable=singleton-comparison
|
|
180
|
+
CustomFieldDefinition.active == True
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
result = await async_session.execute(query)
|
|
185
|
+
except SQLAlchemyError as e:
|
|
186
|
+
sa_error = errors.QueryError()
|
|
187
|
+
log.exception(f"Failed to fetch custom fields with error: '{e}'")
|
|
188
|
+
raise sa_error
|
|
189
|
+
|
|
190
|
+
custom_fields = result.mappings().all()
|
|
191
|
+
|
|
192
|
+
if not custom_fields:
|
|
193
|
+
return resource_dict
|
|
194
|
+
|
|
195
|
+
for field in custom_fields:
|
|
196
|
+
if field["name"] in resource_dict:
|
|
197
|
+
resource_dict[field["name"]] = (
|
|
198
|
+
f"{resource_dict[field['name']]}, {', '.join(field['value'])}"
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
resource_dict[field["name"]] = ", ".join(field["value"])
|
|
202
|
+
|
|
203
|
+
return resource_dict
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
async def list_resource(sql_model: Type[T], async_session: AsyncSession) -> List[T]:
|
|
207
|
+
"""
|
|
208
|
+
Get a list of all of the resources of this type from the database.
|
|
209
|
+
|
|
210
|
+
Returns a list of SQLAlchemy models of that resource type.
|
|
211
|
+
|
|
212
|
+
This version does NOT manually manage transactions - transaction management
|
|
213
|
+
is left to the calling code.
|
|
214
|
+
"""
|
|
215
|
+
query = select(sql_model)
|
|
216
|
+
return await list_resource_query(async_session, query, sql_model)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
async def list_resource_query(
|
|
220
|
+
async_session: AsyncSession, query: Select, sql_model: Type[T]
|
|
221
|
+
) -> List[T]:
|
|
222
|
+
"""
|
|
223
|
+
Utility function to wrap a select query in generic "list_resource" execution handling.
|
|
224
|
+
Wrapping includes execution against the DB session, logging and error handling.
|
|
225
|
+
|
|
226
|
+
This version does NOT manually manage transactions - transaction management
|
|
227
|
+
is left to the calling code.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
with log.contextualize(sql_model=sql_model.__name__):
|
|
231
|
+
try:
|
|
232
|
+
log.debug("Fetching resources")
|
|
233
|
+
result = await async_session.execute(query)
|
|
234
|
+
sql_resources = result.scalars().all()
|
|
235
|
+
except SQLAlchemyError as e:
|
|
236
|
+
log.exception(f"Failed to fetch resources with error: '{e}'")
|
|
237
|
+
sa_error = errors.QueryError()
|
|
238
|
+
raise sa_error
|
|
239
|
+
|
|
240
|
+
return sql_resources
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
async def update_resource(
|
|
244
|
+
sql_model: Type[T], resource_dict: Dict, async_session: AsyncSession
|
|
245
|
+
) -> Dict:
|
|
246
|
+
"""
|
|
247
|
+
Update a resource in the database by its fides_key.
|
|
248
|
+
|
|
249
|
+
This version does NOT manually manage transactions - transaction management
|
|
250
|
+
is left to the calling code.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
with log.contextualize(
|
|
254
|
+
sql_model=sql_model.__name__, fides_key=resource_dict["fides_key"]
|
|
255
|
+
):
|
|
256
|
+
await get_resource(sql_model, resource_dict["fides_key"], async_session)
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
log.debug("Updating resource")
|
|
260
|
+
await async_session.execute(
|
|
261
|
+
_update(sql_model.__table__)
|
|
262
|
+
.where(sql_model.fides_key == resource_dict["fides_key"])
|
|
263
|
+
.values(resource_dict)
|
|
264
|
+
)
|
|
265
|
+
except SQLAlchemyError as e:
|
|
266
|
+
log.exception(f"Failed to update resource with error: '{e}'")
|
|
267
|
+
sa_error = errors.QueryError()
|
|
268
|
+
raise sa_error
|
|
269
|
+
|
|
270
|
+
return await get_resource(sql_model, resource_dict["fides_key"], async_session)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
async def upsert_resources(
|
|
274
|
+
sql_model: Type[T], resource_dicts: List[Dict], async_session: AsyncSession
|
|
275
|
+
) -> Tuple[int, int]:
|
|
276
|
+
"""
|
|
277
|
+
Insert new resources into the database. If a resource already exists,
|
|
278
|
+
update it by it's fides_key.
|
|
279
|
+
|
|
280
|
+
Returns a Tuple containing the counts of inserted and updated rows.
|
|
281
|
+
|
|
282
|
+
This version does NOT manually manage transactions - transaction management
|
|
283
|
+
is left to the calling code.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
with log.contextualize(
|
|
287
|
+
sql_model=sql_model.__name__,
|
|
288
|
+
fides_keys=[resource["fides_key"] for resource in resource_dicts],
|
|
289
|
+
):
|
|
290
|
+
try:
|
|
291
|
+
log.debug("Upserting resources")
|
|
292
|
+
insert_stmt = (
|
|
293
|
+
_insert(sql_model.__table__)
|
|
294
|
+
.values(resource_dicts)
|
|
295
|
+
.returning(
|
|
296
|
+
(column("xmax") == 0), # Row was inserted
|
|
297
|
+
(column("xmax") != 0), # Row was updated
|
|
298
|
+
)
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
excluded = dict(insert_stmt.excluded.items()) # type: ignore[attr-defined]
|
|
302
|
+
excluded.pop("id", None) # If updating, don't update the "id"
|
|
303
|
+
|
|
304
|
+
result = await async_session.execute(
|
|
305
|
+
insert_stmt.on_conflict_do_update(
|
|
306
|
+
index_elements=["fides_key"],
|
|
307
|
+
set_=excluded,
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
inserts, updates = 0, 0
|
|
312
|
+
for xmax in result:
|
|
313
|
+
inserts += 1 if xmax[0] else 0
|
|
314
|
+
updates += 1 if xmax[1] else 0
|
|
315
|
+
|
|
316
|
+
return (inserts, updates)
|
|
317
|
+
|
|
318
|
+
except SQLAlchemyError as e:
|
|
319
|
+
log.exception(f"Failed to upsert resources with error: '{e}'")
|
|
320
|
+
sa_error = errors.QueryError()
|
|
321
|
+
raise sa_error
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
async def delete_resource(
|
|
325
|
+
sql_model: Type[T], fides_key: str, async_session: AsyncSession
|
|
326
|
+
) -> T:
|
|
327
|
+
"""
|
|
328
|
+
Delete a resource by its fides_key.
|
|
329
|
+
|
|
330
|
+
If the resource has child keys referring to it, also delete those.
|
|
331
|
+
|
|
332
|
+
This version does NOT manually manage transactions - transaction management
|
|
333
|
+
is left to the calling code.
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
with log.contextualize(sql_model=sql_model.__name__, fides_key=fides_key):
|
|
337
|
+
sql_resource = await get_resource(sql_model, fides_key, async_session)
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
# Automatically delete related resources if they are CTL objects
|
|
341
|
+
if hasattr(sql_model, "parent_key"):
|
|
342
|
+
log.debug("Deleting resource and its children")
|
|
343
|
+
query = (
|
|
344
|
+
_delete(sql_model.__table__)
|
|
345
|
+
.where(
|
|
346
|
+
or_(
|
|
347
|
+
sql_model.fides_key == fides_key,
|
|
348
|
+
sql_model.fides_key.like(f"{fides_key}.%"),
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
.execution_options(synchronize_session=False)
|
|
352
|
+
)
|
|
353
|
+
else:
|
|
354
|
+
log.debug("Deleting resource")
|
|
355
|
+
query = _delete(sql_model.__table__).where(
|
|
356
|
+
sql_model.fides_key == fides_key
|
|
357
|
+
)
|
|
358
|
+
await async_session.execute(query)
|
|
359
|
+
except IntegrityError as err:
|
|
360
|
+
raw_error_text: str = err.orig.args[0]
|
|
361
|
+
|
|
362
|
+
if "violates foreign key constraint" in raw_error_text:
|
|
363
|
+
error_message = "Failed to delete resource! Foreign key constraint found, try deleting related resources first."
|
|
364
|
+
else:
|
|
365
|
+
error_message = "Failed to delete resource!"
|
|
366
|
+
|
|
367
|
+
log.bind(error="SQL Query integrity error!").error(raw_error_text)
|
|
368
|
+
raise HTTPException(
|
|
369
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
370
|
+
detail=error_message,
|
|
371
|
+
)
|
|
372
|
+
except SQLAlchemyError as e:
|
|
373
|
+
log.exception(f"Failed to delete resource with error: '{e}'")
|
|
374
|
+
sa_error = errors.QueryError()
|
|
375
|
+
raise sa_error
|
|
376
|
+
|
|
377
|
+
return sql_resource
|
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
|
"""
|
|
@@ -355,6 +355,64 @@ class PrivacyRequest(
|
|
|
355
355
|
|
|
356
356
|
return super().create(db=db, data=data, check_name=check_name)
|
|
357
357
|
|
|
358
|
+
def to_safe_dict(self) -> Dict[str, Any]:
|
|
359
|
+
"""
|
|
360
|
+
Return a dict representation of the PrivacyRequest, excluding any fields
|
|
361
|
+
that may contain sensitive information.
|
|
362
|
+
"""
|
|
363
|
+
return {
|
|
364
|
+
"id": self.id,
|
|
365
|
+
"external_id": self.external_id,
|
|
366
|
+
"status": self.status.value,
|
|
367
|
+
"requested_at": (
|
|
368
|
+
self.requested_at.isoformat() if self.requested_at else None
|
|
369
|
+
),
|
|
370
|
+
"started_processing_at": (
|
|
371
|
+
self.started_processing_at.isoformat()
|
|
372
|
+
if self.started_processing_at
|
|
373
|
+
else None
|
|
374
|
+
),
|
|
375
|
+
"finished_processing_at": (
|
|
376
|
+
self.finished_processing_at.isoformat()
|
|
377
|
+
if self.finished_processing_at
|
|
378
|
+
else None
|
|
379
|
+
),
|
|
380
|
+
"reviewed_at": self.reviewed_at.isoformat() if self.reviewed_at else None,
|
|
381
|
+
"reviewed_by": self.reviewed_by,
|
|
382
|
+
"finalized_at": (
|
|
383
|
+
self.finalized_at.isoformat() if self.finalized_at else None
|
|
384
|
+
),
|
|
385
|
+
"finalized_by": self.finalized_by,
|
|
386
|
+
"submitted_by": self.submitted_by,
|
|
387
|
+
"custom_privacy_request_fields_approved_by": (
|
|
388
|
+
self.custom_privacy_request_fields_approved_by
|
|
389
|
+
),
|
|
390
|
+
"identity_verified_at": (
|
|
391
|
+
self.identity_verified_at.isoformat()
|
|
392
|
+
if self.identity_verified_at
|
|
393
|
+
else None
|
|
394
|
+
),
|
|
395
|
+
"custom_privacy_request_fields_approved_at": (
|
|
396
|
+
self.custom_privacy_request_fields_approved_at.isoformat()
|
|
397
|
+
if self.custom_privacy_request_fields_approved_at
|
|
398
|
+
else None
|
|
399
|
+
),
|
|
400
|
+
"client_id": self.client_id,
|
|
401
|
+
"origin": self.origin,
|
|
402
|
+
"policy_id": self.policy_id,
|
|
403
|
+
"policy": self.policy.to_safe_dict() if self.policy else None,
|
|
404
|
+
"property_id": self.property_id,
|
|
405
|
+
"cancel_reason": self.cancel_reason,
|
|
406
|
+
"canceled_at": self.canceled_at.isoformat() if self.canceled_at else None,
|
|
407
|
+
"consent_preferences": self.consent_preferences,
|
|
408
|
+
"source": self.source.value if self.source else None,
|
|
409
|
+
"paused_at": self.paused_at.isoformat() if self.paused_at else None,
|
|
410
|
+
"due_date": self.due_date.isoformat() if self.due_date else None,
|
|
411
|
+
"days_left": self.days_left,
|
|
412
|
+
"custom_fields": self.get_persisted_custom_privacy_request_fields() if self.custom_fields else None, # type: ignore[attr-defined]
|
|
413
|
+
"location": self.location,
|
|
414
|
+
}
|
|
415
|
+
|
|
358
416
|
def clear_cached_values(self) -> None:
|
|
359
417
|
"""
|
|
360
418
|
Clears all cached values associated with this privacy request from Redis.
|
|
@@ -903,6 +961,8 @@ class PrivacyRequest(
|
|
|
903
961
|
callback_type=CallbackType.pre_approval,
|
|
904
962
|
identity=self.get_cached_identity_data(),
|
|
905
963
|
policy_action=policy_action,
|
|
964
|
+
privacy_request=self.to_safe_dict(),
|
|
965
|
+
timestamp=datetime.utcnow(),
|
|
906
966
|
)
|
|
907
967
|
headers = {
|
|
908
968
|
"reply-to-approve": f"/privacy-request/{self.id}/pre-approve/eligible",
|
|
@@ -943,6 +1003,8 @@ class PrivacyRequest(
|
|
|
943
1003
|
callback_type=webhook.prefix,
|
|
944
1004
|
identity=self.get_cached_identity_data(),
|
|
945
1005
|
policy_action=policy_action,
|
|
1006
|
+
privacy_request=self.to_safe_dict(),
|
|
1007
|
+
timestamp=datetime.utcnow(),
|
|
946
1008
|
)
|
|
947
1009
|
|
|
948
1010
|
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:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import ClassVar, List
|
|
1
|
+
from typing import ClassVar, List, Optional
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
@@ -30,10 +30,22 @@ class MongoDBSchema(ConnectionConfigSecretsSchema):
|
|
|
30
30
|
json_schema_extra={"sensitive": True},
|
|
31
31
|
)
|
|
32
32
|
defaultauthdb: str = Field(
|
|
33
|
-
title="Default
|
|
33
|
+
title="Default auth DB",
|
|
34
34
|
description="Used to specify the default authentication database.",
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
+
use_srv: Optional[bool] = Field(
|
|
38
|
+
False,
|
|
39
|
+
title="Use SRV",
|
|
40
|
+
description="Enable SRV record lookup for service discovery (mongodb+srv://). Required for MongoDB Atlas. Enables SSL by default.",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
ssl_enabled: Optional[bool] = Field(
|
|
44
|
+
None,
|
|
45
|
+
title="SSL enabled",
|
|
46
|
+
description="Enable SSL/TLS encryption. With SRV: defaults to enabled (can override). Without SRV: defaults to disabled.",
|
|
47
|
+
)
|
|
48
|
+
|
|
37
49
|
_required_components: ClassVar[List[str]] = [
|
|
38
50
|
"host",
|
|
39
51
|
"username",
|