ethyca-fides 2.58.1b5__py2.py3-none-any.whl → 2.58.1rc0__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.
Files changed (161) hide show
  1. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/RECORD +154 -157
  3. fides/_version.py +3 -3
  4. fides/api/api/deps.py +2 -8
  5. fides/api/cryptography/identity_salt.py +13 -12
  6. fides/api/custom_types.py +1 -6
  7. fides/api/db/base.py +0 -1
  8. fides/api/migrations/hash_migration_job.py +2 -2
  9. fides/api/models/attachment.py +11 -80
  10. fides/api/models/comment.py +15 -45
  11. fides/api/models/privacy_experience.py +0 -42
  12. fides/api/models/privacy_request/privacy_request.py +6 -23
  13. fides/api/schemas/connection_configuration/connection_config.py +16 -30
  14. fides/api/service/storage/s3.py +1 -14
  15. fides/api/task/graph_task.py +1 -1
  16. fides/ui-build/static/admin/404.html +1 -1
  17. fides/ui-build/static/admin/_next/static/{ImUuWMsloiAWNWbICVyCj → 7Gn2YyMsVjWkBPSaVWEi9}/_buildManifest.js +1 -1
  18. fides/ui-build/static/admin/_next/static/chunks/{1150-2642cd9cdc8a52f6.js → 1150-035a721a04f4451e.js} +1 -1
  19. fides/ui-build/static/admin/_next/static/chunks/1376-5cea5ef9362215e8.js +1 -0
  20. fides/ui-build/static/admin/_next/static/chunks/{2397-0d1c289b788fcc11.js → 2397-ee53235fb21b5e97.js} +1 -1
  21. fides/ui-build/static/admin/_next/static/chunks/3412-7ec8751b8182e1bf.js +1 -0
  22. fides/ui-build/static/admin/_next/static/chunks/{3855-63495367531cb776.js → 3855-b6b7865dedd7bc2a.js} +1 -1
  23. fides/ui-build/static/admin/_next/static/chunks/{3872-472bb47eb34d8fdb.js → 3872-4e053c20d546f027.js} +1 -1
  24. fides/ui-build/static/admin/_next/static/chunks/{4060-53a5c6347690a8fa.js → 4060-8d165e1236ea521a.js} +1 -1
  25. fides/ui-build/static/admin/_next/static/chunks/{4450-f5e6eb9270f03bf0.js → 4450-36234280bee624ff.js} +1 -1
  26. fides/ui-build/static/admin/_next/static/chunks/{5258-cf7b27ef51f38392.js → 5258-0658dc2274df6832.js} +1 -1
  27. fides/ui-build/static/admin/_next/static/chunks/{5480-52dc446be40725f5.js → 5480-f49696df5e8ae500.js} +1 -1
  28. fides/ui-build/static/admin/_next/static/chunks/{5487-8678d75ee1d1ef09.js → 5487-3ad50d21cdbc9209.js} +1 -1
  29. fides/ui-build/static/admin/_next/static/chunks/{5973-88141f9b92f20e0a.js → 5973-52aee296edc44f7e.js} +1 -1
  30. fides/ui-build/static/admin/_next/static/chunks/{6315-1adb10a8b98b4a13.js → 6315-fa1519cdf080f42d.js} +1 -1
  31. fides/ui-build/static/admin/_next/static/chunks/{6372-e0bb9f8d07cc3b04.js → 6372-ca9c12ac8902365b.js} +1 -1
  32. fides/ui-build/static/admin/_next/static/chunks/{6853-8700d87c9e1f6940.js → 6853-8941824350c3c1a8.js} +1 -1
  33. fides/ui-build/static/admin/_next/static/chunks/{6954-85a998d74391caaf.js → 6954-3b887fb444f9228c.js} +1 -1
  34. fides/ui-build/static/admin/_next/static/chunks/{7453-ef1887105c062d37.js → 7453-39761c38da31257e.js} +1 -1
  35. fides/ui-build/static/admin/_next/static/chunks/{7751-a70fe0e5f67f5538.js → 7751-a8f31c062d4cb09d.js} +1 -1
  36. fides/ui-build/static/admin/_next/static/chunks/{79-8e060d36d36c752c.js → 79-f9b948ebb186900f.js} +1 -1
  37. fides/ui-build/static/admin/_next/static/chunks/{7980-72f745bff9fabcc9.js → 7980-4bd08957448dea32.js} +1 -1
  38. fides/ui-build/static/admin/_next/static/chunks/{9046-742ad2bb5108d4c5.js → 9046-04bd7becea207cb1.js} +1 -1
  39. fides/ui-build/static/admin/_next/static/chunks/{9767-06d9d54a452ec9f4.js → 9767-1a23925d2cb27b51.js} +1 -1
  40. fides/ui-build/static/admin/_next/static/chunks/{main-090643377c8254e6.js → main-24f422f93845a596.js} +1 -1
  41. fides/ui-build/static/admin/_next/static/chunks/{main-app-59156a9331ac7bce.js → main-app-94a0711202e08b15.js} +1 -1
  42. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-d4f59c13cb550ff4.js → _app-fc89ce7bed454c84.js} +1 -1
  43. fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-fac606150b65d494.js → add-systems-d258f0c25fa020bf.js} +1 -1
  44. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-d6909fbd52309a89.js → privacy-experience-c946b33b0322b8ad.js} +1 -1
  45. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-e7acf6d9d30b1fd9.js → privacy-notices-ea57f9d6ad17e957.js} +1 -1
  46. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-100234c23a85d235.js → reporting-788cf0e34829af46.js} +1 -1
  47. fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-fffd4942be7760dd.js → data-catalog-900004e402c31797.js} +1 -1
  48. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/{[systemId]-df8512ccd0ea9829.js → [systemId]-b66831fdafcdf67c.js} +1 -1
  49. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-8aeded3289d61405.js → activity-11b3ce9f61d9bfe9.js} +1 -1
  50. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-4d4a31d0186a4a5b.js → new-803c1b577ab17ae3.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-29317d18ce34adfe.js → dataset-fa743ddc7f89d76b.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-14c57e5069e9cccd.js → [id]-bbe1ca2793798e6b.js} +1 -1
  53. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-4e0057c72fac3a9e.js → new-abc17fef69cd951b.js} +1 -1
  54. fides/ui-build/static/admin/_next/static/chunks/pages/{datastore-connection-60a01ede4d8b56fd.js → datastore-connection-a78a73b65929853a.js} +1 -1
  55. fides/ui-build/static/admin/_next/static/chunks/pages/{index-b70def65e264270e.js → index-bfaacdb55a5a6c9f.js} +1 -1
  56. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-d4329043219fed9b.js +1 -0
  57. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-1bdec4c3e51f5199.js → [id]-fe765154315782cf.js} +1 -1
  58. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{messaging-5e2687ab5ab10275.js → messaging-f5f7a8069909ef24.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-2914aade73dcaecc.js → storage-9f7eaad05e5b9292.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/pages/{privacy-requests-dea4dd41db4d382b.js → privacy-requests-d85c0d16ba09ba35.js} +1 -1
  61. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-0da40a92590792af.js → datamap-afedc48ef4e7f858.js} +1 -1
  62. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-89524101b7279f6e.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-dfcd7a4b6aa773bd.js → custom-fields-52d030b1db2ca1b9.js} +1 -1
  64. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-0e0aa552f520f913.js → organization-a08693d0d1e10bc8.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-1d83d5178b3eb216.js → test-datasets-151571cff4e85894.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/pages/{systems-8490aaaee9d76a4a.js → systems-abd68fc5ddde5482.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-be1ffe267b1602e1.js → taxonomy-16b4d75c49276add.js} +1 -1
  68. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-c0378fd1a26a71da.js → [id]-78eaf933f755bfe8.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-3ca3c687e72d1364.js → user-management-6c9ad62479a7d03e.js} +1 -1
  70. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  71. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  72. fides/ui-build/static/admin/add-systems.html +1 -1
  73. fides/ui-build/static/admin/ant-poc.html +1 -1
  74. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  75. fides/ui-build/static/admin/consent/configure.html +1 -1
  76. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  77. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  78. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  79. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  80. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  81. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  82. fides/ui-build/static/admin/consent/properties.html +1 -1
  83. fides/ui-build/static/admin/consent/reporting.html +1 -1
  84. fides/ui-build/static/admin/consent.html +1 -1
  85. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  86. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  87. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  88. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  89. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  90. fides/ui-build/static/admin/data-catalog.html +1 -1
  91. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  92. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  93. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  94. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  95. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  96. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  97. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  98. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  99. fides/ui-build/static/admin/datamap.html +1 -1
  100. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  101. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  102. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  103. fides/ui-build/static/admin/dataset/new.html +1 -1
  104. fides/ui-build/static/admin/dataset.html +1 -1
  105. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  106. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  107. fides/ui-build/static/admin/datastore-connection.html +1 -1
  108. fides/ui-build/static/admin/index.html +1 -1
  109. fides/ui-build/static/admin/integrations/[id].html +1 -1
  110. fides/ui-build/static/admin/integrations.html +1 -1
  111. fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
  112. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  113. fides/ui-build/static/admin/lib/fides-tcf.js +3 -3
  114. fides/ui-build/static/admin/lib/fides.js +2 -2
  115. fides/ui-build/static/admin/login/[provider].html +1 -1
  116. fides/ui-build/static/admin/login.html +1 -1
  117. fides/ui-build/static/admin/messaging/[id].html +1 -1
  118. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  119. fides/ui-build/static/admin/messaging.html +1 -1
  120. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  121. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  122. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  123. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  124. fides/ui-build/static/admin/privacy-requests.html +1 -1
  125. fides/ui-build/static/admin/properties/[id].html +1 -1
  126. fides/ui-build/static/admin/properties/add-property.html +1 -1
  127. fides/ui-build/static/admin/properties.html +1 -1
  128. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  129. fides/ui-build/static/admin/settings/about.html +1 -1
  130. fides/ui-build/static/admin/settings/consent.html +1 -1
  131. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  132. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  133. fides/ui-build/static/admin/settings/domains.html +1 -1
  134. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  135. fides/ui-build/static/admin/settings/locations.html +1 -1
  136. fides/ui-build/static/admin/settings/organization.html +1 -1
  137. fides/ui-build/static/admin/settings/regulations.html +1 -1
  138. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  139. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  140. fides/ui-build/static/admin/systems.html +1 -1
  141. fides/ui-build/static/admin/taxonomy.html +1 -1
  142. fides/ui-build/static/admin/user-management/new.html +1 -1
  143. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  144. fides/ui-build/static/admin/user-management.html +1 -1
  145. fides/api/alembic/migrations/versions/67d01c4e124e_add_reject_all_mechanism_to_privacy_.py +0 -56
  146. fides/service/error_handling/__init__.py +0 -0
  147. fides/service/error_handling/error_handler.py +0 -202
  148. fides/ui-build/static/admin/_next/static/chunks/1376-98cbf3789b9145c3.js +0 -1
  149. fides/ui-build/static/admin/_next/static/chunks/3412-da7ad82093c5b879.js +0 -1
  150. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-528c98747299d138.js +0 -1
  151. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-3ac1e5d3de5dd4a7.js +0 -1
  152. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/LICENSE +0 -0
  153. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/WHEEL +0 -0
  154. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/entry_points.txt +0 -0
  155. {ethyca_fides-2.58.1b5.dist-info → ethyca_fides-2.58.1rc0.dist-info}/top_level.txt +0 -0
  156. /fides/ui-build/static/admin/_next/static/{ImUuWMsloiAWNWbICVyCj → 7Gn2YyMsVjWkBPSaVWEi9}/_ssgManifest.js +0 -0
  157. /fides/ui-build/static/admin/_next/static/chunks/{4723-1dd1d16f404d56a2.js → 4723-0a3c5e2ce143a7d0.js} +0 -0
  158. /fides/ui-build/static/admin/_next/static/chunks/{5826-ef0aa43ffad83acc.js → 5826-e5dcb4e68cfe6289.js} +0 -0
  159. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-a4e636eecaba5324.js → configure-723cc3d4f5740ea6.js} +0 -0
  160. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-72ec54ee8755a503.js → domain-records-fa42d8f18df44927.js} +0 -0
  161. /fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-8aae66669bdc0883.js → [id]-4f5a28226575c976.js} +0 -0
