ethyca-fides 2.58.2b5__py2.py3-none-any.whl → 2.58.2rc0__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.58.2b5.dist-info → ethyca_fides-2.58.2rc0.dist-info}/METADATA +11 -20
- {ethyca_fides-2.58.2b5.dist-info → ethyca_fides-2.58.2rc0.dist-info}/RECORD +178 -188
- {ethyca_fides-2.58.2b5.dist-info → ethyca_fides-2.58.2rc0.dist-info}/WHEEL +1 -1
- {ethyca_fides-2.58.2b5.dist-info → ethyca_fides-2.58.2rc0.dist-info}/entry_points.txt +1 -0
- fides/_version.py +3 -3
- fides/api/api/deps.py +2 -8
- fides/api/api/v1/endpoints/user_endpoints.py +12 -8
- fides/api/cryptography/identity_salt.py +13 -12
- fides/api/custom_types.py +1 -6
- fides/api/db/base.py +0 -5
- fides/api/db/system.py +3 -1
- fides/api/migrations/hash_migration_job.py +2 -2
- fides/api/models/attachment.py +11 -80
- fides/api/models/comment.py +15 -45
- fides/api/models/detection_discovery.py +0 -31
- fides/api/models/fides_user.py +9 -26
- fides/api/models/fides_user_invite.py +0 -2
- fides/api/models/privacy_experience.py +0 -68
- fides/api/models/privacy_request/privacy_request.py +6 -23
- fides/api/schemas/connection_configuration/connection_config.py +16 -30
- fides/api/schemas/user.py +1 -5
- fides/api/service/deps.py +0 -9
- fides/api/service/storage/s3.py +1 -14
- fides/api/service/user/fides_user_service.py +128 -0
- fides/api/task/graph_task.py +1 -1
- fides/api/util/collection_util.py +9 -48
- fides/cli/commands/pull.py +13 -77
- fides/core/api.py +1 -2
- fides/core/pull.py +7 -38
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1150-035a721a04f4451e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1376-5cea5ef9362215e8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{2397-0d1c289b788fcc11.js → 2397-ee53235fb21b5e97.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3412-7ec8751b8182e1bf.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3855-63495367531cb776.js → 3855-b6b7865dedd7bc2a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{3872-472bb47eb34d8fdb.js → 3872-4e053c20d546f027.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{4060-53a5c6347690a8fa.js → 4060-8d165e1236ea521a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/4450-36234280bee624ff.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4481-aab99ff80f707473.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5258-cf7b27ef51f38392.js → 5258-0658dc2274df6832.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5480-52dc446be40725f5.js → 5480-f49696df5e8ae500.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5487-8678d75ee1d1ef09.js → 5487-3ad50d21cdbc9209.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/5973-52aee296edc44f7e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6315-fa1519cdf080f42d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{6372-e0bb9f8d07cc3b04.js → 6372-ca9c12ac8902365b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6853-09e831e9dff7fd3b.js → 6853-8941824350c3c1a8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6954-ec5276bb464d42b2.js → 6954-3b887fb444f9228c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7453-39761c38da31257e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7751-a70fe0e5f67f5538.js → 7751-a8f31c062d4cb09d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{79-8e060d36d36c752c.js → 79-f9b948ebb186900f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{7980-72f745bff9fabcc9.js → 7980-4bd08957448dea32.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{9046-a69fa8f99c414570.js → 9046-04bd7becea207cb1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9767-1a23925d2cb27b51.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{main-090643377c8254e6.js → main-24f422f93845a596.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{main-app-59156a9331ac7bce.js → main-app-94a0711202e08b15.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-0c1548ca3b158123.js → _app-fc89ce7bed454c84.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-9f9500c639362aa6.js → manual-9acaab973dfe86e2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-fac606150b65d494.js → add-systems-d258f0c25fa020bf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-fb75fa0aea77678d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-c02b14c50b19bd91.js → new-a9d9402c219d13e5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-c946b33b0322b8ad.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-ea57f9d6ad17e957.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-100234c23a85d235.js → reporting-788cf0e34829af46.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-49bffaf07973fead.js → data-catalog-900004e402c31797.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/{[systemId]-727f1f5d06be674b.js → [systemId]-b66831fdafcdf67c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-5f9ef1f99818117c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-d001337d1bb73bd1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-11b3ce9f61d9bfe9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-4d4a31d0186a4a5b.js → new-803c1b577ab17ae3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-29317d18ce34adfe.js → dataset-fa743ddc7f89d76b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-14c57e5069e9cccd.js → [id]-bbe1ca2793798e6b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-f0a4e385c1ad8fee.js → new-abc17fef69cd951b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-a78a73b65929853a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-b70def65e264270e.js → index-bfaacdb55a5a6c9f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-d4329043219fed9b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-1e60754abec1ee6b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-72d64a02b7ef175e.js → [id]-fe765154315782cf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-f5f7a8069909ef24.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-9f7eaad05e5b9292.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{privacy-requests-fd81714d811db7b3.js → privacy-requests-d85c0d16ba09ba35.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-f035cddf17f4d898.js → datamap-afedc48ef4e7f858.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-89524101b7279f6e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-dfcd7a4b6aa773bd.js → custom-fields-52d030b1db2ca1b9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-24cba38685dc872c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-0e0aa552f520f913.js → organization-a08693d0d1e10bc8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-1d83d5178b3eb216.js → test-datasets-151571cff4e85894.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-a158fa77df288523.js → [id]-4f5a28226575c976.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{systems-8490aaaee9d76a4a.js → systems-abd68fc5ddde5482.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-be1ffe267b1602e1.js → taxonomy-16b4d75c49276add.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-082c3156175f9267.js → new-be690621a944bfe2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-78eaf933f755bfe8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-a1db56f1cbfba373.js → user-management-6c9ad62479a7d03e.js} +1 -1
- fides/ui-build/static/admin/_next/static/css/{cf2744a40308fc4a.css → 113d823fe71f6af0.css} +1 -1
- fides/ui-build/static/admin/_next/static/o0mKeH0cB6eAYV6qOlVD0/_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/ant-poc.html +1 -1
- fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
- fides/ui-build/static/admin/consent/configure.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
- fides/ui-build/static/admin/consent/properties.html +1 -1
- fides/ui-build/static/admin/consent/reporting.html +1 -1
- fides/ui-build/static/admin/consent.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
- fides/ui-build/static/admin/data-catalog.html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
- fides/ui-build/static/admin/data-discovery/activity.html +1 -1
- fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/detection.html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
- fides/ui-build/static/admin/datamap.html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
- fides/ui-build/static/admin/dataset/new.html +1 -1
- fides/ui-build/static/admin/dataset.html +1 -1
- fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
- fides/ui-build/static/admin/datastore-connection/new.html +1 -1
- fides/ui-build/static/admin/datastore-connection.html +1 -1
- fides/ui-build/static/admin/index.html +1 -1
- fides/ui-build/static/admin/integrations/[id].html +1 -1
- fides/ui-build/static/admin/integrations.html +1 -1
- fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
- fides/ui-build/static/admin/lib/fides-headless.js +1 -1
- fides/ui-build/static/admin/lib/fides-tcf.js +4 -4
- fides/ui-build/static/admin/lib/fides.js +3 -3
- 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/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.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/alembic/migrations/versions/67d01c4e124e_add_reject_all_mechanism_to_privacy_.py +0 -56
- fides/api/alembic/migrations/versions/6e565c16dae1_add_tcf_publisher_restrictions.py +0 -107
- fides/api/alembic/migrations/versions/9288f729cac4_add_tcf_configuration_fk_to_experience_.py +0 -62
- fides/api/alembic/migrations/versions/99c603c1b8f9_add_password_login_enabled_and_totp_secret_to_fidesuser.py +0 -45
- fides/api/models/tcf_publisher_restrictions.py +0 -465
- fides/service/error_handling/__init__.py +0 -0
- fides/service/error_handling/error_handler.py +0 -202
- fides/service/user/__init__.py +0 -0
- fides/service/user/user_service.py +0 -140
- fides/ui-build/static/admin/_next/static/_o6WH0hDzNEhnUJyvLex7/_buildManifest.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1376-87058e04584cff20.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/146-0ae2d30ec71fce09.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-48e1c9d3504e18f0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3938-6a1c07d06a80cf4c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4121-4d5273d7a354994d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4450-9c3086ccb55c66aa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4481-275aa9f4c10bce53.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5973-d3d3872692c1d0fa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6315-24a0483ee1cab6cc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9767-8179ce7336727141.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-ab3ef485f6101697.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-ba5325035c71a97e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-ef31c181cac86c64.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-53efbed54d230f07.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-17d1525551d8904f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-7d2cb947eee11262.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-d2f88a8fc68944db.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-b75ab4ee677f118d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-26407674949bcbc4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-28d4bdf060ec8cb2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-208e49ef43361d6f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-ff1985f72d50ef47.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-5a0b10ec955097d4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-af83245e9373a064.js +0 -1
- fides/ui-build/static/admin/images/connector-logos/website.svg +0 -10
- {ethyca_fides-2.58.2b5.dist-info/licenses → ethyca_fides-2.58.2rc0.dist-info}/LICENSE +0 -0
- {ethyca_fides-2.58.2b5.dist-info → ethyca_fides-2.58.2rc0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{4723-1dd1d16f404d56a2.js → 4723-0a3c5e2ce143a7d0.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{5826-ef0aa43ffad83acc.js → 5826-e5dcb4e68cfe6289.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-a4e636eecaba5324.js → configure-723cc3d4f5740ea6.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-606457ef5bd1eb04.js → [id]-72251b48e2e03a1e.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-2ae030f3a28f057a.js → about-a49d0f84cf0cf05e.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-72ec54ee8755a503.js → domain-records-fa42d8f18df44927.js} +0 -0
- /fides/ui-build/static/admin/_next/static/{_o6WH0hDzNEhnUJyvLex7 → o0mKeH0cB6eAYV6qOlVD0}/_ssgManifest.js +0 -0
@@ -1,107 +0,0 @@
|
|
1
|
-
"""Add TCF Publisher Restrictions
|
2
|
-
|
3
|
-
Revision ID: 6e565c16dae1
|
4
|
-
Revises: 67d01c4e124e
|
5
|
-
Create Date: 2025-04-02 12:35:34.105607
|
6
|
-
|
7
|
-
"""
|
8
|
-
|
9
|
-
import sqlalchemy as sa
|
10
|
-
from alembic import op
|
11
|
-
from sqlalchemy.dialects import postgresql
|
12
|
-
|
13
|
-
# revision identifiers, used by Alembic.
|
14
|
-
revision = "6e565c16dae1"
|
15
|
-
down_revision = "67d01c4e124e"
|
16
|
-
branch_labels = None
|
17
|
-
depends_on = None
|
18
|
-
|
19
|
-
|
20
|
-
def upgrade():
|
21
|
-
# Create tcf_configuration table
|
22
|
-
op.create_table(
|
23
|
-
"tcf_configuration",
|
24
|
-
sa.Column("id", sa.String(length=255), nullable=False),
|
25
|
-
sa.Column(
|
26
|
-
"created_at",
|
27
|
-
sa.DateTime(timezone=True),
|
28
|
-
server_default=sa.text("now()"),
|
29
|
-
nullable=True,
|
30
|
-
),
|
31
|
-
sa.Column(
|
32
|
-
"updated_at",
|
33
|
-
sa.DateTime(timezone=True),
|
34
|
-
server_default=sa.text("now()"),
|
35
|
-
nullable=True,
|
36
|
-
),
|
37
|
-
sa.Column("name", sa.String(), nullable=False),
|
38
|
-
sa.PrimaryKeyConstraint("id"),
|
39
|
-
sa.UniqueConstraint("name"),
|
40
|
-
)
|
41
|
-
# Create tcf_publisher_restriction table
|
42
|
-
op.create_table(
|
43
|
-
"tcf_publisher_restriction",
|
44
|
-
sa.Column("id", sa.String(length=255), nullable=False),
|
45
|
-
sa.Column(
|
46
|
-
"created_at",
|
47
|
-
sa.DateTime(timezone=True),
|
48
|
-
server_default=sa.text("now()"),
|
49
|
-
nullable=True,
|
50
|
-
),
|
51
|
-
sa.Column(
|
52
|
-
"updated_at",
|
53
|
-
sa.DateTime(timezone=True),
|
54
|
-
server_default=sa.text("now()"),
|
55
|
-
nullable=True,
|
56
|
-
),
|
57
|
-
sa.Column("tcf_configuration_id", sa.String(255), nullable=False),
|
58
|
-
sa.Column("purpose_id", sa.Integer(), nullable=False),
|
59
|
-
sa.Column(
|
60
|
-
"restriction_type",
|
61
|
-
sa.Enum(
|
62
|
-
"purpose_restriction",
|
63
|
-
"require_consent",
|
64
|
-
"require_legitimate_interest",
|
65
|
-
name="tcfrestrictiontype",
|
66
|
-
),
|
67
|
-
nullable=False,
|
68
|
-
),
|
69
|
-
sa.Column(
|
70
|
-
"vendor_restriction",
|
71
|
-
sa.Enum(
|
72
|
-
"restrict_all_vendors",
|
73
|
-
"allow_specific_vendors",
|
74
|
-
"restrict_specific_vendors",
|
75
|
-
name="tcfvendorrestriction",
|
76
|
-
),
|
77
|
-
nullable=False,
|
78
|
-
),
|
79
|
-
sa.Column(
|
80
|
-
"range_entries",
|
81
|
-
postgresql.ARRAY(postgresql.JSONB(astext_type=sa.Text())),
|
82
|
-
server_default="{}",
|
83
|
-
nullable=False,
|
84
|
-
),
|
85
|
-
sa.ForeignKeyConstraint(
|
86
|
-
["tcf_configuration_id"],
|
87
|
-
["tcf_configuration.id"],
|
88
|
-
ondelete="CASCADE",
|
89
|
-
),
|
90
|
-
sa.PrimaryKeyConstraint("id"),
|
91
|
-
)
|
92
|
-
op.create_index(
|
93
|
-
op.f("ix_tcf_publisher_restriction_config_purpose"),
|
94
|
-
"tcf_publisher_restriction",
|
95
|
-
["tcf_configuration_id", "purpose_id"],
|
96
|
-
unique=False,
|
97
|
-
)
|
98
|
-
|
99
|
-
|
100
|
-
def downgrade():
|
101
|
-
# Drop tables
|
102
|
-
op.drop_table("tcf_publisher_restriction")
|
103
|
-
op.drop_table("tcf_configuration")
|
104
|
-
|
105
|
-
# Drop enums
|
106
|
-
op.execute("DROP TYPE tcfrestrictiontype")
|
107
|
-
op.execute("DROP TYPE tcfvendorrestriction")
|
fides/api/alembic/migrations/versions/9288f729cac4_add_tcf_configuration_fk_to_experience_.py
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
"""Add tcf_configuration FK to experience config
|
2
|
-
|
3
|
-
Revision ID: 9288f729cac4
|
4
|
-
Revises: 99c603c1b8f9
|
5
|
-
Create Date: 2025-04-07 18:49:31.843362
|
6
|
-
|
7
|
-
"""
|
8
|
-
|
9
|
-
import sqlalchemy as sa
|
10
|
-
from alembic import op
|
11
|
-
|
12
|
-
# revision identifiers, used by Alembic.
|
13
|
-
revision = "9288f729cac4"
|
14
|
-
down_revision = "99c603c1b8f9"
|
15
|
-
branch_labels = None
|
16
|
-
depends_on = None
|
17
|
-
|
18
|
-
|
19
|
-
def upgrade():
|
20
|
-
# ### commands auto generated by Alembic - please adjust! ###
|
21
|
-
op.add_column(
|
22
|
-
"privacyexperienceconfig",
|
23
|
-
sa.Column("tcf_configuration_id", sa.String(), nullable=True),
|
24
|
-
)
|
25
|
-
op.create_foreign_key(
|
26
|
-
"privacyexperienceconfig_tcf_configuration_fkey",
|
27
|
-
"privacyexperienceconfig",
|
28
|
-
"tcf_configuration",
|
29
|
-
["tcf_configuration_id"],
|
30
|
-
["id"],
|
31
|
-
ondelete="SET NULL",
|
32
|
-
)
|
33
|
-
op.add_column(
|
34
|
-
"privacyexperienceconfighistory",
|
35
|
-
sa.Column("tcf_configuration_id", sa.String(), nullable=True),
|
36
|
-
)
|
37
|
-
op.create_foreign_key(
|
38
|
-
"privacyexperienceconfighistory_tcf_configuration_fkey",
|
39
|
-
"privacyexperienceconfighistory",
|
40
|
-
"tcf_configuration",
|
41
|
-
["tcf_configuration_id"],
|
42
|
-
["id"],
|
43
|
-
ondelete="SET NULL",
|
44
|
-
)
|
45
|
-
# ### end Alembic commands ###
|
46
|
-
|
47
|
-
|
48
|
-
def downgrade():
|
49
|
-
# ### commands auto generated by Alembic - please adjust! ###
|
50
|
-
op.drop_constraint(
|
51
|
-
"privacyexperienceconfighistory_tcf_configuration_fkey",
|
52
|
-
"privacyexperienceconfighistory",
|
53
|
-
type_="foreignkey",
|
54
|
-
)
|
55
|
-
op.drop_column("privacyexperienceconfighistory", "tcf_configuration_id")
|
56
|
-
op.drop_constraint(
|
57
|
-
"privacyexperienceconfig_tcf_configuration_fkey",
|
58
|
-
"privacyexperienceconfig",
|
59
|
-
type_="foreignkey",
|
60
|
-
)
|
61
|
-
op.drop_column("privacyexperienceconfig", "tcf_configuration_id")
|
62
|
-
# ### end Alembic commands ###
|
@@ -1,45 +0,0 @@
|
|
1
|
-
"""add password login enabled and totp secret to fidesuser
|
2
|
-
|
3
|
-
Revision ID: 99c603c1b8f9
|
4
|
-
Revises: 6e565c16dae1
|
5
|
-
Create Date: 2025-04-02 01:55:57.890545
|
6
|
-
|
7
|
-
"""
|
8
|
-
|
9
|
-
import sqlalchemy as sa
|
10
|
-
import sqlalchemy_utils
|
11
|
-
from alembic import op
|
12
|
-
|
13
|
-
# revision identifiers, used by Alembic.
|
14
|
-
revision = "99c603c1b8f9"
|
15
|
-
down_revision = "6e565c16dae1"
|
16
|
-
branch_labels = None
|
17
|
-
depends_on = None
|
18
|
-
|
19
|
-
|
20
|
-
def upgrade():
|
21
|
-
op.add_column(
|
22
|
-
"fidesuser",
|
23
|
-
sa.Column(
|
24
|
-
"password_login_enabled",
|
25
|
-
sa.Boolean(),
|
26
|
-
nullable=True,
|
27
|
-
),
|
28
|
-
)
|
29
|
-
op.add_column(
|
30
|
-
"fidesuser",
|
31
|
-
sa.Column(
|
32
|
-
"totp_secret",
|
33
|
-
sqlalchemy_utils.types.encrypted.encrypted_type.StringEncryptedType(),
|
34
|
-
nullable=True,
|
35
|
-
),
|
36
|
-
)
|
37
|
-
op.alter_column("fidesuser", "hashed_password", nullable=True)
|
38
|
-
op.alter_column("fidesuser", "salt", nullable=True)
|
39
|
-
|
40
|
-
|
41
|
-
def downgrade():
|
42
|
-
op.alter_column("fidesuser", "hashed_password", nullable=False)
|
43
|
-
op.alter_column("fidesuser", "salt", nullable=False)
|
44
|
-
op.drop_column("fidesuser", "totp_secret")
|
45
|
-
op.drop_column("fidesuser", "password_login_enabled")
|
@@ -1,465 +0,0 @@
|
|
1
|
-
from enum import Enum
|
2
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
3
|
-
|
4
|
-
from pydantic import BaseModel, Field, ValidationError, model_validator
|
5
|
-
from sqlalchemy import Column
|
6
|
-
from sqlalchemy import Enum as EnumColumn
|
7
|
-
from sqlalchemy import ForeignKey, Index, Integer, String, insert, select, update
|
8
|
-
from sqlalchemy.dialects.postgresql import ARRAY, JSONB
|
9
|
-
from sqlalchemy.ext.asyncio import AsyncSession
|
10
|
-
from sqlalchemy.ext.declarative import declared_attr
|
11
|
-
from sqlalchemy.orm import Session, relationship
|
12
|
-
|
13
|
-
from fides.api.db.base_class import Base
|
14
|
-
|
15
|
-
if TYPE_CHECKING:
|
16
|
-
from fides.api.models.privacy_experience import PrivacyExperienceConfig
|
17
|
-
|
18
|
-
|
19
|
-
class TCFRestrictionType(str, Enum):
|
20
|
-
"""Enum for TCF restriction types"""
|
21
|
-
|
22
|
-
purpose_restriction = "purpose_restriction"
|
23
|
-
require_consent = "require_consent"
|
24
|
-
require_legitimate_interest = "require_legitimate_interest"
|
25
|
-
|
26
|
-
|
27
|
-
class TCFVendorRestriction(str, Enum):
|
28
|
-
"""Enum for TCF vendor restriction types"""
|
29
|
-
|
30
|
-
restrict_all_vendors = "restrict_all_vendors"
|
31
|
-
allow_specific_vendors = "allow_specific_vendors"
|
32
|
-
restrict_specific_vendors = "restrict_specific_vendors"
|
33
|
-
|
34
|
-
|
35
|
-
# This is Pydantic model used for validation, not a database model!
|
36
|
-
class RangeEntry(BaseModel):
|
37
|
-
"""
|
38
|
-
Pydantic model that represents a vendor range entry as per the TCF spec,
|
39
|
-
used for Publisher Restrictions.
|
40
|
-
A range entry must have a start_vendor_id and optionally an end_vendor_id.
|
41
|
-
If end_vendor_id is present, it must be greater than start_vendor_id.
|
42
|
-
"""
|
43
|
-
|
44
|
-
start_vendor_id: int = Field(description="The starting vendor ID in the range")
|
45
|
-
end_vendor_id: Optional[int] = Field(
|
46
|
-
default=None, description="The ending vendor ID in the range (inclusive)"
|
47
|
-
)
|
48
|
-
|
49
|
-
@model_validator(mode="after")
|
50
|
-
def validate_vendor_range(self) -> "RangeEntry":
|
51
|
-
"""Validates that end_vendor_id is greater than start_vendor_id if present."""
|
52
|
-
if self.end_vendor_id is not None and self.end_vendor_id < self.start_vendor_id:
|
53
|
-
raise ValueError(
|
54
|
-
"end_vendor_id must be greater than or equal to start_vendor_id"
|
55
|
-
)
|
56
|
-
return self
|
57
|
-
|
58
|
-
@property
|
59
|
-
def effective_end_vendor_id(self) -> int:
|
60
|
-
"""Get the effective end of the range."""
|
61
|
-
return self.end_vendor_id or self.start_vendor_id
|
62
|
-
|
63
|
-
def overlaps_with(self, other: "RangeEntry") -> bool:
|
64
|
-
"""
|
65
|
-
Check if this range overlaps with another range.
|
66
|
-
Two ranges overlap if the end of the range that starts first is greater than
|
67
|
-
or equal to the start of the range that starts second.
|
68
|
-
"""
|
69
|
-
# Sort ranges by start_vendor_id
|
70
|
-
first = self if self.start_vendor_id <= other.start_vendor_id else other
|
71
|
-
second = other if self.start_vendor_id <= other.start_vendor_id else self
|
72
|
-
|
73
|
-
# If first range's end is >= second range's start, they overlap
|
74
|
-
return first.effective_end_vendor_id >= second.start_vendor_id
|
75
|
-
|
76
|
-
|
77
|
-
class TCFConfiguration(Base):
|
78
|
-
"""
|
79
|
-
Stores TCF Configuration settings.
|
80
|
-
"""
|
81
|
-
|
82
|
-
@declared_attr
|
83
|
-
def __tablename__(self) -> str:
|
84
|
-
return "tcf_configuration"
|
85
|
-
|
86
|
-
name = Column(String, nullable=False, index=True, unique=True)
|
87
|
-
|
88
|
-
privacy_experience_configs = relationship(
|
89
|
-
"PrivacyExperienceConfig",
|
90
|
-
back_populates="tcf_configuration",
|
91
|
-
lazy="selectin",
|
92
|
-
)
|
93
|
-
|
94
|
-
|
95
|
-
class TCFPublisherRestriction(Base):
|
96
|
-
"""
|
97
|
-
Stores TCF Publisher Restrictions. TCF Publisher Restrictions belong to a TCF Configuration,
|
98
|
-
and specify the restriction type and vendor restriction for a given purpose.
|
99
|
-
"""
|
100
|
-
|
101
|
-
@declared_attr
|
102
|
-
def __tablename__(self) -> str:
|
103
|
-
return "tcf_publisher_restriction"
|
104
|
-
|
105
|
-
tcf_configuration_id = Column(
|
106
|
-
String(255),
|
107
|
-
ForeignKey("tcf_configuration.id", ondelete="CASCADE"),
|
108
|
-
nullable=False,
|
109
|
-
index=True,
|
110
|
-
)
|
111
|
-
purpose_id = Column(Integer, nullable=False)
|
112
|
-
restriction_type = Column(EnumColumn(TCFRestrictionType), nullable=False)
|
113
|
-
vendor_restriction = Column(EnumColumn(TCFVendorRestriction), nullable=False)
|
114
|
-
|
115
|
-
# range_entries represents a list of RangeEntry objects as per the TCF spec.
|
116
|
-
# A RangeEntry object will have a start_vendor_id and an end_vendor_id (the
|
117
|
-
# end vendor id is included in the range).
|
118
|
-
# If the range represents a single vendor, then the end_vendor_id can be omitted.
|
119
|
-
# TCF spec also includes an IsARange boolean, which we are omitting because it
|
120
|
-
# can be inferred from the presence of the end_vendor_id.
|
121
|
-
range_entries = Column(
|
122
|
-
ARRAY(JSONB),
|
123
|
-
nullable=True,
|
124
|
-
server_default="{}",
|
125
|
-
default=list,
|
126
|
-
)
|
127
|
-
|
128
|
-
__table_args__ = (
|
129
|
-
Index(
|
130
|
-
"ix_tcf_publisher_restriction_config_purpose",
|
131
|
-
"tcf_configuration_id",
|
132
|
-
"purpose_id",
|
133
|
-
),
|
134
|
-
)
|
135
|
-
|
136
|
-
def __init__(self, **kwargs: Any) -> None:
|
137
|
-
validated_kwargs = self.validate_publisher_restriction_data(kwargs)
|
138
|
-
super().__init__(**validated_kwargs)
|
139
|
-
|
140
|
-
@staticmethod
|
141
|
-
def validate_entires_for_vendor_restriction(
|
142
|
-
entries: List[RangeEntry], vendor_restriction: TCFVendorRestriction
|
143
|
-
) -> None:
|
144
|
-
"""
|
145
|
-
Validates that if vendor_restriction is restrict_all_vendors, then the entries list is empty.
|
146
|
-
If vendor_restriction is not restrict_all_vendors, then there must be at least one entry.
|
147
|
-
"""
|
148
|
-
if vendor_restriction == TCFVendorRestriction.restrict_all_vendors and entries:
|
149
|
-
raise ValueError(
|
150
|
-
"A restrict_all_vendors restriction cannot have any range entries"
|
151
|
-
)
|
152
|
-
|
153
|
-
if (
|
154
|
-
vendor_restriction != TCFVendorRestriction.restrict_all_vendors
|
155
|
-
and not entries
|
156
|
-
):
|
157
|
-
raise ValueError(
|
158
|
-
f"A {vendor_restriction} restriction must have at least one range entry"
|
159
|
-
)
|
160
|
-
|
161
|
-
@staticmethod
|
162
|
-
def check_for_overlaps(entries: List[RangeEntry]) -> None:
|
163
|
-
"""
|
164
|
-
Check for overlapping ranges in a list of RangeEntry objects,
|
165
|
-
raises a ValueError if any pair of RangeEntry overlaps with each other.
|
166
|
-
Sorts the ranges by start_vendor_id and compares adjacent ranges.
|
167
|
-
"""
|
168
|
-
# Sort ranges by start_vendor_id
|
169
|
-
sorted_entries = sorted(entries, key=lambda x: x.start_vendor_id)
|
170
|
-
|
171
|
-
# Compare each range with the next one
|
172
|
-
for i in range(len(sorted_entries) - 1):
|
173
|
-
current = sorted_entries[i]
|
174
|
-
next_entry = sorted_entries[i + 1]
|
175
|
-
if current.overlaps_with(next_entry):
|
176
|
-
raise ValueError(
|
177
|
-
f"Overlapping ranges found: {current.model_dump()} overlaps with {next_entry.model_dump()}"
|
178
|
-
)
|
179
|
-
|
180
|
-
@classmethod
|
181
|
-
def validate_publisher_restriction_data(
|
182
|
-
cls, data: Dict[str, Any]
|
183
|
-
) -> Dict[str, Any]:
|
184
|
-
"""
|
185
|
-
Validate the restriction data.
|
186
|
-
"""
|
187
|
-
raw_range_entries = data.get("range_entries", [])
|
188
|
-
|
189
|
-
try:
|
190
|
-
# Validate each range entry using the Pydantic model
|
191
|
-
validated_entries = [
|
192
|
-
RangeEntry.model_validate(entry) for entry in raw_range_entries
|
193
|
-
]
|
194
|
-
except ValidationError as e:
|
195
|
-
raise ValueError(f"Invalid range entry: {str(e)}")
|
196
|
-
|
197
|
-
# Validate the entries for the vendor restriction
|
198
|
-
cls.validate_entires_for_vendor_restriction(
|
199
|
-
validated_entries, data["vendor_restriction"]
|
200
|
-
)
|
201
|
-
# Check for overlapping ranges
|
202
|
-
cls.check_for_overlaps(validated_entries)
|
203
|
-
|
204
|
-
data["range_entries"] = [entry.model_dump() for entry in validated_entries]
|
205
|
-
|
206
|
-
return data
|
207
|
-
|
208
|
-
@classmethod
|
209
|
-
async def check_for_restriction_conflicts(
|
210
|
-
cls,
|
211
|
-
*,
|
212
|
-
async_db: AsyncSession,
|
213
|
-
configuration_id: str,
|
214
|
-
purpose_id: int,
|
215
|
-
restriction_type: TCFRestrictionType,
|
216
|
-
vendor_restriction: TCFVendorRestriction,
|
217
|
-
range_entries: Optional[list[RangeEntry]] = None,
|
218
|
-
restriction_id: Optional[str] = None,
|
219
|
-
) -> None:
|
220
|
-
"""
|
221
|
-
Checks that the new restriction data does not conflict with any existing restrictions for the purpose.
|
222
|
-
"""
|
223
|
-
# First, get all the restrictions for the purpose in the given configuration
|
224
|
-
query = (
|
225
|
-
select(cls) # type: ignore[arg-type]
|
226
|
-
.where(cls.tcf_configuration_id == configuration_id)
|
227
|
-
.where(cls.purpose_id == purpose_id)
|
228
|
-
)
|
229
|
-
# If we're updating an existing restriction, exclude it from the list of
|
230
|
-
# restrictions so it doesn't conflict with itself
|
231
|
-
if restriction_id:
|
232
|
-
query = query.where(cls.id != restriction_id)
|
233
|
-
|
234
|
-
restrictions_result = await async_db.execute(query)
|
235
|
-
relevant_restrictions = restrictions_result.scalars().all()
|
236
|
-
|
237
|
-
if any(
|
238
|
-
restriction.vendor_restriction == TCFVendorRestriction.restrict_all_vendors
|
239
|
-
for restriction in relevant_restrictions
|
240
|
-
):
|
241
|
-
raise ValueError(
|
242
|
-
f"Invalid restriction for purpose {purpose_id}: a restrict_all_vendors restriction exists for this purpose."
|
243
|
-
)
|
244
|
-
|
245
|
-
# If we're creating a restrict_all_vendors restriction,
|
246
|
-
# then there should be no other restrictions for this purpose
|
247
|
-
if vendor_restriction == TCFVendorRestriction.restrict_all_vendors:
|
248
|
-
if relevant_restrictions:
|
249
|
-
raise ValueError(
|
250
|
-
f"Invalid restrict_all_vendors restriction for purpose {purpose_id}: other restrictions already exist for this purpose."
|
251
|
-
)
|
252
|
-
|
253
|
-
return None
|
254
|
-
|
255
|
-
# If we already have a restriction for that restriction type,
|
256
|
-
# then we raise an error
|
257
|
-
if any(
|
258
|
-
restriction.restriction_type == restriction_type
|
259
|
-
for restriction in relevant_restrictions
|
260
|
-
):
|
261
|
-
raise ValueError(
|
262
|
-
f"Invalid {restriction_type} restriction for purpose {purpose_id}: a restriction of this type already exists for this purpose."
|
263
|
-
)
|
264
|
-
|
265
|
-
# We now need to check for vendor overlaps between all the restrictions.
|
266
|
-
# To achieve this, we need to transform allowlist-style restrictions into
|
267
|
-
# actual restriction ranges (rather than "allow" ranges).
|
268
|
-
new_range_entries = (
|
269
|
-
cls.transform_allowlist_restriction(range_entries or [])
|
270
|
-
if vendor_restriction == TCFVendorRestriction.allow_specific_vendors
|
271
|
-
else (range_entries or [])
|
272
|
-
)
|
273
|
-
|
274
|
-
existing_range_entries = []
|
275
|
-
for restriction in relevant_restrictions:
|
276
|
-
range_entries = [
|
277
|
-
RangeEntry.model_validate(entry) for entry in restriction.range_entries
|
278
|
-
]
|
279
|
-
transformed_range_entries = (
|
280
|
-
cls.transform_allowlist_restriction(range_entries)
|
281
|
-
if restriction.vendor_restriction
|
282
|
-
== TCFVendorRestriction.allow_specific_vendors
|
283
|
-
else range_entries
|
284
|
-
)
|
285
|
-
existing_range_entries.extend(transformed_range_entries)
|
286
|
-
|
287
|
-
all_entries = [*existing_range_entries, *new_range_entries]
|
288
|
-
cls.check_for_overlaps(all_entries)
|
289
|
-
|
290
|
-
@classmethod
|
291
|
-
def transform_allowlist_restriction(
|
292
|
-
cls, range_entries: list[RangeEntry]
|
293
|
-
) -> list[RangeEntry]:
|
294
|
-
"""
|
295
|
-
Transform allowlist-style restrictions into restriction ranges.
|
296
|
-
E.g if you have an "allow specific vendors" restriction with the range_entries
|
297
|
-
[
|
298
|
-
{start_vendor_id: 5, end_vendor_id: 10},
|
299
|
-
{start_vendor_id: 25, end_vendor_id: 40},
|
300
|
-
{start_vendor_id: 123 },
|
301
|
-
{start_vendor_id: 345, end_vendor_id: 380},
|
302
|
-
],
|
303
|
-
the transformed restriction ranges would be:
|
304
|
-
[
|
305
|
-
{start_vendor_id: 1, end_vendor_id: 4},
|
306
|
-
{start_vendor_id: 11, end_vendor_id: 24},
|
307
|
-
{start_vendor_id: 41, end_vendor_id: 122},
|
308
|
-
{start_vendor_id: 124, end_vendor_id: MAX_GVL_ID},
|
309
|
-
]
|
310
|
-
"""
|
311
|
-
MAX_GVL_ID = 9999 # TODO: get this from the TCF spec
|
312
|
-
|
313
|
-
# First, we need to sort the range_entries by start_vendor_id
|
314
|
-
sorted_range_entries = sorted(range_entries, key=lambda x: x.start_vendor_id)
|
315
|
-
|
316
|
-
# Now, we need to transform the allowlist-style restrictions into
|
317
|
-
# actual restriction ranges.
|
318
|
-
transformed_range_entries: list[RangeEntry] = []
|
319
|
-
|
320
|
-
total_entries = len(sorted_range_entries)
|
321
|
-
|
322
|
-
# This shouldn't happen, but just in case
|
323
|
-
if total_entries == 0:
|
324
|
-
raise ValueError(
|
325
|
-
"No range entries found for allow_specific_vendors restriction"
|
326
|
-
)
|
327
|
-
|
328
|
-
# If the first range entry starts at a number greater than 1,
|
329
|
-
# we need to add a transformed range entry from 1 up to the entry's start
|
330
|
-
if sorted_range_entries[0].start_vendor_id > 1:
|
331
|
-
transformed_range_entries.append(
|
332
|
-
RangeEntry(
|
333
|
-
start_vendor_id=1,
|
334
|
-
end_vendor_id=sorted_range_entries[0].start_vendor_id - 1,
|
335
|
-
)
|
336
|
-
)
|
337
|
-
|
338
|
-
# Iterate through the sorted range_entries and transform them into restriction ranges
|
339
|
-
for idx, range_entry in enumerate(sorted_range_entries):
|
340
|
-
# For all but the last range entry, we add an entry that corresponds to the numbers
|
341
|
-
# between the end of the current range entry and the start of the next range entry
|
342
|
-
if idx < total_entries - 1:
|
343
|
-
# Only create a range entry if there's actually a gap between the ranges
|
344
|
-
next_start = sorted_range_entries[idx + 1].start_vendor_id
|
345
|
-
current_end = range_entry.effective_end_vendor_id
|
346
|
-
if next_start > current_end + 1:
|
347
|
-
transformed_range_entries.append(
|
348
|
-
RangeEntry(
|
349
|
-
start_vendor_id=current_end + 1,
|
350
|
-
end_vendor_id=next_start - 1,
|
351
|
-
)
|
352
|
-
)
|
353
|
-
|
354
|
-
# If the last range entry ends at a number less than MAX_GVL_ID,
|
355
|
-
# we need to add a transformed range entry from the last entry's end to MAX_GVL_ID
|
356
|
-
if sorted_range_entries[-1].effective_end_vendor_id < MAX_GVL_ID:
|
357
|
-
transformed_range_entries.append(
|
358
|
-
RangeEntry(
|
359
|
-
start_vendor_id=sorted_range_entries[-1].effective_end_vendor_id
|
360
|
-
+ 1,
|
361
|
-
end_vendor_id=MAX_GVL_ID,
|
362
|
-
)
|
363
|
-
)
|
364
|
-
|
365
|
-
# Return the transformed restriction entries
|
366
|
-
return transformed_range_entries
|
367
|
-
|
368
|
-
@classmethod
|
369
|
-
def create(
|
370
|
-
cls,
|
371
|
-
db: Session,
|
372
|
-
*,
|
373
|
-
data: Dict[str, Any],
|
374
|
-
check_name: bool = True,
|
375
|
-
) -> "TCFPublisherRestriction":
|
376
|
-
raise NotImplementedError("Use create_async instead")
|
377
|
-
|
378
|
-
@classmethod
|
379
|
-
async def create_async(
|
380
|
-
cls,
|
381
|
-
async_db: AsyncSession,
|
382
|
-
*,
|
383
|
-
data: Dict[str, Any],
|
384
|
-
) -> "TCFPublisherRestriction":
|
385
|
-
"""
|
386
|
-
Create a new TCFPublisherRestriction with validated range_entries.
|
387
|
-
"""
|
388
|
-
|
389
|
-
data = cls.validate_publisher_restriction_data(data)
|
390
|
-
|
391
|
-
await cls.check_for_restriction_conflicts(
|
392
|
-
async_db=async_db,
|
393
|
-
configuration_id=data["tcf_configuration_id"],
|
394
|
-
purpose_id=data["purpose_id"],
|
395
|
-
restriction_type=TCFRestrictionType(data["restriction_type"]),
|
396
|
-
vendor_restriction=TCFVendorRestriction(data["vendor_restriction"]),
|
397
|
-
range_entries=[
|
398
|
-
RangeEntry.model_validate(entry) for entry in data["range_entries"]
|
399
|
-
],
|
400
|
-
)
|
401
|
-
|
402
|
-
values = {
|
403
|
-
"tcf_configuration_id": data["tcf_configuration_id"],
|
404
|
-
"purpose_id": data["purpose_id"],
|
405
|
-
"restriction_type": data["restriction_type"],
|
406
|
-
"vendor_restriction": data["vendor_restriction"],
|
407
|
-
"range_entries": data["range_entries"],
|
408
|
-
}
|
409
|
-
|
410
|
-
# Insert the new restriction
|
411
|
-
insert_stmt = insert(cls).values(values) # type: ignore[arg-type]
|
412
|
-
result = await async_db.execute(insert_stmt)
|
413
|
-
record_id = result.inserted_primary_key.id
|
414
|
-
|
415
|
-
created_record = await async_db.execute(select(cls).where(cls.id == record_id)) # type: ignore[arg-type]
|
416
|
-
return created_record.scalars().first()
|
417
|
-
|
418
|
-
async def update_async(
|
419
|
-
self, async_db: AsyncSession, data: Dict[str, Any]
|
420
|
-
) -> "TCFPublisherRestriction":
|
421
|
-
"""
|
422
|
-
Update a TCFPublisherRestriction with the data.
|
423
|
-
Validates the data and checks for vendor overlaps.
|
424
|
-
"""
|
425
|
-
# Create a new dict merging the existing data and the updated data
|
426
|
-
updated_data = {
|
427
|
-
"id": self.id,
|
428
|
-
"tcf_configuration_id": self.tcf_configuration_id,
|
429
|
-
"purpose_id": self.purpose_id,
|
430
|
-
"restriction_type": self.restriction_type,
|
431
|
-
"vendor_restriction": self.vendor_restriction,
|
432
|
-
"range_entries": self.range_entries,
|
433
|
-
**data,
|
434
|
-
}
|
435
|
-
|
436
|
-
# First validate the data on its own
|
437
|
-
data = self.validate_publisher_restriction_data(updated_data)
|
438
|
-
|
439
|
-
# Then check for conflicts
|
440
|
-
await self.check_for_restriction_conflicts(
|
441
|
-
async_db=async_db,
|
442
|
-
configuration_id=self.tcf_configuration_id,
|
443
|
-
purpose_id=self.purpose_id,
|
444
|
-
restriction_type=TCFRestrictionType(data["restriction_type"]),
|
445
|
-
vendor_restriction=TCFVendorRestriction(data["vendor_restriction"]),
|
446
|
-
range_entries=[
|
447
|
-
RangeEntry.model_validate(entry) for entry in data["range_entries"]
|
448
|
-
],
|
449
|
-
restriction_id=self.id,
|
450
|
-
)
|
451
|
-
|
452
|
-
# Remove the id from the updated
|
453
|
-
updated_data.pop("id")
|
454
|
-
|
455
|
-
# Finally, make the update
|
456
|
-
update_query = (
|
457
|
-
update(TCFPublisherRestriction) # type: ignore[arg-type]
|
458
|
-
.where(TCFPublisherRestriction.id == self.id)
|
459
|
-
.values(**updated_data)
|
460
|
-
)
|
461
|
-
await async_db.execute(update_query)
|
462
|
-
await async_db.commit()
|
463
|
-
await async_db.refresh(self)
|
464
|
-
|
465
|
-
return self
|
File without changes
|