ethyca-fides 2.63.3rc0__py2.py3-none-any.whl → 2.64.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.
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/METADATA +2 -2
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/RECORD +249 -242
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/ba414a58ba90_create_manual_task_config_tables.py +121 -0
- fides/api/api/v1/endpoints/connection_endpoints.py +16 -3
- fides/api/api/v1/endpoints/oauth_endpoints.py +8 -2
- fides/api/db/base.py +4 -0
- fides/api/models/attachment.py +37 -23
- fides/api/models/manual_tasks/__init__.py +6 -0
- fides/api/models/manual_tasks/manual_task.py +11 -1
- fides/api/models/manual_tasks/manual_task_config.py +136 -0
- fides/api/models/manual_tasks/manual_task_log.py +13 -9
- fides/api/schemas/connection_configuration/connection_config.py +19 -4
- fides/api/schemas/manual_tasks/manual_task_config.py +311 -0
- fides/api/schemas/manual_tasks/manual_task_schemas.py +1 -1
- fides/api/schemas/manual_tasks/manual_task_status.py +1 -1
- fides/api/schemas/privacy_request.py +2 -0
- fides/api/service/connectors/query_configs/saas_query_config.py +15 -0
- fides/api/service/privacy_request/attachment_handling.py +132 -0
- fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +264 -46
- fides/api/service/privacy_request/dsr_package/templates/attachments_index.html +33 -0
- fides/api/service/privacy_request/dsr_package/templates/collection_index.html +34 -9
- fides/api/service/privacy_request/dsr_package/templates/main.css +45 -2
- fides/api/service/privacy_request/dsr_package/templates/welcome.html +12 -8
- fides/api/service/privacy_request/request_runner_service.py +258 -139
- fides/api/service/storage/gcs.py +15 -3
- fides/api/service/storage/s3.py +28 -14
- fides/api/service/storage/util.py +45 -7
- fides/api/tasks/csv_utils.py +170 -0
- fides/api/tasks/encryption_utils.py +42 -0
- fides/api/tasks/storage.py +85 -91
- fides/api/util/cache.py +6 -3
- fides/api/util/saas_util.py +1 -0
- fides/config/redis_settings.py +105 -44
- fides/service/manual_tasks/manual_task_config_service.py +370 -0
- fides/service/manual_tasks/manual_task_service.py +231 -87
- fides/service/manual_tasks/utils.py +185 -0
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1040-630c7f4284dc6f70.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1100-d43cb04522a6505c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1316-6cc72a45ebf7ff81.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1817-b4688ba5042ec687.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/2430-b480401d44c55416.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/2599-6c4d22e75028d8b6.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/2921-aabf41bf3d7573f9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3450-bdaeb35442d810b4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3505-a79256cd851dfab4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3513-8677ee280eaef0da.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3855-0dec3e7d9e886550.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3872-ffa16c2df7ef0ab6.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3923-5d580fbb1dd6ae01.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/401-fceaae662cfca5a5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4060-71cd041e5a57ca5a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/409-037cfc3f096150f0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4121-78a76e980acbd539.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4230-1cdb7ea1be370ed3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/431-f72599f01b98f07d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4481-f597a7cf03f8c9e1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5309-4511df9708d5a63c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5574-3cd33b3a6c937899.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6277-3fb4c7fc790a6d20.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6662-cb11881dcaabe5e2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6853-a4097260e402980e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6882-3cc73d407a088d7d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/69-6889d6674c95e7b5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6954-13a25cef3a8fdd76.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/699-8ca44b0de9fa20f0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7553-a95939c32d54b5b7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/79-5670e31eb65d0a53.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/796-9a6b13c838e25538.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/8433-adb1fcb29d82f1b7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9046-fdf53cc7e926a8c1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{905-8ab919e7b274ed50.js → 905-742074a074be1055.js} +2 -2
- fides/ui-build/static/admin/_next/static/chunks/9226-ba6587e46ec7659a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9392.81edc11e3a175275.js → 9392.25024e070026343d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9676.e60a53f1f5890847.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9767-e49b065d03ce4e80.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9951-f9ab5cac7e2c05ab.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/404-ac2f0844e5c4b4cd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-f70bffa5a7903c46.js → _app-8ec6e466f3373ac0.js} +10 -10
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-0a5f2310ce6b1059.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-00cb904825aad7e3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-587e21d14e0a5196.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/add-vendors-fa7305b88c1afd20.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-f140ec9d8e8a0f7a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-0edb7c92518e7d21.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-d8d926f0735a2546.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/[id]-5c949f2e3cef2398.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/new-130155cfb4a0bcc7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-1135ad8924d32c36.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/properties-776855e370414beb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-21c23f75ff1135d9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent-4d5ea70a77df1bb8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-18e3faf7963962e4.js → [resourceUrn]-c623d6f1a61c8ea9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-030ee304cbe5e530.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-cfac259a30641e68.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-7320524a47104798.js → [resourceUrn]-57bd5cdf784f059f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-7b5aec33da578745.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-c948f93c833d4358.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-333f53caab751428.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-27205f8457a1ecb0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-20a1043f6a06198f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-4c526db0c30c488a.js → [resourceUrn]-06edce289876dea1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-6f27dbb7c8edc69d.js → detection-faf326a6200637d0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-562d2b8ae90dd1f0.js → [resourceUrn]-64acf269256ee74f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-fe7f51502eda57c9.js → discovery-8c3e4be6d36da66d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datamap-fb50de22f83edd4a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-41ab27c4195cfa93.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-6e2caba24b3e78c2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-904d43e31157aa55.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-d4e31a1c4a58800e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-8f7d16bc5e9229c8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-4a33dd0371dbaebc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-e88509346b2d2851.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-8f9b8890018e1ea5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{fides-js-docs-80b241bf6cddb72e.js → fides-js-docs-5d8fd1af75f19e2f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/index-1adb6bcb71701ac2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-fdc2964fa7d1d8fd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-adc286ff254e7f41.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/[id]-9b4d1d61c7c97509.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/add-template-f8fd4795e260887c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-aa744ae8b61e5ff2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-3407158757fb3627.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-47e947c02ae90fd0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-24f9a44512ce8827.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-e567a69f8c37fb9a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-35a33f9c7def2220.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-780e18dde8e38099.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-7a17dffa515e5560.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-91dd0039cc2b70bc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-b01cbbaac34dadbc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-a15410de7f1d0f84.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-1a1aa83a3f88844c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-c4e1b69fb5bab61a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/[id]-19737d4f21aadbee.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/add-property-9ccb295110feee20.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties-3a1037a2e036212a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-4cdbbb8cd1d8698e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-965cc21889b25e44.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-0e1c381d488a7ada.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-d0e350d2a2667883.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-7796fbf458f8f159.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-6f866bc799a5f67f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domain-records-0b44b2b224077dcd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-5d00e1155bd11178.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-d2cdbe770683e9df.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-811dadb489f23d7d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-24108f615ff5e1e7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/regulations-54f142bc3e4c95ba.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-fef247a87baeb080.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]-6eb886e7b7e6785b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-7b71274334c559a4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-18534d2a79a3850b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-75d41fde668b9025.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management-dd43755b687c09a7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/webpack-0a61b5bd21a41fe6.js +1 -0
- fides/ui-build/static/admin/_next/static/css/c693338e3bc8dcc6.css +1 -0
- fides/ui-build/static/admin/_next/static/nRQ3pmK_d3F5PJE39rP2h/_buildManifest.js +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/images/connector-logos/salesforce.svg +41 -0
- fides/ui-build/static/admin/index.html +1 -1
- fides/ui-build/static/admin/integrations/[id].html +1 -1
- fides/ui-build/static/admin/integrations.html +1 -1
- fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
- fides/ui-build/static/admin/lib/fides-headless.js +1 -1
- fides/ui-build/static/admin/lib/fides-preview.js +1 -1
- fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
- fides/ui-build/static/admin/lib/fides.js +2 -2
- fides/ui-build/static/admin/login/[provider].html +1 -1
- fides/ui-build/static/admin/login.html +1 -1
- fides/ui-build/static/admin/messaging/[id].html +1 -1
- fides/ui-build/static/admin/messaging/add-template.html +1 -1
- fides/ui-build/static/admin/messaging.html +1 -1
- fides/ui-build/static/admin/poc/ant-components.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
- fides/ui-build/static/admin/poc/forms.html +1 -1
- fides/ui-build/static/admin/poc/table-migration.html +1 -1
- fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
- fides/ui-build/static/admin/privacy-requests.html +1 -1
- fides/ui-build/static/admin/properties/[id].html +1 -1
- fides/ui-build/static/admin/properties/add-property.html +1 -1
- fides/ui-build/static/admin/properties.html +1 -1
- fides/ui-build/static/admin/reporting/datamap.html +1 -1
- fides/ui-build/static/admin/settings/about/alpha.html +1 -1
- fides/ui-build/static/admin/settings/about.html +1 -1
- fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
- fides/ui-build/static/admin/settings/consent.html +1 -1
- fides/ui-build/static/admin/settings/custom-fields.html +1 -1
- fides/ui-build/static/admin/settings/domain-records.html +1 -1
- fides/ui-build/static/admin/settings/domains.html +1 -1
- fides/ui-build/static/admin/settings/email-templates.html +1 -1
- fides/ui-build/static/admin/settings/locations.html +1 -1
- fides/ui-build/static/admin/settings/organization.html +1 -1
- fides/ui-build/static/admin/settings/regulations.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id].html +1 -1
- fides/ui-build/static/admin/systems.html +1 -1
- fides/ui-build/static/admin/taxonomy.html +1 -1
- fides/ui-build/static/admin/user-management/new.html +1 -1
- fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
- fides/ui-build/static/admin/user-management.html +1 -1
- fides/api/service/privacy_request/dsr_package/templates/item.html +0 -37
- fides/ui-build/static/admin/_next/static/chunks/1099-667e84655846e78c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1100-0b01f500b1eaf60d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-951f58ddd5d46081.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1904-964f8eb328dc2715.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/2310-744354001d01f366.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/2921-49af55ad7c631c93.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3119-e36ae5071c8f27a5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3505-113f9c95d34b7aae.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3513-5c2d412a84a78971.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3872-45cc725e241211f0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3923-b4f701ada3ef0ee0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/401-7e800aed05537126.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4060-90a52a9afc655bfc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4121-66b0e00d5e7ae817.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4132-9b1731bfec6ee537.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4481-7f6710c928bb0cb0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5258-2079138c8cc34f6c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5404-2694509cf5fa96da.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5487-2cbd8d2169eb2a65.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5683-37137111b3e769fb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6202-081545c7822d09af.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6277-459e054b2702c60e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/641-7e4eef3222cbda70.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6853-688df0b88fe65fd5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/69-00cba94689b9e740.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6954-4e313b4599b8763d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7553-08bc3d9f66695111.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/79-fc548561beed136f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/796-d6586308ed44334b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7980-736f9fd1e749ddd2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8032-74d94f7bd5b81c89.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8433-51870336908fb253.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8499-1fd392d0be9e8ee4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8702-d1c8296f9f6afc10.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9033-fdd87182c15b91e2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9187-851756440f79cd75.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9327-6a53461c9764b16f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9494-1ffb888b95289891.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9676.61cf5f6d6a083175.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9767-afd674014a1d1152.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/404-ec04f826f3dd79ea.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-1bec086d567aacff.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-f68bf100e4e60e88.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-effde5cfe49de55f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/add-vendors-ec95ed8cb0712828.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-4cc195e15e0c3cc8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-be8972c79fb39705.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-ccf96207de3b74ea.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/[id]-b9823cc008372cee.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/new-373f5772ab41bc93.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-b9beeee1bde5ca79.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/properties-6ab3a5baafebd199.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-8562790ae07f17c9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent-42d4d2d6e0253671.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-9d1df6d890671b0c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-7eb08af333baaa8e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-bb57eed84f59a932.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-47eb34aef3e31ac6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-76cefefc53e84c7f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-9d8e84a8b4bf568d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-f208fef5e72dafd6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datamap-db45aa864e9dda8a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-d5cfdebc74654337.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-618b89228f83435e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-12fc86f15a4c764e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-c23d18a9b56c2e3c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-e3b2d8e3980ab093.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-6e27257eccf65f01.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-bbac1f624424282d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-84eb56f5a07bdf4f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/index-773182b5e35d0045.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-eb28c927da5bd653.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-781808bca01f8048.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/[id]-b51bee8680d66b20.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/add-template-1de479533f733fbd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-7dc295b3ed3d2224.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-f64dac3392f5ded7.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-eb020bfac4bee532.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-0bd62e28b539e114.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-936877004113c2a6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-6416f01524482af9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-3f4e1313d1f2969b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-1db7a54437db7db0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-64236fd0141414fd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-8cab04871908cfeb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-150d40428245ee0c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-b6c876dceb16ad1b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-20cdb2c8a03deae1.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/[id]-54bcc875592d1fb9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/add-property-644dc669b508a79a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties-9a88220d03e7e02f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-70dc1081df37ea69.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-3c71b4dbcb6fd6c9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-7cb16e0000dd16c9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-a18d8f12ee8dcf5d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-dc220e116ad5c09e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-55ddc5f25b86f28e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domain-records-5ca7decded228bc8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-a6fafa1be2834c40.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-e633750d2b45ddd6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-3948686cbd372969.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-04ece499c22d23f4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/regulations-7752305084280cca.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-9e5f9066be6f218d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]-86de9e6d72098e45.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-cac52e6c3abf6a15.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-60d5930b6855679b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-b0f4c34752d32c73.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management-7dee83dd6d9292aa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/webpack-8457bad7859c44f0.js +0 -1
- fides/ui-build/static/admin/_next/static/css/1fdf5c593349dbc6.css +0 -1
- fides/ui-build/static/admin/_next/static/f_8LkSZkhtDM14f8gbC0b/_buildManifest.js +0 -1
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{f_8LkSZkhtDM14f8gbC0b → nRQ3pmK_d3F5PJE39rP2h}/_ssgManifest.js +0 -0
@@ -1,13 +1,15 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
|
+
import time as time_module
|
3
4
|
import zipfile
|
4
5
|
from collections import defaultdict
|
5
6
|
from io import BytesIO
|
6
7
|
from pathlib import Path
|
7
|
-
from typing import Any,
|
8
|
+
from typing import Any, Optional
|
8
9
|
|
9
10
|
import jinja2
|
10
11
|
from jinja2 import Environment, FileSystemLoader
|
12
|
+
from loguru import logger
|
11
13
|
|
12
14
|
from fides.api.models.privacy_request import PrivacyRequest
|
13
15
|
from fides.api.schemas.policy import ActionType
|
@@ -22,54 +24,79 @@ BORDER_COLOR = "#E2E8F0"
|
|
22
24
|
|
23
25
|
# pylint: disable=too-many-instance-attributes
|
24
26
|
class DsrReportBuilder:
|
27
|
+
"""
|
28
|
+
Manages populating HTML templates from the given data and adding the generated
|
29
|
+
pages to a zip file in a way that the pages can be navigated between.
|
30
|
+
|
31
|
+
The zip file is structured as follows:
|
32
|
+
- welcome.html: the main index page
|
33
|
+
- data/dataset_name/index.html: the index page for the dataset
|
34
|
+
- data/dataset_name/collection_name/index.html: the index page for the collection
|
35
|
+
- data/dataset_name/collection_name/item_index.html: the detail page for the item
|
36
|
+
- attachments/index.html: the index page for the attachments
|
37
|
+
|
38
|
+
Args:
|
39
|
+
privacy_request: the privacy request object
|
40
|
+
dsr_data: the DSR data
|
41
|
+
"""
|
42
|
+
|
25
43
|
def __init__(
|
26
44
|
self,
|
27
45
|
privacy_request: PrivacyRequest,
|
28
|
-
dsr_data:
|
46
|
+
dsr_data: dict[str, Any],
|
29
47
|
):
|
30
48
|
"""
|
31
|
-
|
32
|
-
pages to a zip file in a way that the pages can be navigated between.
|
49
|
+
Initializes the DSR report builder.
|
33
50
|
"""
|
51
|
+
# Define pretty_print function for Jinja templates
|
52
|
+
jinja2.filters.FILTERS["pretty_print"] = lambda value, indent=4: json.dumps(
|
53
|
+
value, indent=indent, cls=StorageJSONEncoder
|
54
|
+
)
|
34
55
|
|
35
|
-
# zip file variables
|
56
|
+
# Initialize instance zip file variables
|
36
57
|
self.baos = BytesIO()
|
37
58
|
|
38
59
|
# we close this in the finally block of generate()
|
39
60
|
# pylint: disable=consider-using-with
|
40
61
|
self.out = zipfile.ZipFile(self.baos, "w")
|
41
|
-
|
42
|
-
# Jinja template environment initialization
|
43
|
-
def pretty_print(value: str, indent: int = 4) -> str:
|
44
|
-
return json.dumps(
|
45
|
-
value, indent=indent, default=StorageJSONEncoder().default
|
46
|
-
)
|
47
|
-
|
48
|
-
jinja2.filters.FILTERS["pretty_print"] = pretty_print
|
49
62
|
self.template_loader = Environment(
|
50
63
|
loader=FileSystemLoader(DSR_DIRECTORY), autoescape=True
|
51
64
|
)
|
52
65
|
|
53
66
|
# to pass in custom colors in the future
|
54
|
-
self.template_data:
|
67
|
+
self.template_data: dict[str, Any] = {
|
55
68
|
"text_color": TEXT_COLOR,
|
56
69
|
"header_color": HEADER_COLOR,
|
57
70
|
"border_color": BORDER_COLOR,
|
58
71
|
}
|
59
|
-
self.main_links:
|
72
|
+
self.main_links: dict[str, Any] = {} # used to track the generated pages
|
60
73
|
|
61
74
|
# report data to populate the templates
|
62
75
|
self.request_data = _map_privacy_request(privacy_request)
|
63
76
|
self.dsr_data = dsr_data
|
64
77
|
|
78
|
+
# Track used filenames across all attachments
|
79
|
+
self.used_filenames: set[str] = set()
|
80
|
+
|
65
81
|
def _populate_template(
|
66
82
|
self,
|
67
83
|
template_path: str,
|
68
84
|
heading: Optional[str] = None,
|
69
85
|
description: Optional[str] = None,
|
70
|
-
data: Optional[
|
86
|
+
data: Optional[dict[str, Any]] = None,
|
71
87
|
) -> str:
|
72
|
-
"""
|
88
|
+
"""
|
89
|
+
Populates the template with the given data.
|
90
|
+
|
91
|
+
Args:
|
92
|
+
template_path: the path to the template to populate
|
93
|
+
heading: the heading to display on the template
|
94
|
+
description: the description to display on the template
|
95
|
+
data: the data to populate the template with
|
96
|
+
|
97
|
+
Returns:
|
98
|
+
The rendered template as a string.
|
99
|
+
"""
|
73
100
|
report_data = {
|
74
101
|
"heading": heading,
|
75
102
|
"description": description,
|
@@ -82,14 +109,24 @@ class DsrReportBuilder:
|
|
82
109
|
return rendered_template
|
83
110
|
|
84
111
|
def _add_file(self, filename: str, contents: str) -> None:
|
85
|
-
"""
|
112
|
+
"""
|
113
|
+
Adds a file to the zip file.
|
114
|
+
|
115
|
+
Args:
|
116
|
+
filename: the name of the file to add
|
117
|
+
contents: the contents of the file to add
|
118
|
+
"""
|
86
119
|
if filename and contents:
|
87
120
|
self.out.writestr(f"{filename}", contents.encode("utf-8"))
|
88
121
|
|
89
|
-
def _add_dataset(self, dataset_name: str, collections:
|
122
|
+
def _add_dataset(self, dataset_name: str, collections: dict[str, Any]) -> None:
|
90
123
|
"""
|
91
124
|
Generates a page for each collection in the dataset and an index page for the dataset.
|
92
125
|
Tracks the generated links to build a root level index after each collection has been processed.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
dataset_name: the name of the dataset to add
|
129
|
+
collections: the collections to add to the dataset
|
93
130
|
"""
|
94
131
|
# track links to collection indexes
|
95
132
|
collection_links = {}
|
@@ -109,40 +146,203 @@ class DsrReportBuilder:
|
|
109
146
|
),
|
110
147
|
)
|
111
148
|
|
149
|
+
def _get_unique_filename(self, filename: str) -> str:
|
150
|
+
"""
|
151
|
+
Generates a unique filename by appending a counter if the file already exists.
|
152
|
+
Now tracks filenames across all directories to ensure global uniqueness.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
filename: The original filename
|
156
|
+
|
157
|
+
Returns:
|
158
|
+
A unique filename that won't conflict with existing files
|
159
|
+
"""
|
160
|
+
base_name, extension = os.path.splitext(filename)
|
161
|
+
counter = 1
|
162
|
+
unique_filename = filename
|
163
|
+
|
164
|
+
# Check if file exists in used_filenames set
|
165
|
+
while unique_filename in self.used_filenames:
|
166
|
+
unique_filename = f"{base_name}_{counter}{extension}"
|
167
|
+
counter += 1
|
168
|
+
|
169
|
+
# Add the new filename to the set
|
170
|
+
self.used_filenames.add(unique_filename)
|
171
|
+
return unique_filename
|
172
|
+
|
173
|
+
def _write_attachment_content(
|
174
|
+
self,
|
175
|
+
attachments: list[dict[str, Any]],
|
176
|
+
directory: str,
|
177
|
+
) -> dict[str, dict[str, str]]:
|
178
|
+
"""
|
179
|
+
Processes attachments and returns a dictionary mapping filenames to their download URLs and sizes.
|
180
|
+
|
181
|
+
Args:
|
182
|
+
attachments: The attachments to process
|
183
|
+
directory: The directory path (unused for presigned URLs)
|
184
|
+
|
185
|
+
Returns:
|
186
|
+
Dictionary mapping filenames to dictionaries containing url and size
|
187
|
+
"""
|
188
|
+
# First process all attachments into a list of tuples (filename, data)
|
189
|
+
processed_attachments = []
|
190
|
+
|
191
|
+
for attachment in attachments:
|
192
|
+
if not isinstance(attachment, dict):
|
193
|
+
continue
|
194
|
+
|
195
|
+
file_name = attachment.get("file_name")
|
196
|
+
if not file_name:
|
197
|
+
logger.warning("Skipping attachment with no file name")
|
198
|
+
continue
|
199
|
+
|
200
|
+
download_url = attachment.get("download_url")
|
201
|
+
if not download_url:
|
202
|
+
logger.warning("Skipping attachment with no download URL")
|
203
|
+
continue
|
204
|
+
|
205
|
+
file_size = attachment.get("file_size")
|
206
|
+
if isinstance(file_size, (int, float)):
|
207
|
+
file_size = self._format_size(float(file_size))
|
208
|
+
else:
|
209
|
+
file_size = "Unknown"
|
210
|
+
|
211
|
+
# Get a unique filename to prevent duplicates
|
212
|
+
unique_filename = self._get_unique_filename(file_name)
|
213
|
+
|
214
|
+
# Add to processed attachments
|
215
|
+
processed_attachments.append(
|
216
|
+
(unique_filename, {"url": download_url, "size": file_size})
|
217
|
+
)
|
218
|
+
|
219
|
+
# Convert list of tuples to dictionary
|
220
|
+
return dict(processed_attachments)
|
221
|
+
|
112
222
|
def _add_collection(
|
113
|
-
self, rows:
|
223
|
+
self, rows: list[dict[str, Any]], dataset_name: str, collection_name: str
|
114
224
|
) -> None:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
225
|
+
"""
|
226
|
+
Adds a collection to the zip file.
|
227
|
+
|
228
|
+
Args:
|
229
|
+
rows: the rows to add to the collection
|
230
|
+
dataset_name: the name of the dataset to add the collection to
|
231
|
+
collection_name: the name of the collection to add
|
232
|
+
"""
|
233
|
+
items_content = []
|
234
|
+
|
235
|
+
for index, collection_item in enumerate(rows, 1):
|
236
|
+
# Create a copy of the item data to avoid modifying the original
|
237
|
+
item_data = collection_item.copy()
|
238
|
+
|
239
|
+
# Process any attachments in the item
|
240
|
+
if "attachments" in item_data and isinstance(
|
241
|
+
item_data["attachments"], list
|
242
|
+
):
|
243
|
+
# Process attachments and get their URLs
|
244
|
+
attachment_links = self._write_attachment_content(
|
245
|
+
item_data["attachments"],
|
246
|
+
f"data/{dataset_name}/{collection_name}",
|
247
|
+
)
|
248
|
+
# Add the attachment URLs to the item data
|
249
|
+
item_data["attachments"] = attachment_links
|
250
|
+
|
251
|
+
# Add item content to the list
|
252
|
+
items_content.append(
|
253
|
+
{
|
254
|
+
"index": index,
|
255
|
+
"heading": f"{collection_name} (item #{index})",
|
256
|
+
"data": item_data,
|
257
|
+
}
|
127
258
|
)
|
128
|
-
detail_links[f"item #{index}"] = detail_url
|
129
259
|
|
130
|
-
#
|
260
|
+
# Generate the collection index page
|
131
261
|
self._add_file(
|
132
262
|
f"data/{dataset_name}/{collection_name}/index.html",
|
133
263
|
self._populate_template(
|
134
264
|
"templates/collection_index.html",
|
135
265
|
collection_name,
|
136
266
|
None,
|
137
|
-
|
267
|
+
{"collection_items": items_content},
|
268
|
+
),
|
269
|
+
)
|
270
|
+
|
271
|
+
def _add_attachments(self, attachments: list[dict[str, Any]]) -> None:
|
272
|
+
"""
|
273
|
+
Adds top-level attachments to the zip file.
|
274
|
+
|
275
|
+
Args:
|
276
|
+
attachments: the attachments to add
|
277
|
+
"""
|
278
|
+
if not attachments or not isinstance(attachments, list):
|
279
|
+
return
|
280
|
+
|
281
|
+
# Process attachments and get the links
|
282
|
+
attachment_links = self._write_attachment_content(attachments, "attachments")
|
283
|
+
|
284
|
+
# Generate attachments index page using the attachments index template
|
285
|
+
self._add_file(
|
286
|
+
"attachments/index.html",
|
287
|
+
self._populate_template(
|
288
|
+
"templates/attachments_index.html",
|
289
|
+
"Attachments",
|
290
|
+
"Files attached to this privacy request",
|
291
|
+
attachment_links,
|
138
292
|
),
|
139
293
|
)
|
140
294
|
|
295
|
+
def _get_datasets_from_dsr_data(self) -> dict[str, Any]:
|
296
|
+
"""
|
297
|
+
Returns the datasets from the DSR data.
|
298
|
+
"""
|
299
|
+
# pre-process data to split the dataset:collection keys
|
300
|
+
datasets: dict[str, Any] = defaultdict(lambda: defaultdict(list))
|
301
|
+
for key, rows in self.dsr_data.items():
|
302
|
+
|
303
|
+
# we handle attachments separately
|
304
|
+
if key == "attachments":
|
305
|
+
continue
|
306
|
+
|
307
|
+
parts = key.split(":", 1)
|
308
|
+
if len(parts) > 1:
|
309
|
+
dataset_name, collection_name = parts
|
310
|
+
else:
|
311
|
+
for row in rows:
|
312
|
+
if "system_name" in row:
|
313
|
+
dataset_name = row["system_name"]
|
314
|
+
collection_name = parts[0]
|
315
|
+
break
|
316
|
+
else:
|
317
|
+
dataset_name = "manual"
|
318
|
+
collection_name = parts[0]
|
319
|
+
|
320
|
+
datasets[dataset_name][collection_name].extend(rows)
|
321
|
+
|
322
|
+
return datasets
|
323
|
+
|
324
|
+
def _format_size(self, size_bytes: float) -> str:
|
325
|
+
"""
|
326
|
+
Format size in bytes to human readable format.
|
327
|
+
|
328
|
+
Args:
|
329
|
+
size_bytes: Size in bytes
|
330
|
+
|
331
|
+
Returns:
|
332
|
+
Formatted string with appropriate unit (B, KB, MB, GB)
|
333
|
+
"""
|
334
|
+
for unit in ["B", "KB", "MB", "GB"]:
|
335
|
+
if size_bytes < 1024.0:
|
336
|
+
return f"{size_bytes:.1f} {unit}"
|
337
|
+
size_bytes /= 1024.0
|
338
|
+
return f"{size_bytes:.1f} TB"
|
339
|
+
|
141
340
|
def generate(self) -> BytesIO:
|
142
341
|
"""
|
143
342
|
Processes the request and DSR data to build zip file containing the DSR report.
|
144
343
|
Returns the zip file as an in-memory byte array.
|
145
344
|
"""
|
345
|
+
start_time = time_module.time()
|
146
346
|
try:
|
147
347
|
# all the css for the pages is in main.css
|
148
348
|
self._add_file(
|
@@ -157,18 +357,28 @@ class DsrReportBuilder:
|
|
157
357
|
)
|
158
358
|
|
159
359
|
# pre-process data to split the dataset:collection keys
|
160
|
-
datasets:
|
161
|
-
for key, rows in self.dsr_data.items():
|
162
|
-
parts = key.split(":", 1)
|
163
|
-
dataset_name, collection_name = (
|
164
|
-
parts if len(parts) > 1 else ("manual", parts[0])
|
165
|
-
)
|
166
|
-
datasets[dataset_name][collection_name].extend(rows)
|
360
|
+
datasets: dict[str, Any] = self._get_datasets_from_dsr_data()
|
167
361
|
|
168
|
-
|
169
|
-
|
362
|
+
# Sort datasets alphabetically, excluding special cases
|
363
|
+
regular_datasets = [
|
364
|
+
name for name in sorted(datasets.keys()) if name != "dataset"
|
365
|
+
] # pylint: disable=invalid-name
|
366
|
+
|
367
|
+
# Add regular datasets in alphabetical order
|
368
|
+
for dataset_name in regular_datasets:
|
369
|
+
self._add_dataset(dataset_name, datasets[dataset_name])
|
170
370
|
self.main_links[dataset_name] = f"data/{dataset_name}/index.html"
|
171
371
|
|
372
|
+
# Add Additional Data if it exists
|
373
|
+
if "dataset" in datasets:
|
374
|
+
self._add_dataset("dataset", datasets["dataset"])
|
375
|
+
self.main_links["Additional Data"] = "data/dataset/index.html"
|
376
|
+
|
377
|
+
# Add Additional Attachments last if it exists
|
378
|
+
if "attachments" in self.dsr_data:
|
379
|
+
self._add_attachments(self.dsr_data["attachments"])
|
380
|
+
self.main_links["Additional Attachments"] = "attachments/index.html"
|
381
|
+
|
172
382
|
# create the main index once all the datasets have been added
|
173
383
|
self._add_file(
|
174
384
|
"welcome.html",
|
@@ -182,12 +392,20 @@ class DsrReportBuilder:
|
|
182
392
|
|
183
393
|
# reset the file pointer so the file can be fully read by the caller
|
184
394
|
self.baos.seek(0)
|
395
|
+
|
396
|
+
# Calculate time taken and file size
|
397
|
+
time_taken = time_module.time() - start_time
|
398
|
+
file_size = self._format_size(float(len(self.baos.getvalue())))
|
399
|
+
|
400
|
+
logger.bind(time_to_generate=time_taken, dsr_package_size=file_size).info(
|
401
|
+
"DSR report generation complete."
|
402
|
+
)
|
185
403
|
return self.baos
|
186
404
|
|
187
405
|
|
188
|
-
def _map_privacy_request(privacy_request: PrivacyRequest) ->
|
406
|
+
def _map_privacy_request(privacy_request: PrivacyRequest) -> dict[str, Any]:
|
189
407
|
"""Creates a map with a subset of values from the privacy request"""
|
190
|
-
request_data:
|
408
|
+
request_data: dict[str, Any] = {}
|
191
409
|
request_data["id"] = privacy_request.id
|
192
410
|
|
193
411
|
action_type: Optional[ActionType] = privacy_request.policy.get_action_type()
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600">
|
4
|
+
<link rel="stylesheet" href="../data/main.css">
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<div class="container">
|
8
|
+
<div class="header"></div>
|
9
|
+
<div class="content">
|
10
|
+
<div class="button-container">
|
11
|
+
<a href="../welcome.html">
|
12
|
+
<div class="button"><img src="../data/back.svg"></div>
|
13
|
+
<span>Back to main page</span>
|
14
|
+
</a>
|
15
|
+
</div>
|
16
|
+
<h1>Attachments</h1>
|
17
|
+
<p class="expiration-notice">Note: All download links will expire in 7 days.</p>
|
18
|
+
<div class="table table-hover">
|
19
|
+
<div class="table-row">
|
20
|
+
<div class="table-cell" style="text-align: left;">File Name</div>
|
21
|
+
<div class="table-cell" style="text-align: left;">Size</div>
|
22
|
+
</div>
|
23
|
+
{% for name, info in data.items() %}
|
24
|
+
<a href="{{ info.url }}" class="table-row" target="_blank">
|
25
|
+
<div class="table-cell" style="text-align: left;">{{ name }}</div>
|
26
|
+
<div class="table-cell" style="text-align: left;">{{ info.size }}</div>
|
27
|
+
</a>
|
28
|
+
{% endfor %}
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</body>
|
33
|
+
</html>
|
@@ -14,17 +14,42 @@
|
|
14
14
|
</a>
|
15
15
|
</div>
|
16
16
|
<h1>{{ heading }}</h1>
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
{% for item in data.collection_items %}
|
18
|
+
<div class="item-section">
|
19
|
+
<h2>{{ item.heading }}</h2>
|
20
|
+
<div class="table">
|
21
|
+
<div class="table-row">
|
22
|
+
<div class="table-cell">Field</div>
|
23
|
+
<div class="table-cell">Value</div>
|
24
|
+
</div>
|
25
|
+
{% for field, value in item.data.items() %}
|
26
|
+
<div class="table-row">
|
27
|
+
<div class="table-cell">{{ field }}</div>
|
28
|
+
<div class="table-cell">
|
29
|
+
{% if field == "attachments" and value is mapping and value|length > 0 %}
|
30
|
+
<p class="expiration-notice">Note: All download links will expire in 7 days.</p>
|
31
|
+
<div class="table table-hover">
|
32
|
+
<div class="table-row">
|
33
|
+
<div class="table-cell" style="text-align: left;">File Name</div>
|
34
|
+
<div class="table-cell" style="text-align: left;">Size</div>
|
35
|
+
</div>
|
36
|
+
{% for attachment_name, attachment_info in value.items() %}
|
37
|
+
<a href="{{ attachment_info.url }}" class="table-row" target="_blank">
|
38
|
+
<div class="table-cell" style="text-align: left;">{{ attachment_name }}</div>
|
39
|
+
<div class="table-cell" style="text-align: left;">{{ attachment_info.size }}</div>
|
40
|
+
</a>
|
41
|
+
{% endfor %}
|
42
|
+
</div>
|
43
|
+
{% else %}
|
44
|
+
<pre>{{ value | pretty_print }}</pre>
|
45
|
+
{% endif %}
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
{% endfor %}
|
20
49
|
</div>
|
21
|
-
{% for name, link in data.items() %}
|
22
|
-
<a href="{{ link }}" class="table-row">
|
23
|
-
<div class="table-cell">{{ name }}</div>
|
24
|
-
</a>
|
25
|
-
{% endfor %}
|
26
50
|
</div>
|
51
|
+
{% endfor %}
|
27
52
|
</div>
|
28
53
|
</div>
|
29
54
|
</body>
|
30
|
-
</html>
|
55
|
+
</html>
|
@@ -35,7 +35,7 @@ h1 {
|
|
35
35
|
margin-bottom: 24px;
|
36
36
|
width: 100%;
|
37
37
|
display: flex;
|
38
|
-
justify-content: center;
|
38
|
+
justify-content: center;
|
39
39
|
}
|
40
40
|
|
41
41
|
.header div {
|
@@ -176,4 +176,47 @@ h1 {
|
|
176
176
|
|
177
177
|
a {
|
178
178
|
text-decoration: none;
|
179
|
-
}
|
179
|
+
}
|
180
|
+
|
181
|
+
.attachment-link {
|
182
|
+
color: var(--text-color);
|
183
|
+
text-decoration: underline;
|
184
|
+
cursor: pointer;
|
185
|
+
}
|
186
|
+
|
187
|
+
.attachment-link:hover {
|
188
|
+
opacity: 0.8;
|
189
|
+
}
|
190
|
+
|
191
|
+
.dataset-list {
|
192
|
+
padding: 20px 0 100px;
|
193
|
+
}
|
194
|
+
|
195
|
+
.dataset-list h2 {
|
196
|
+
font-size: 16px;
|
197
|
+
font-weight: 600;
|
198
|
+
margin-bottom: 16px;
|
199
|
+
}
|
200
|
+
|
201
|
+
.dataset-item {
|
202
|
+
margin-bottom: 8px;
|
203
|
+
}
|
204
|
+
|
205
|
+
.dataset-link {
|
206
|
+
display: block;
|
207
|
+
color: var(--text-color);
|
208
|
+
text-decoration: none;
|
209
|
+
font-size: 14px;
|
210
|
+
line-height: 20px;
|
211
|
+
font-weight: 600;
|
212
|
+
background-color: var(--header-color);
|
213
|
+
padding: 16px;
|
214
|
+
border: 1px solid var(--border-color);
|
215
|
+
border-radius: 6px;
|
216
|
+
transition: opacity 0.2s ease;
|
217
|
+
}
|
218
|
+
|
219
|
+
.dataset-link:hover {
|
220
|
+
opacity: 0.8;
|
221
|
+
cursor: pointer;
|
222
|
+
}
|
@@ -45,18 +45,22 @@
|
|
45
45
|
<div id="requestedAt">{{ request.requested_at }}</div>
|
46
46
|
</div>
|
47
47
|
</div>
|
48
|
-
<div class="
|
49
|
-
<
|
50
|
-
|
51
|
-
|
48
|
+
<div class="dsr-information-text">
|
49
|
+
<p>
|
50
|
+
This web link contains all data requested as part of your Data Subject Request (DSR). Your
|
51
|
+
information has been compiled from the following areas. Click on each section to open a file and view
|
52
|
+
your data in PDF format.
|
53
|
+
</p>
|
54
|
+
</div>
|
55
|
+
<div class="dataset-list">
|
52
56
|
{% for name, link in data.items() %}
|
53
|
-
<
|
54
|
-
<
|
55
|
-
</
|
57
|
+
<div class="dataset-item">
|
58
|
+
<a href="{{ link }}" class="dataset-link">{{ name }}</a>
|
59
|
+
</div>
|
56
60
|
{% endfor %}
|
57
61
|
</div>
|
58
62
|
</div>
|
59
63
|
</div>
|
60
64
|
</body>
|
61
65
|
|
62
|
-
</html>
|
66
|
+
</html>
|