fides/api/api/deps.py CHANGED
@@ -29,14 +29,8 @@ def get_db() -> Generator:
29
29
 
30
30
 
31
31
  @contextmanager
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
- """
32
+ def get_db_contextmanager() -> Generator[Session, None, None]:
33
+ """Return our database session as a context manager"""
40
34
  try:
41
35
  db = get_api_session()
42
36
  yield db
@@ -3,8 +3,9 @@ from functools import cache
3
3
 
4
4
  from loguru import logger
5
5
 
6
- from fides.api.api.deps import get_autoclose_db_session
6
+ from fides.api.db.session import get_db_session
7
7
  from fides.api.models.identity_salt import IdentitySalt
8
+ from fides.config import CONFIG
8
9
 
9
10
 
10
11
  @cache
@@ -14,14 +15,14 @@ def get_identity_salt() -> str:
14
15
  This function is cached to avoid repeated calls to the database for the same value.
15
16
  """
16
17
 
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")
18
+ SessionLocal = get_db_session(CONFIG)
19
+ db = SessionLocal()
20
+ existing_salt = db.query(IdentitySalt).first()
21
+ if existing_salt is None:
22
+ new_salt = IdentitySalt.create(
23
+ db, data={"encrypted_value": {"value": secrets.token_hex(32)}}
24
+ )
25
+ logger.info("Created new identity salt.")
26
+ return new_salt.encrypted_value.get("value")
27
+ logger.info("Caching existing identity salt.")
28
+ return existing_salt.encrypted_value.get("value")
fides/api/custom_types.py CHANGED
@@ -66,13 +66,8 @@ 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
-
74
69
  if val:
