ethyca-fides 2.58.1rc0__py2.py3-none-any.whl → 2.58.2b0__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.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/METADATA +1 -1
- {ethyca_fides-2.58.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/RECORD +159 -154
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/67d01c4e124e_add_reject_all_mechanism_to_privacy_.py +56 -0
- fides/api/alembic/migrations/versions/6e565c16dae1_add_tcf_publisher_restrictions.py +107 -0
- fides/api/api/deps.py +8 -2
- fides/api/cryptography/identity_salt.py +12 -13
- fides/api/custom_types.py +6 -1
- fides/api/db/base.py +5 -0
- fides/api/migrations/hash_migration_job.py +2 -2
- fides/api/models/attachment.py +80 -11
- fides/api/models/comment.py +45 -15
- fides/api/models/privacy_experience.py +42 -0
- fides/api/models/privacy_request/privacy_request.py +23 -6
- fides/api/models/tcf_publisher_restrictions.py +186 -0
- fides/api/schemas/connection_configuration/connection_config.py +30 -16
- fides/api/service/storage/s3.py +14 -1
- fides/api/task/graph_task.py +1 -1
- fides/service/error_handling/__init__.py +0 -0
- fides/service/error_handling/error_handler.py +202 -0
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{1150-035a721a04f4451e.js → 1150-2642cd9cdc8a52f6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1376-98cbf3789b9145c3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{2397-ee53235fb21b5e97.js → 2397-0d1c289b788fcc11.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3412-da7ad82093c5b879.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3855-b6b7865dedd7bc2a.js → 3855-63495367531cb776.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{3872-4e053c20d546f027.js → 3872-472bb47eb34d8fdb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{4060-8d165e1236ea521a.js → 4060-53a5c6347690a8fa.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{4450-36234280bee624ff.js → 4450-f5e6eb9270f03bf0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5258-0658dc2274df6832.js → 5258-cf7b27ef51f38392.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5480-f49696df5e8ae500.js → 5480-52dc446be40725f5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5487-3ad50d21cdbc9209.js → 5487-8678d75ee1d1ef09.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5973-52aee296edc44f7e.js → 5973-88141f9b92f20e0a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6315-fa1519cdf080f42d.js → 6315-1adb10a8b98b4a13.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6372-ca9c12ac8902365b.js → 6372-e0bb9f8d07cc3b04.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6853-8941824350c3c1a8.js → 6853-8700d87c9e1f6940.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6954-3b887fb444f9228c.js → 6954-85a998d74391caaf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{7453-39761c38da31257e.js → 7453-ef1887105c062d37.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{7751-a8f31c062d4cb09d.js → 7751-a70fe0e5f67f5538.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{79-f9b948ebb186900f.js → 79-8e060d36d36c752c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{7980-4bd08957448dea32.js → 7980-72f745bff9fabcc9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{9046-04bd7becea207cb1.js → 9046-742ad2bb5108d4c5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{9767-1a23925d2cb27b51.js → 9767-06d9d54a452ec9f4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{main-24f422f93845a596.js → main-090643377c8254e6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{main-app-94a0711202e08b15.js → main-app-59156a9331ac7bce.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-fc89ce7bed454c84.js → _app-d4f59c13cb550ff4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-d258f0c25fa020bf.js → add-systems-fac606150b65d494.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-c946b33b0322b8ad.js → privacy-experience-d6909fbd52309a89.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-ea57f9d6ad17e957.js → privacy-notices-e7acf6d9d30b1fd9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-788cf0e34829af46.js → reporting-100234c23a85d235.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-900004e402c31797.js → data-catalog-fffd4942be7760dd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/{[systemId]-b66831fdafcdf67c.js → [systemId]-df8512ccd0ea9829.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-11b3ce9f61d9bfe9.js → activity-8aeded3289d61405.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-803c1b577ab17ae3.js → new-4d4a31d0186a4a5b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-fa743ddc7f89d76b.js → dataset-29317d18ce34adfe.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-bbe1ca2793798e6b.js → [id]-14c57e5069e9cccd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-abc17fef69cd951b.js → new-4e0057c72fac3a9e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{datastore-connection-a78a73b65929853a.js → datastore-connection-60a01ede4d8b56fd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-bfaacdb55a5a6c9f.js → index-b70def65e264270e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-528c98747299d138.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-fe765154315782cf.js → [id]-1bdec4c3e51f5199.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{messaging-f5f7a8069909ef24.js → messaging-5e2687ab5ab10275.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-9f7eaad05e5b9292.js → storage-2914aade73dcaecc.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{privacy-requests-d85c0d16ba09ba35.js → privacy-requests-dea4dd41db4d382b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-afedc48ef4e7f858.js → datamap-0da40a92590792af.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-3ac1e5d3de5dd4a7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-52d030b1db2ca1b9.js → custom-fields-dfcd7a4b6aa773bd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-a08693d0d1e10bc8.js → organization-0e0aa552f520f913.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-151571cff4e85894.js → test-datasets-1d83d5178b3eb216.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{systems-abd68fc5ddde5482.js → systems-8490aaaee9d76a4a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-16b4d75c49276add.js → taxonomy-be1ffe267b1602e1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-78eaf933f755bfe8.js → [id]-c0378fd1a26a71da.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-6c9ad62479a7d03e.js → user-management-3ca3c687e72d1364.js} +1 -1
- fides/ui-build/static/admin/_next/static/{7Gn2YyMsVjWkBPSaVWEi9 → u9w7grMtLxEveFsXqNFab}/_buildManifest.js +1 -1
- fides/ui-build/static/admin/add-systems/manual.html +1 -1
- fides/ui-build/static/admin/add-systems/multiple.html +1 -1
- fides/ui-build/static/admin/add-systems.html +1 -1
- fides/ui-build/static/admin/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 +3 -3
- 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/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/ui-build/static/admin/_next/static/chunks/1376-5cea5ef9362215e8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3412-7ec8751b8182e1bf.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-d4329043219fed9b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-89524101b7279f6e.js +0 -1
- {ethyca_fides-2.58.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/LICENSE +0 -0
- {ethyca_fides-2.58.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.58.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.58.1rc0.dist-info → ethyca_fides-2.58.2b0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{4723-0a3c5e2ce143a7d0.js → 4723-1dd1d16f404d56a2.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{5826-e5dcb4e68cfe6289.js → 5826-ef0aa43ffad83acc.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-723cc3d4f5740ea6.js → configure-a4e636eecaba5324.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-fa42d8f18df44927.js → domain-records-72ec54ee8755a503.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-4f5a28226575c976.js → [id]-8aae66669bdc0883.js} +0 -0
- /fides/ui-build/static/admin/_next/static/{7Gn2YyMsVjWkBPSaVWEi9 → u9w7grMtLxEveFsXqNFab}/_ssgManifest.js +0 -0
fides/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2025-04-
|
11
|
+
"date": "2025-04-02T16:21:34-0300",
|
12
12
|
"dirty": false,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "2.58.
|
14
|
+
"full-revisionid": "fe5691256243517ec2cac351e75000e269a4fa50",
|
15
|
+
"version": "2.58.2b0"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
"""add_reject_all_mechanism_to_privacy_experience_config
|
2
|
+
|
3
|
+
Revision ID: 67d01c4e124e
|
4
|
+
Revises: 1d2f04ac19f2
|
5
|
+
Create Date: 2025-03-27 15:26:24.635947
|
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 = "67d01c4e124e"
|
15
|
+
down_revision = "1d2f04ac19f2"
|
16
|
+
branch_labels = None
|
17
|
+
depends_on = None
|
18
|
+
|
19
|
+
|
20
|
+
def upgrade():
|
21
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
22
|
+
|
23
|
+
# Add the reject all mechanism enum and column
|
24
|
+
op.execute(
|
25
|
+
"CREATE TYPE rejectallmechanism AS ENUM ('REJECT_ALL', 'REJECT_CONSENT_ONLY')"
|
26
|
+
)
|
27
|
+
op.add_column(
|
28
|
+
"privacyexperienceconfig",
|
29
|
+
sa.Column(
|
30
|
+
"reject_all_mechanism",
|
31
|
+
sa.Enum("REJECT_ALL", "REJECT_CONSENT_ONLY", name="rejectallmechanism"),
|
32
|
+
nullable=True,
|
33
|
+
),
|
34
|
+
)
|
35
|
+
op.add_column(
|
36
|
+
"privacyexperienceconfighistory",
|
37
|
+
sa.Column(
|
38
|
+
"reject_all_mechanism",
|
39
|
+
sa.Enum("REJECT_ALL", "REJECT_CONSENT_ONLY", name="rejectallmechanism"),
|
40
|
+
nullable=True,
|
41
|
+
),
|
42
|
+
)
|
43
|
+
|
44
|
+
# Data migration - set the reject_all_mechanism for all TCF experience configs to REJECT_ALL
|
45
|
+
op.execute(
|
46
|
+
"UPDATE privacyexperienceconfig SET reject_all_mechanism = 'REJECT_ALL' WHERE component = 'tcf_overlay'"
|
47
|
+
)
|
48
|
+
# ### end Alembic commands ###
|
49
|
+
|
50
|
+
|
51
|
+
def downgrade():
|
52
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
53
|
+
op.drop_column("privacyexperienceconfig", "reject_all_mechanism")
|
54
|
+
op.drop_column("privacyexperienceconfighistory", "reject_all_mechanism")
|
55
|
+
op.execute("DROP TYPE IF EXISTS rejectallmechanism")
|
56
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,107 @@
|
|
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/api/deps.py
CHANGED
@@ -29,8 +29,14 @@ def get_db() -> Generator:
|
|
29
29
|
|
30
30
|
|
31
31
|
@contextmanager
|
32
|
-
def
|
33
|
-
"""
|
32
|
+
def get_autoclose_db_session() -> Generator[Session, None, None]:
|
33
|
+
"""
|
34
|
+
Return a database session as a context manager that automatically closes when the context exits.
|
35
|
+
|
36
|
+
Unlike get_api_session which is managed by FastAPI's dependency injection,
|
37
|
+
this context manager explicitly closes the session when exiting the context.
|
38
|
+
Use this when you need manual control over the session lifecycle outside of API endpoints.
|
39
|
+
"""
|
34
40
|
try:
|
35
41
|
db = get_api_session()
|
36
42
|
yield db
|
@@ -3,9 +3,8 @@ from functools import cache
|
|
3
3
|
|
4
4
|
from loguru import logger
|
5
5
|
|
6
|
-
from fides.api.
|
6
|
+
from fides.api.api.deps import get_autoclose_db_session
|
7
7
|
from fides.api.models.identity_salt import IdentitySalt
|
8
|
-
from fides.config import CONFIG
|
9
8
|
|
10
9
|
|
11
10
|
@cache
|
@@ -15,14 +14,14 @@ def get_identity_salt() -> str:
|
|
15
14
|
This function is cached to avoid repeated calls to the database for the same value.
|
16
15
|
"""
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
with get_autoclose_db_session() as db:
|
18
|
+
existing_salt = db.query(IdentitySalt).first()
|
19
|
+
if existing_salt is None:
|
20
|
+
new_salt = IdentitySalt.create(
|
21
|
+
db, data={"encrypted_value": {"value": secrets.token_hex(32)}}
|
22
|
+
)
|
23
|
+
logger.info("Created new identity salt.")
|
24
|
+
return new_salt.encrypted_value.get("value")
|
25
|
+
|
26
|
+
logger.info("Caching existing identity salt.")
|
27
|
+
return existing_salt.encrypted_value.get("value")
|
fides/api/custom_types.py
CHANGED
@@ -66,8 +66,13 @@ def validate_html_str(val: str) -> str:
|
|
66
66
|
"strong",
|
67
67
|
"u",
|
68
68
|
}
|
69
|
+
|
70
|
+
ALLOWED_ATTRIBUTES = {
|
71
|
+
"a": {"href", "hreflang", "target"},
|
72
|
+
}
|
73
|
+
|
69
74
|
if val:
|
70
|
-
return clean(val, tags=ALLOWED_HTML_TAGS)
|
75
|
+
return clean(val, tags=ALLOWED_HTML_TAGS, attributes=ALLOWED_ATTRIBUTES)
|
71
76
|
return val
|
72
77
|
|
73
78
|
|
fides/api/db/base.py
CHANGED
@@ -8,6 +8,7 @@ from fides.api.models.attachment import Attachment, AttachmentReference
|
|
8
8
|
from fides.api.models.audit_log import AuditLog
|
9
9
|
from fides.api.models.authentication_request import AuthenticationRequest
|
10
10
|
from fides.api.models.client import ClientDetail
|
11
|
+
from fides.api.models.comment import Comment, CommentReference
|
11
12
|
from fides.api.models.connectionconfig import ConnectionConfig
|
12
13
|
from fides.api.models.consent_automation import ConsentAutomation
|
13
14
|
from fides.api.models.custom_asset import CustomAsset
|
@@ -58,4 +59,8 @@ from fides.api.models.storage import StorageConfig
|
|
58
59
|
from fides.api.models.system_compass_sync import SystemCompassSync
|
59
60
|
from fides.api.models.system_history import SystemHistory
|
60
61
|
from fides.api.models.system_manager import SystemManager
|
62
|
+
from fides.api.models.tcf_publisher_restrictions import (
|
63
|
+
TCFConfiguration,
|
64
|
+
TCFPublisherRestriction,
|
65
|
+
)
|
61
66
|
from fides.api.models.tcf_purpose_overrides import TCFPurposeOverride
|
@@ -2,7 +2,7 @@ from loguru import logger
|
|
2
2
|
from sqlalchemy import text
|
3
3
|
from sqlalchemy.orm import Session
|
4
4
|
|
5
|
-
from fides.api.api.deps import
|
5
|
+
from fides.api.api.deps import get_autoclose_db_session
|
6
6
|
from fides.api.db.base_class import FidesBase
|
7
7
|
from fides.api.migrations.hash_migration_mixin import HashMigrationMixin
|
8
8
|
from fides.api.migrations.hash_migration_tracker import HashMigrationTracker
|
@@ -47,7 +47,7 @@ def bcrypt_migration_task() -> None:
|
|
47
47
|
Job to migrate all the tables using bcrypt hashes for general data (excludes tables with credentials).
|
48
48
|
"""
|
49
49
|
|
50
|
-
with
|
50
|
+
with get_autoclose_db_session() as db:
|
51
51
|
# Do a single pass to check if any of the models have already been migrated.
|
52
52
|
# This will allow us to optimize searching for these models by not calling
|
53
53
|
# the previously used bcrypt hash.
|
fides/api/models/attachment.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import os
|
2
2
|
from enum import Enum as EnumType
|
3
|
-
from
|
3
|
+
from io import BytesIO
|
4
|
+
from typing import IO, TYPE_CHECKING, Any, Optional, Tuple, Union
|
4
5
|
|
6
|
+
from fideslang.validation import AnyHttpUrlString
|
5
7
|
from loguru import logger as log
|
6
8
|
from sqlalchemy import Column
|
7
9
|
from sqlalchemy import Enum as EnumColumn
|
8
|
-
from sqlalchemy import ForeignKey, String, UniqueConstraint
|
10
|
+
from sqlalchemy import ForeignKey, String, UniqueConstraint, orm
|
9
11
|
from sqlalchemy.ext.declarative import declared_attr
|
10
12
|
from sqlalchemy.orm import Session, relationship
|
11
13
|
|
@@ -23,6 +25,10 @@ from fides.api.service.storage.util import (
|
|
23
25
|
get_local_filename,
|
24
26
|
)
|
25
27
|
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
from fides.api.models.comment import Comment
|
30
|
+
from fides.api.models.privacy_request import PrivacyRequest
|
31
|
+
|
26
32
|
|
27
33
|
class AttachmentType(str, EnumType):
|
28
34
|
"""
|
@@ -53,7 +59,9 @@ class AttachmentReference(Base):
|
|
53
59
|
"""Overriding base class method to set the table name."""
|
54
60
|
return "attachment_reference"
|
55
61
|
|
56
|
-
attachment_id = Column(
|
62
|
+
attachment_id = Column(
|
63
|
+
String, ForeignKey("attachment.id", ondelete="CASCADE"), nullable=False
|
64
|
+
)
|
57
65
|
reference_id = Column(String, nullable=False)
|
58
66
|
reference_type = Column(EnumColumn(AttachmentReferenceType), nullable=False)
|
59
67
|
|
@@ -63,11 +71,8 @@ class AttachmentReference(Base):
|
|
63
71
|
),
|
64
72
|
)
|
65
73
|
|
66
|
-
|
67
|
-
|
68
|
-
back_populates="references",
|
69
|
-
uselist=False,
|
70
|
-
)
|
74
|
+
# Relationships
|
75
|
+
attachment = relationship("Attachment", back_populates="references")
|
71
76
|
|
72
77
|
@classmethod
|
73
78
|
def create(
|
@@ -100,8 +105,11 @@ class Attachment(Base):
|
|
100
105
|
references = relationship(
|
101
106
|
"AttachmentReference",
|
102
107
|
back_populates="attachment",
|
103
|
-
cascade="all, delete",
|
108
|
+
cascade="all, delete-orphan",
|
104
109
|
uselist=True,
|
110
|
+
foreign_keys=[AttachmentReference.attachment_id],
|
111
|
+
primaryjoin=lambda: Attachment.id
|
112
|
+
== orm.foreign(AttachmentReference.attachment_id),
|
105
113
|
)
|
106
114
|
|
107
115
|
config = relationship(
|
@@ -127,13 +135,34 @@ class Attachment(Base):
|
|
127
135
|
|
128
136
|
if self.config.type == StorageType.local:
|
129
137
|
filename = get_local_filename(self.id)
|
138
|
+
|
139
|
+
# Validate that attachment is a file-like object
|
140
|
+
if not hasattr(attachment, "read"):
|
141
|
+
raise TypeError(f"Expected a file-like object, got {type(attachment)}")
|
142
|
+
|
143
|
+
# Reset the file pointer to the beginning
|
144
|
+
try:
|
145
|
+
attachment.seek(0)
|
146
|
+
except Exception as e:
|
147
|
+
raise ValueError(f"Failed to reset file pointer for attachment: {e}")
|
148
|
+
|
149
|
+
# Write the file in chunks to avoid loading the entire content into memory
|
130
150
|
with open(filename, "wb") as file:
|
131
|
-
|
151
|
+
for chunk in iter(
|
152
|
+
lambda: attachment.read(1024 * 1024), b""
|
153
|
+
): # 1 MB chunks
|
154
|
+
if not isinstance(chunk, bytes):
|
155
|
+
raise TypeError(f"Expected bytes, got {type(chunk)}")
|
156
|
+
file.write(chunk)
|
157
|
+
|
158
|
+
log.info(f"Uploaded {self.file_name} to local storage at {filename}")
|
132
159
|
return
|
133
160
|
|
134
161
|
raise ValueError(f"Unsupported storage type: {self.config.type}")
|
135
162
|
|
136
|
-
def retrieve_attachment(
|
163
|
+
def retrieve_attachment(
|
164
|
+
self,
|
165
|
+
) -> Optional[Tuple[BytesIO, Union[AnyHttpUrlString, str]]]:
|
137
166
|
"""Returns the attachment from S3 in bytes form."""
|
138
167
|
if self.config.type == StorageType.s3:
|
139
168
|
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
@@ -208,4 +237,44 @@ class Attachment(Base):
|
|
208
237
|
def delete(self, db: Session) -> None:
|
209
238
|
"""Deletes an attachment record from the database and deletes the attachment from S3."""
|
210
239
|
self.delete_attachment_from_storage()
|
240
|
+
for attachment_reference in self.references:
|
241
|
+
attachment_reference.delete(db)
|
211
242
|
super().delete(db=db)
|
243
|
+
|
244
|
+
@staticmethod
|
245
|
+
def delete_attachments_for_reference_and_type(
|
246
|
+
db: Session, reference_id: str, reference_type: AttachmentReferenceType
|
247
|
+
) -> None:
|
248
|
+
"""
|
249
|
+
Deletes attachments associated with a given reference_id and reference_type.
|
250
|
+
Deletes all references to the attachments.
|
251
|
+
|
252
|
+
Args:
|
253
|
+
db: Database session
|
254
|
+
reference_id: ID of the reference
|
255
|
+
reference_type: Type of the reference
|
256
|
+
|
257
|
+
Examples:
|
258
|
+
|
259
|
+
- Delete all attachments associated with a comment.
|
260
|
+
``Attachment.delete_attachments_for_reference_and_type(
|
261
|
+
db, comment.id, AttachmentReferenceType.comment
|
262
|
+
)``
|
263
|
+
- Delete all attachments associated with a privacy request.
|
264
|
+
``Attachment.delete_attachments_for_reference_and_type(
|
265
|
+
db, privacy_request.id, AttachmentReferenceType.privacy_request
|
266
|
+
)``
|
267
|
+
"""
|
268
|
+
# Query attachments explicitly to avoid lazy loading
|
269
|
+
attachments = (
|
270
|
+
db.query(Attachment)
|
271
|
+
.join(AttachmentReference)
|
272
|
+
.filter(
|
273
|
+
AttachmentReference.reference_id == reference_id,
|
274
|
+
AttachmentReference.reference_type == reference_type,
|
275
|
+
)
|
276
|
+
.all()
|
277
|
+
)
|
278
|
+
|
279
|
+
for attachment in attachments:
|
280
|
+
attachment.delete(db)
|
fides/api/models/comment.py
CHANGED
@@ -3,15 +3,17 @@ from typing import TYPE_CHECKING, Any
|
|
3
3
|
|
4
4
|
from sqlalchemy import Column
|
5
5
|
from sqlalchemy import Enum as EnumColumn
|
6
|
-
from sqlalchemy import ForeignKey, String, UniqueConstraint
|
6
|
+
from sqlalchemy import ForeignKey, String, UniqueConstraint, orm
|
7
7
|
from sqlalchemy.ext.declarative import declared_attr
|
8
8
|
from sqlalchemy.orm import Session, relationship
|
9
9
|
|
10
10
|
from fides.api.db.base_class import Base
|
11
|
+
from fides.api.models.attachment import Attachment, AttachmentReferenceType
|
11
12
|
|
12
13
|
if TYPE_CHECKING:
|
13
|
-
from fides.api.models.attachment import
|
14
|
+
from fides.api.models.attachment import AttachmentReference
|
14
15
|
from fides.api.models.fides_user import FidesUser
|
16
|
+
from fides.api.models.privacy_request import PrivacyRequest
|
15
17
|
|
16
18
|
|
17
19
|
class CommentType(str, EnumType):
|
@@ -87,23 +89,51 @@ class Comment(Base):
|
|
87
89
|
references = relationship(
|
88
90
|
"CommentReference",
|
89
91
|
back_populates="comment",
|
90
|
-
cascade="all, delete",
|
91
|
-
uselist=True,
|
92
|
-
)
|
93
|
-
|
94
|
-
attachments = relationship(
|
95
|
-
"Attachment",
|
96
|
-
secondary="attachment_reference",
|
97
|
-
primaryjoin="Comment.id == AttachmentReference.reference_id",
|
98
|
-
secondaryjoin="Attachment.id == AttachmentReference.attachment_id",
|
99
|
-
order_by="Attachment.created_at",
|
92
|
+
cascade="all, delete-orphan",
|
100
93
|
uselist=True,
|
94
|
+
foreign_keys=[CommentReference.comment_id],
|
95
|
+
primaryjoin=lambda: Comment.id == orm.foreign(CommentReference.comment_id),
|
101
96
|
)
|
102
97
|
|
103
98
|
def delete(self, db: Session) -> None:
|
104
99
|
"""Delete the comment and all associated references."""
|
105
100
|
# Delete the comment
|
106
|
-
|
107
|
-
|
108
|
-
|
101
|
+
Attachment.delete_attachments_for_reference_and_type(
|
102
|
+
db, self.id, AttachmentReferenceType.comment
|
103
|
+
)
|
104
|
+
for reference in self.references:
|
105
|
+
reference.delete(db)
|
109
106
|
db.delete(self)
|
107
|
+
|
108
|
+
@staticmethod
|
109
|
+
def delete_comments_for_reference_and_type(
|
110
|
+
db: Session, reference_id: str, reference_type: CommentReferenceType
|
111
|
+
) -> None:
|
112
|
+
"""
|
113
|
+
Deletes comments associated with a given reference_id and reference_type.
|
114
|
+
Delete all references to the comments.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
db: Database session.
|
118
|
+
reference_id: The reference id to delete.
|
119
|
+
reference_type: The reference type to delete
|
120
|
+
|
121
|
+
Examples:
|
122
|
+
- Delete all comments associated with a privacy request.
|
123
|
+
``Comment.delete_comments_for_reference_and_type(
|
124
|
+
db, privacy_request.id, CommentReferenceType.privacy_request
|
125
|
+
)``
|
126
|
+
"""
|
127
|
+
# Query comments explicitly to avoid lazy loading
|
128
|
+
comments = (
|
129
|
+
db.query(Comment)
|
130
|
+
.join(CommentReference)
|
131
|
+
.filter(
|
132
|
+
CommentReference.reference_id == reference_id,
|
133
|
+
CommentReference.reference_type == reference_type,
|
134
|
+
)
|
135
|
+
.all()
|
136
|
+
)
|
137
|
+
|
138
|
+
for comment in comments:
|
139
|
+
comment.delete(db)
|
@@ -46,6 +46,21 @@ class Layer1ButtonOption(Enum):
|
|
46
46
|
|
47
47
|
ACKNOWLEDGE = "acknowledge"
|
48
48
|
OPT_IN_OPT_OUT = "opt_in_opt_out"
|
49
|
+
OPT_IN_ONLY = "opt_in_only"
|
50
|
+
|
51
|
+
|
52
|
+
class RejectAllMechanism(Enum):
|
53
|
+
"""
|
54
|
+
Reject all mechanism options - not formalized in the db.
|
55
|
+
Used to configure the behavior of the reject all button in TCF experiences
|
56
|
+
"""
|
57
|
+
|
58
|
+
# Reject both consent and legitimate interest preferences (all purposes, special features, vendors)
|
59
|
+
# This is the default behavior
|
60
|
+
REJECT_ALL = "reject_all"
|
61
|
+
# Reject only consent preferences (all purposes, special features, vendors).
|
62
|
+
# Do not reject any legitimate interest preferences.
|
63
|
+
REJECT_CONSENT_ONLY = "reject_consent_only"
|
49
64
|
|
50
65
|
|
51
66
|
# Fides JS UX Types - there should only be one of these defined per region
|
@@ -179,6 +194,10 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
|
|
179
194
|
The Privacy Experience Configuration model that stores shared configuration for Privacy Experiences.
|
180
195
|
|
181
196
|
- Translations, Notices, and Regions (via Privacy Experiences) are linked to this resource.
|
197
|
+
|
198
|
+
If you're adding a new PrivacyExperienceConfig, make sure to use the `create` method since it has
|
199
|
+
custom logic that ensures other resources are created/updated as needed, as well as setting the
|
200
|
+
expected values for some fields in the experience config itself.
|
182
201
|
"""
|
183
202
|
|
184
203
|
allow_language_selection = Column(
|
@@ -203,6 +222,13 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
|
|
203
222
|
String, ForeignKey(ExperienceConfigTemplate.id_field_path)
|
204
223
|
) # The template from which this config was created if applicable
|
205
224
|
|
225
|
+
# Mechanism to use when the reject all button is clicked in a TCF experience
|
226
|
+
# Nullable because this is not applicable for other experience types
|
227
|
+
reject_all_mechanism = Column(
|
228
|
+
EnumColumn(RejectAllMechanism),
|
229
|
+
nullable=True,
|
230
|
+
)
|
231
|
+
|
206
232
|
# Relationships
|
207
233
|
experiences = relationship(
|
208
234
|
"PrivacyExperience",
|
@@ -304,6 +330,15 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
|
|
304
330
|
# Link Properties to this Privacy Experience config via the PrivacyExperienceConfigProperty table
|
305
331
|
link_properties_to_experience_config(db, properties, experience_config)
|
306
332
|
|
333
|
+
# If the reject all mechanism is not set and the experience config is a TCF experience,
|
334
|
+
# set the reject all mechanism to REJECT_ALL
|
335
|
+
if (
|
336
|
+
experience_config.component == ComponentType.tcf_overlay
|
337
|
+
and experience_config.reject_all_mechanism is None
|
338
|
+
):
|
339
|
+
experience_config.reject_all_mechanism = RejectAllMechanism.REJECT_ALL # type: ignore
|
340
|
+
experience_config.save(db)
|
341
|
+
|
307
342
|
return experience_config
|
308
343
|
|
309
344
|
def update(self, db: Session, *, data: dict[str, Any]) -> PrivacyExperienceConfig:
|
@@ -507,6 +542,13 @@ class PrivacyExperienceConfigHistory(
|
|
507
542
|
index=True,
|
508
543
|
) # If a translation is deleted, this is set to null, but the overall record remains in the database for reporting purposes
|
509
544
|
|
545
|
+
# Mechanism to use when the reject all button is clicked in a TCF experience
|
546
|
+
# Nullable because this is not applicable for other experience types
|
547
|
+
reject_all_mechanism = Column(
|
548
|
+
EnumColumn(RejectAllMechanism),
|
549
|
+
nullable=True,
|
550
|
+
)
|
551
|
+
|
510
552
|
version = Column(Float, nullable=False, default=1.0)
|
511
553
|
|
512
554
|
|
@@ -39,10 +39,14 @@ from fides.api.graph.config import (
|
|
39
39
|
CollectionAddress,
|
40
40
|
)
|
41
41
|
from fides.api.migrations.hash_migration_mixin import HashMigrationMixin
|
42
|
-
from fides.api.models.attachment import
|
42
|
+
from fides.api.models.attachment import (
|
43
|
+
Attachment,
|
44
|
+
AttachmentReference,
|
45
|
+
AttachmentReferenceType,
|
46
|
+
)
|
43
47
|
from fides.api.models.audit_log import AuditLog
|
44
48
|
from fides.api.models.client import ClientDetail
|
45
|
-
from fides.api.models.comment import Comment, CommentReference
|
49
|
+
from fides.api.models.comment import Comment, CommentReference, CommentReferenceType
|
46
50
|
from fides.api.models.fides_user import FidesUser
|
47
51
|
from fides.api.models.manual_webhook import AccessManualWebhook
|
48
52
|
from fides.api.models.policy import (
|
@@ -169,18 +173,25 @@ class PrivacyRequest(
|
|
169
173
|
backref="privacy_requests",
|
170
174
|
)
|
171
175
|
attachments = relationship(
|
172
|
-
Attachment,
|
176
|
+
"Attachment",
|
173
177
|
secondary="attachment_reference",
|
174
|
-
primaryjoin="PrivacyRequest.id == AttachmentReference.reference_id"
|
178
|
+
primaryjoin="and_(PrivacyRequest.id == AttachmentReference.reference_id, "
|
179
|
+
"AttachmentReference.reference_type == 'privacy_request')",
|
175
180
|
secondaryjoin="Attachment.id == AttachmentReference.attachment_id",
|
176
181
|
order_by="Attachment.created_at",
|
182
|
+
viewonly=True,
|
183
|
+
uselist=True,
|
177
184
|
)
|
185
|
+
|
178
186
|
comments = relationship(
|
179
|
-
Comment,
|
187
|
+
"Comment",
|
180
188
|
secondary="comment_reference",
|
181
|
-
primaryjoin="PrivacyRequest.id == CommentReference.reference_id"
|
189
|
+
primaryjoin="and_(PrivacyRequest.id == CommentReference.reference_id, "
|
190
|
+
"CommentReference.reference_type == 'privacy_request')",
|
182
191
|
secondaryjoin="Comment.id == CommentReference.comment_id",
|
183
192
|
order_by="Comment.created_at",
|
193
|
+
viewonly=True,
|
194
|
+
uselist=True,
|
184
195
|
)
|
185
196
|
property_id = Column(String, nullable=True)
|
186
197
|
|
@@ -323,6 +334,12 @@ class PrivacyRequest(
|
|
323
334
|
deleting this object from the database
|
324
335
|
"""
|
325
336
|
self.clear_cached_values()
|
337
|
+
Attachment.delete_attachments_for_reference_and_type(
|
338
|
+
db, self.id, AttachmentReferenceType.privacy_request
|
339
|
+
)
|
340
|
+
Comment.delete_comments_for_reference_and_type(
|
341
|
+
db, self.id, CommentReferenceType.privacy_request
|
342
|
+
)
|
326
343
|
|
327
344
|
for provided_identity in self.provided_identities: # type: ignore[attr-defined]
|
328
345
|
provided_identity.delete(db=db)
|