75
- return clean(val, tags=ALLOWED_HTML_TAGS, attributes=ALLOWED_ATTRIBUTES)
70
+ return clean(val, tags=ALLOWED_HTML_TAGS)
76
71
  return val
77
72
 
78
73
 
fides/api/db/base.py CHANGED
@@ -8,7 +8,6 @@ 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
12
11
  from fides.api.models.connectionconfig import ConnectionConfig
13
12
  from fides.api.models.consent_automation import ConsentAutomation
14
13
  from fides.api.models.custom_asset import CustomAsset
@@ -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 get_autoclose_db_session
5
+ from fides.api.api.deps import get_db_contextmanager
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 get_autoclose_db_session() as db:
50
+ with get_db_contextmanager() 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.
@@ -1,13 +1,11 @@
1
1
  import os
2
2
  from enum import Enum as EnumType
3
- from io import BytesIO
4
- from typing import IO, TYPE_CHECKING, Any, Optional, Tuple, Union
3
+ from typing import IO, Any, Optional
5
4
 
6
- from fideslang.validation import AnyHttpUrlString
7
5
  from loguru import logger as log
8
6
  from sqlalchemy import Column
9
7
  from sqlalchemy import Enum as EnumColumn
10
- from sqlalchemy import ForeignKey, String, UniqueConstraint, orm
8
+ from sqlalchemy import ForeignKey, String, UniqueConstraint
11
9
  from sqlalchemy.ext.declarative import declared_attr
12
10
  from sqlalchemy.orm import Session, relationship
13
11
 
@@ -25,10 +23,6 @@ from fides.api.service.storage.util import (
25
23
  get_local_filename,
26
24
  )
27
25
 
28
- if TYPE_CHECKING:
29
- from fides.api.models.comment import Comment
30
- from fides.api.models.privacy_request import PrivacyRequest
31
-
32
26
 
33
27
  class AttachmentType(str, EnumType):
34
28
  """
@@ -59,9 +53,7 @@ class AttachmentReference(Base):
59
53
  """Overriding base class method to set the table name."""
60
54
  return "attachment_reference"
61
55
 
62
- attachment_id = Column(
63
- String, ForeignKey("attachment.id", ondelete="CASCADE"), nullable=False
64
- )
56
+ attachment_id = Column(String, ForeignKey("attachment.id"), nullable=False)
65
57
  reference_id = Column(String, nullable=False)
66
58
  reference_type = Column(EnumColumn(AttachmentReferenceType), nullable=False)
67
59
 
@@ -71,8 +63,11 @@ class AttachmentReference(Base):
71
63
  ),
72
64
  )
73
65
 
74
- # Relationships
75
- attachment = relationship("Attachment", back_populates="references")
66
+ attachment = relationship(
67
+ "Attachment",
68
+ back_populates="references",
69
+ uselist=False,
70
+ )
76
71
 
77
72
  @classmethod
78
73
  def create(
@@ -105,11 +100,8 @@ class Attachment(Base):
105
100
  references = relationship(
106
101
  "AttachmentReference",
107
102
  back_populates="attachment",
108
- cascade="all, delete-orphan",
103
+ cascade="all, delete",
109
104
  uselist=True,
110
- foreign_keys=[AttachmentReference.attachment_id],
111
- primaryjoin=lambda: Attachment.id
112
- == orm.foreign(AttachmentReference.attachment_id),
113
105
  )
114
106
 
115
107
  config = relationship(
@@ -135,34 +127,13 @@ class Attachment(Base):
135
127
 
136
128
  if self.config.type == StorageType.local:
137
129
  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
150
130
  with open(filename, "wb") as file:
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}")
131
+ file.write(attachment.read())
159
132
  return
160
133
 
161
134
  raise ValueError(f"Unsupported storage type: {self.config.type}")
162
135
 
163
- def retrieve_attachment(
164
- self,
165
- ) -> Optional[Tuple[BytesIO, Union[AnyHttpUrlString, str]]]:
136
+ def retrieve_attachment(self) -> Optional[bytes]:
166
137
  """Returns the attachment from S3 in bytes form."""
167
138
  if self.config.type == StorageType.s3:
168
139
  bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
@@ -237,44 +208,4 @@ class Attachment(Base):
237
208
  def delete(self, db: Session) -> None:
238
209
  """Deletes an attachment record from the database and deletes the attachment from S3."""
239
210
  self.delete_attachment_from_storage()
240
- for attachment_reference in self.references:
241
- attachment_reference.delete(db)
242
211
  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)
@@ -3,17 +3,15 @@ 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, orm
6
+ from sqlalchemy import ForeignKey, String, UniqueConstraint
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
12
11
 
13
12
  if TYPE_CHECKING:
14
- from fides.api.models.attachment import AttachmentReference
13
+ from fides.api.models.attachment import Attachment
15
14
  from fides.api.models.fides_user import FidesUser
16
- from fides.api.models.privacy_request import PrivacyRequest
17
15
 
18
16
 
19
17
  class CommentType(str, EnumType):
@@ -89,51 +87,23 @@ class Comment(Base):
89
87
  references = relationship(
90
88
  "CommentReference",
91
89
  back_populates="comment",
92
- cascade="all, delete-orphan",
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",
93
100
  uselist=True,
94
- foreign_keys=[CommentReference.comment_id],
95
- primaryjoin=lambda: Comment.id == orm.foreign(CommentReference.comment_id),
96
101
  )
97
102
 
98
103
  def delete(self, db: Session) -> None:
99
104
  """Delete the comment and all associated references."""
100
105
  # Delete the comment
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)
106
+ for attachment in self.attachments:
107
+ if len(attachment.references) == 1:
108
+ attachment.delete(db)
106
109
  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,21 +46,6 @@ 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"
64
49
 
65
50
 
66
51
  # Fides JS UX Types - there should only be one of these defined per region
@@ -194,10 +179,6 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
194
179
  The Privacy Experience Configuration model that stores shared configuration for Privacy Experiences.
195
180
 
196
181
  - 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.
201
182
  """
202
183
 
203
184
  allow_language_selection = Column(
@@ -222,13 +203,6 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
222
203
  String, ForeignKey(ExperienceConfigTemplate.id_field_path)
223
204
  ) # The template from which this config was created if applicable
224
205
 
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
-
232
206
  # Relationships
233
207
  experiences = relationship(
234
208
  "PrivacyExperience",
@@ -330,15 +304,6 @@ class PrivacyExperienceConfig(PrivacyExperienceConfigBase, Base):
330
304
  # Link Properties to this Privacy Experience config via the PrivacyExperienceConfigProperty table
331
305
  link_properties_to_experience_config(db, properties, experience_config)
332
306
 
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
-
342
307
  return experience_config
343
308
 
344
309
  def update(self, db: Session, *, data: dict[str, Any]) -> PrivacyExperienceConfig:
@@ -542,13 +507,6 @@ class PrivacyExperienceConfigHistory(
542
507
  index=True,
543
508
  ) # If a translation is deleted, this is set to null, but the overall record remains in the database for reporting purposes
544
509
 
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
-
552
510
  version = Column(Float, nullable=False, default=1.0)
553
511
 
554
512
 
@@ -39,14 +39,10 @@ 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 (
43
- Attachment,
44
- AttachmentReference,
45
- AttachmentReferenceType,
46
- )
42
+ from fides.api.models.attachment import Attachment, AttachmentReference
47
43
  from fides.api.models.audit_log import AuditLog
48
44
  from fides.api.models.client import ClientDetail
49
- from fides.api.models.comment import Comment, CommentReference, CommentReferenceType
45
+ from fides.api.models.comment import Comment, CommentReference
50
46
  from fides.api.models.fides_user import FidesUser
51
47
  from fides.api.models.manual_webhook import AccessManualWebhook
52
48
  from fides.api.models.policy import (
@@ -173,25 +169,18 @@ class PrivacyRequest(
173
169
  backref="privacy_requests",
174
170
  )
175
171
  attachments = relationship(
176
- "Attachment",
172
+ Attachment,
177
173
  secondary="attachment_reference",
178
- primaryjoin="and_(PrivacyRequest.id == AttachmentReference.reference_id, "
179
- "AttachmentReference.reference_type == 'privacy_request')",
174
+ primaryjoin="PrivacyRequest.id == AttachmentReference.reference_id",
180
175
  secondaryjoin="Attachment.id == AttachmentReference.attachment_id",
181
176
  order_by="Attachment.created_at",
182
- viewonly=True,
183
- uselist=True,
184
177
  )
185
-
186
178
  comments = relationship(
187
- "Comment",
179
+ Comment,
188
180
  secondary="comment_reference",
189
- primaryjoin="and_(PrivacyRequest.id == CommentReference.reference_id, "
190
- "CommentReference.reference_type == 'privacy_request')",
181
+ primaryjoin="PrivacyRequest.id == CommentReference.reference_id",
191
182
  secondaryjoin="Comment.id == CommentReference.comment_id",
192
183
  order_by="Comment.created_at",
193
- viewonly=True,
194
- uselist=True,
195
184
  )
196
185
  property_id = Column(String, nullable=True)
197
186
 
@@ -334,12 +323,6 @@ class PrivacyRequest(
334
323
  deleting this object from the database
335
324
  """
336
325
  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
- )
343
326
 
344
327
  for provided_identity in self.provided_identities: # type: ignore[attr-defined]
345
328
  provided_identity.delete(db=db)
@@ -71,23 +71,29 @@ def mask_sensitive_fields(
71
71
  return new_connection_secrets
72
72
 
73
73
 
74
- class ConnectionConfigSecretsMixin(BaseModel):
74
+ class ConnectionConfigurationResponse(BaseModel):
75
75
  """
76
- A schema mixin to declare a connection config `secrets` attribute
77
- and handle masking of sensitive values based on `connection_type`
78
- and (optionally) a `saas_config`.
76
+ Describes the returned schema for a ConnectionConfiguration.
79
77
  """
80
78
 
79
+ name: Optional[str] = None
80
+ key: FidesKey
81
+ description: Optional[str] = None
81
82
  connection_type: ConnectionType
82
- secrets: Optional[Dict[str, Any]] = None
83
+ access: AccessLevel
84
+ created_at: datetime
85
+ updated_at: Optional[datetime] = None
86
+ disabled: Optional[bool] = False
87
+ last_test_timestamp: Optional[datetime] = None
88
+ last_test_succeeded: Optional[bool] = None
83
89
  saas_config: Optional[SaaSConfigBase] = None
90
+ secrets: Optional[Dict[str, Any]] = None
91
+ authorized: Optional[bool] = False
92
+ enabled_actions: Optional[List[ActionType]] = None
84
93
 
85
94
  @model_validator(mode="after")
86
- def mask_sensitive_values(self) -> "ConnectionConfigSecretsMixin":
87
- """
88
- Mask sensitive values in the `secrets` attribute based on `connection_type`
89
- and (optionally) a `saas_config`.
90
- """
95
+ def mask_sensitive_values(self) -> "ConnectionConfigurationResponse":
96
+ """Mask sensitive values in the response."""
91
97
  if self.secrets is None:
92
98
  return self
93
99
 
@@ -110,26 +116,6 @@ class ConnectionConfigSecretsMixin(BaseModel):
110
116
  self.secrets = mask_sensitive_fields(cast(dict, self.secrets), secret_schema)
111
117
  return self
112
118
 
113
-
114
- class ConnectionConfigurationResponse(ConnectionConfigSecretsMixin):
115
- """
116
- Describes the returned schema for a ConnectionConfiguration.
117
-
118
- The mixin base class ensures that `secrets` sensitive values are masked.
119
- """
120
-
121
- name: Optional[str] = None
122
- key: FidesKey
123
- description: Optional[str] = None
124
- access: AccessLevel
125
- created_at: datetime
126
- updated_at: Optional[datetime] = None
127
- disabled: Optional[bool] = False
128
- last_test_timestamp: Optional[datetime] = None
129
- last_test_succeeded: Optional[bool] = None
130
- authorized: Optional[bool] = False
131
- enabled_actions: Optional[List[ActionType]] = None
132
-
133
119
  model_config = ConfigDict(from_attributes=True)
134
120
 
135
121
 
@@ -64,7 +64,7 @@ def generic_upload_to_s3( # pylint: disable=R0913
64
64
  size_threshold: int = LARGE_FILE_THRESHOLD, # 5 MB threshold
65
65
  ) -> Optional[AnyHttpUrlString]:
66
66
  """
67
- Uploads file like objects to S3.
67
+ Uploads arbitrary data to S3 returned from an access request.
68
68
  Handles both small and large uploads.
69
69
 
70
70
  :param storage_secrets: S3 storage secrets
@@ -75,19 +75,6 @@ def generic_upload_to_s3( # pylint: disable=R0913
75
75
  """
76
76
  logger.info("Starting S3 Upload of {}", file_key)
77
77
 
78
- # Validate that the document is a file-like object
79
- if not hasattr(document, "read") or not hasattr(document, "seek"):
80
- raise TypeError(
81
- f"The 'document' parameter must be a file-like object supporting 'read' and 'seek'. "
82
- f"Received: {type(document)}"
83
- )
84
-
85
- # Ensure the file pointer is at the beginning
86
- try:
87
- document.seek(0)
88
- except Exception as e:
89
- raise ValueError(f"Failed to reset file pointer for document: {e}")
90
-
91
78
  s3_client = maybe_get_s3_client(auth_method, storage_secrets)
92
79
 
93
80
  # Define a transfer configuration for multipart uploads
@@ -10,7 +10,7 @@ from loguru import logger
10
10
  from ordered_set import OrderedSet
11
11
  from sqlalchemy.orm import Session
12
12
 
13
- from fides.api.api.deps import get_autoclose_db_session as get_db
13
+ from fides.api.api.deps import get_db_contextmanager as get_db
14
14
  from fides.api.common_exceptions import (
15
15
  ActionDisabled,
16
16
  AwaitingAsyncTaskCallback,
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/113d823fe71f6af0.css" as="style"/><link rel="stylesheet" href="/_next/static/css/113d823fe71f6af0.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-2c7ccac5843c4d8e.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d4f59c13cb550ff4.js" defer=""></script><script src="/_next/static/chunks/pages/404-b202c0d8f6fc75c3.js" defer=""></script><script src="/_next/static/ImUuWMsloiAWNWbICVyCj/_buildManifest.js" defer=""></script><script src="/_next/static/ImUuWMsloiAWNWbICVyCj/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"ImUuWMsloiAWNWbICVyCj","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/113d823fe71f6af0.css" as="style"/><link rel="stylesheet" href="/_next/static/css/113d823fe71f6af0.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-2c7ccac5843c4d8e.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-24f422f93845a596.js" defer=""></script><script src="/_next/static/chunks/pages/_app-fc89ce7bed454c84.js" defer=""></script><script src="/_next/static/chunks/pages/404-b202c0d8f6fc75c3.js" defer=""></script><script src="/_next/static/7Gn2YyMsVjWkBPSaVWEi9/_buildManifest.js" defer=""></script><script src="/_next/static/7Gn2YyMsVjWkBPSaVWEi9/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"7Gn2YyMsVjWkBPSaVWEi9","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>