ethyca-fides 2.58.2b3__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.
Files changed (198) hide show
  1. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/RECORD +172 -181
  3. fides/_version.py +3 -3
  4. fides/api/api/deps.py +2 -8
  5. fides/api/api/v1/endpoints/user_endpoints.py +12 -8
  6. fides/api/cryptography/identity_salt.py +13 -12
  7. fides/api/custom_types.py +1 -6
  8. fides/api/db/base.py +0 -5
  9. fides/api/db/system.py +3 -1
  10. fides/api/migrations/hash_migration_job.py +2 -2
  11. fides/api/models/attachment.py +11 -80
  12. fides/api/models/comment.py +15 -45
  13. fides/api/models/detection_discovery.py +0 -31
  14. fides/api/models/fides_user.py +9 -26
  15. fides/api/models/fides_user_invite.py +0 -2
  16. fides/api/models/privacy_experience.py +0 -42
  17. fides/api/models/privacy_request/privacy_request.py +6 -23
  18. fides/api/schemas/connection_configuration/connection_config.py +16 -30
  19. fides/api/schemas/user.py +1 -5
  20. fides/api/service/deps.py +0 -9
  21. fides/api/service/storage/s3.py +1 -14
  22. fides/api/service/user/fides_user_service.py +128 -0
  23. fides/api/task/graph_task.py +1 -1
  24. fides/ui-build/static/admin/404.html +1 -1
  25. fides/ui-build/static/admin/_next/static/chunks/{1150-2642cd9cdc8a52f6.js → 1150-035a721a04f4451e.js} +1 -1
  26. fides/ui-build/static/admin/_next/static/chunks/1376-5cea5ef9362215e8.js +1 -0
  27. fides/ui-build/static/admin/_next/static/chunks/{2397-0d1c289b788fcc11.js → 2397-ee53235fb21b5e97.js} +1 -1
  28. fides/ui-build/static/admin/_next/static/chunks/3412-7ec8751b8182e1bf.js +1 -0
  29. fides/ui-build/static/admin/_next/static/chunks/{3855-63495367531cb776.js → 3855-b6b7865dedd7bc2a.js} +1 -1
  30. fides/ui-build/static/admin/_next/static/chunks/{3872-472bb47eb34d8fdb.js → 3872-4e053c20d546f027.js} +1 -1
  31. fides/ui-build/static/admin/_next/static/chunks/{4060-53a5c6347690a8fa.js → 4060-8d165e1236ea521a.js} +1 -1
  32. fides/ui-build/static/admin/_next/static/chunks/4450-36234280bee624ff.js +1 -0
  33. fides/ui-build/static/admin/_next/static/chunks/4481-aab99ff80f707473.js +1 -0
  34. fides/ui-build/static/admin/_next/static/chunks/{5258-cf7b27ef51f38392.js → 5258-0658dc2274df6832.js} +1 -1
  35. fides/ui-build/static/admin/_next/static/chunks/{5480-52dc446be40725f5.js → 5480-f49696df5e8ae500.js} +1 -1
  36. fides/ui-build/static/admin/_next/static/chunks/{5487-8678d75ee1d1ef09.js → 5487-3ad50d21cdbc9209.js} +1 -1
  37. fides/ui-build/static/admin/_next/static/chunks/5973-52aee296edc44f7e.js +1 -0
  38. fides/ui-build/static/admin/_next/static/chunks/{6315-1adb10a8b98b4a13.js → 6315-fa1519cdf080f42d.js} +1 -1
  39. fides/ui-build/static/admin/_next/static/chunks/{6372-e0bb9f8d07cc3b04.js → 6372-ca9c12ac8902365b.js} +1 -1
  40. fides/ui-build/static/admin/_next/static/chunks/{6853-09e831e9dff7fd3b.js → 6853-8941824350c3c1a8.js} +1 -1
  41. fides/ui-build/static/admin/_next/static/chunks/{6954-baa1d873abfe8b77.js → 6954-3b887fb444f9228c.js} +1 -1
  42. fides/ui-build/static/admin/_next/static/chunks/7453-39761c38da31257e.js +1 -0
  43. fides/ui-build/static/admin/_next/static/chunks/{7751-a70fe0e5f67f5538.js → 7751-a8f31c062d4cb09d.js} +1 -1
  44. fides/ui-build/static/admin/_next/static/chunks/{79-8e060d36d36c752c.js → 79-f9b948ebb186900f.js} +1 -1
  45. fides/ui-build/static/admin/_next/static/chunks/{7980-72f745bff9fabcc9.js → 7980-4bd08957448dea32.js} +1 -1
  46. fides/ui-build/static/admin/_next/static/chunks/{9046-8a5fdd335a76d224.js → 9046-04bd7becea207cb1.js} +1 -1
  47. fides/ui-build/static/admin/_next/static/chunks/9767-1a23925d2cb27b51.js +1 -0
  48. fides/ui-build/static/admin/_next/static/chunks/{main-090643377c8254e6.js → main-24f422f93845a596.js} +1 -1
  49. fides/ui-build/static/admin/_next/static/chunks/{main-app-59156a9331ac7bce.js → main-app-94a0711202e08b15.js} +1 -1
  50. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-fbe3db87623c87a0.js → _app-fc89ce7bed454c84.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-9f9500c639362aa6.js → manual-9acaab973dfe86e2.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-fac606150b65d494.js → add-systems-d258f0c25fa020bf.js} +1 -1
  53. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-fb75fa0aea77678d.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-c02b14c50b19bd91.js → new-a9d9402c219d13e5.js} +1 -1
  55. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-c946b33b0322b8ad.js +1 -0
  56. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-ea57f9d6ad17e957.js +1 -0
  57. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-100234c23a85d235.js → reporting-788cf0e34829af46.js} +1 -1
  58. fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-49bffaf07973fead.js → data-catalog-900004e402c31797.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/{[systemId]-727f1f5d06be674b.js → [systemId]-b66831fdafcdf67c.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-5f9ef1f99818117c.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{action-center-719949074f10bd6e.js → action-center-d001337d1bb73bd1.js} +1 -1
  62. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-11b3ce9f61d9bfe9.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-4d4a31d0186a4a5b.js → new-803c1b577ab17ae3.js} +1 -1
  64. fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-29317d18ce34adfe.js → dataset-fa743ddc7f89d76b.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-14c57e5069e9cccd.js → [id]-bbe1ca2793798e6b.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-f0a4e385c1ad8fee.js → new-abc17fef69cd951b.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-a78a73b65929853a.js +1 -0
  68. fides/ui-build/static/admin/_next/static/chunks/pages/{index-b70def65e264270e.js → index-bfaacdb55a5a6c9f.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-d4329043219fed9b.js +1 -0
  70. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-72d64a02b7ef175e.js → [id]-fe765154315782cf.js} +1 -1
  71. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{messaging-5e2687ab5ab10275.js → messaging-f5f7a8069909ef24.js} +1 -1
  72. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-2914aade73dcaecc.js → storage-9f7eaad05e5b9292.js} +1 -1
  73. fides/ui-build/static/admin/_next/static/chunks/pages/{privacy-requests-b0f801d66e79a31a.js → privacy-requests-d85c0d16ba09ba35.js} +1 -1
  74. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-f035cddf17f4d898.js → datamap-afedc48ef4e7f858.js} +1 -1
  75. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-89524101b7279f6e.js +1 -0
  76. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-dfcd7a4b6aa773bd.js → custom-fields-52d030b1db2ca1b9.js} +1 -1
  77. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-0e0aa552f520f913.js → organization-a08693d0d1e10bc8.js} +1 -1
  78. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-1d83d5178b3eb216.js → test-datasets-151571cff4e85894.js} +1 -1
  79. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-a158fa77df288523.js → [id]-4f5a28226575c976.js} +1 -1
  80. fides/ui-build/static/admin/_next/static/chunks/pages/{systems-8490aaaee9d76a4a.js → systems-abd68fc5ddde5482.js} +1 -1
  81. fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-be1ffe267b1602e1.js → taxonomy-16b4d75c49276add.js} +1 -1
  82. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-c0378fd1a26a71da.js → [id]-78eaf933f755bfe8.js} +1 -1
  83. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-3ca3c687e72d1364.js → user-management-6c9ad62479a7d03e.js} +1 -1
  84. fides/ui-build/static/admin/_next/static/css/{cf2744a40308fc4a.css → 113d823fe71f6af0.css} +1 -1
  85. fides/ui-build/static/admin/_next/static/o0mKeH0cB6eAYV6qOlVD0/_buildManifest.js +1 -0
  86. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  87. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  88. fides/ui-build/static/admin/add-systems.html +1 -1
  89. fides/ui-build/static/admin/ant-poc.html +1 -1
  90. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  91. fides/ui-build/static/admin/consent/configure.html +1 -1
  92. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  93. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  94. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  95. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  96. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  97. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  98. fides/ui-build/static/admin/consent/properties.html +1 -1
  99. fides/ui-build/static/admin/consent/reporting.html +1 -1
  100. fides/ui-build/static/admin/consent.html +1 -1
  101. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  102. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  103. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  104. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  105. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  106. fides/ui-build/static/admin/data-catalog.html +1 -1
  107. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  108. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  109. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  110. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  111. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  112. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  113. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  114. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  115. fides/ui-build/static/admin/datamap.html +1 -1
  116. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  117. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  118. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  119. fides/ui-build/static/admin/dataset/new.html +1 -1
  120. fides/ui-build/static/admin/dataset.html +1 -1
  121. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  122. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  123. fides/ui-build/static/admin/datastore-connection.html +1 -1
  124. fides/ui-build/static/admin/index.html +1 -1
  125. fides/ui-build/static/admin/integrations/[id].html +1 -1
  126. fides/ui-build/static/admin/integrations.html +1 -1
  127. fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
  128. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  129. fides/ui-build/static/admin/lib/fides-tcf.js +4 -4
  130. fides/ui-build/static/admin/lib/fides.js +3 -3
  131. fides/ui-build/static/admin/login/[provider].html +1 -1
  132. fides/ui-build/static/admin/login.html +1 -1
  133. fides/ui-build/static/admin/messaging/[id].html +1 -1
  134. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  135. fides/ui-build/static/admin/messaging.html +1 -1
  136. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  137. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  138. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  139. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  140. fides/ui-build/static/admin/privacy-requests.html +1 -1
  141. fides/ui-build/static/admin/properties/[id].html +1 -1
  142. fides/ui-build/static/admin/properties/add-property.html +1 -1
  143. fides/ui-build/static/admin/properties.html +1 -1
  144. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  145. fides/ui-build/static/admin/settings/about.html +1 -1
  146. fides/ui-build/static/admin/settings/consent.html +1 -1
  147. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  148. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  149. fides/ui-build/static/admin/settings/domains.html +1 -1
  150. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  151. fides/ui-build/static/admin/settings/locations.html +1 -1
  152. fides/ui-build/static/admin/settings/organization.html +1 -1
  153. fides/ui-build/static/admin/settings/regulations.html +1 -1
  154. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  155. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  156. fides/ui-build/static/admin/systems.html +1 -1
  157. fides/ui-build/static/admin/taxonomy.html +1 -1
  158. fides/ui-build/static/admin/user-management/new.html +1 -1
  159. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  160. fides/ui-build/static/admin/user-management.html +1 -1
  161. fides/api/alembic/migrations/versions/67d01c4e124e_add_reject_all_mechanism_to_privacy_.py +0 -56
  162. fides/api/alembic/migrations/versions/6e565c16dae1_add_tcf_publisher_restrictions.py +0 -107
  163. fides/api/alembic/migrations/versions/99c603c1b8f9_add_password_login_enabled_and_totp_secret_to_fidesuser.py +0 -45
  164. fides/api/models/tcf_publisher_restrictions.py +0 -304
  165. fides/service/error_handling/__init__.py +0 -0
  166. fides/service/error_handling/error_handler.py +0 -202
  167. fides/service/user/__init__.py +0 -0
  168. fides/service/user/user_service.py +0 -140
  169. fides/ui-build/static/admin/_next/static/S7gURhIaHGAv7MFBTEOOS/_buildManifest.js +0 -1
  170. fides/ui-build/static/admin/_next/static/chunks/1376-03e7f50e708b7589.js +0 -1
  171. fides/ui-build/static/admin/_next/static/chunks/146-0ae2d30ec71fce09.js +0 -1
  172. fides/ui-build/static/admin/_next/static/chunks/1817-f82105a9608bba1a.js +0 -1
  173. fides/ui-build/static/admin/_next/static/chunks/3938-6a1c07d06a80cf4c.js +0 -1
  174. fides/ui-build/static/admin/_next/static/chunks/4450-6a8aa0d7358ac26f.js +0 -1
  175. fides/ui-build/static/admin/_next/static/chunks/4481-275aa9f4c10bce53.js +0 -1
  176. fides/ui-build/static/admin/_next/static/chunks/5973-d3d3872692c1d0fa.js +0 -1
  177. fides/ui-build/static/admin/_next/static/chunks/9767-8179ce7336727141.js +0 -1
  178. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-ab3ef485f6101697.js +0 -1
  179. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-ba5325035c71a97e.js +0 -1
  180. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-ef31c181cac86c64.js +0 -1
  181. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-53efbed54d230f07.js +0 -1
  182. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-4892603e743cd6ab.js +0 -1
  183. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-d2f88a8fc68944db.js +0 -1
  184. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-b75ab4ee677f118d.js +0 -1
  185. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-3ac1e5d3de5dd4a7.js +0 -1
  186. fides/ui-build/static/admin/images/connector-logos/website.svg +0 -10
  187. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/LICENSE +0 -0
  188. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/WHEEL +0 -0
  189. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/entry_points.txt +0 -0
  190. {ethyca_fides-2.58.2b3.dist-info → ethyca_fides-2.58.2rc0.dist-info}/top_level.txt +0 -0
  191. /fides/ui-build/static/admin/_next/static/chunks/{4723-1dd1d16f404d56a2.js → 4723-0a3c5e2ce143a7d0.js} +0 -0
  192. /fides/ui-build/static/admin/_next/static/chunks/{5826-ef0aa43ffad83acc.js → 5826-e5dcb4e68cfe6289.js} +0 -0
  193. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-a4e636eecaba5324.js → configure-723cc3d4f5740ea6.js} +0 -0
  194. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-606457ef5bd1eb04.js → [id]-72251b48e2e03a1e.js} +0 -0
  195. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-2ae030f3a28f057a.js → about-a49d0f84cf0cf05e.js} +0 -0
  196. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-72ec54ee8755a503.js → domain-records-fa42d8f18df44927.js} +0 -0
  197. /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-f8bca2e322ddf252.js → new-be690621a944bfe2.js} +0 -0
  198. /fides/ui-build/static/admin/_next/static/{S7gURhIaHGAv7MFBTEOOS → 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")
@@ -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,304 +0,0 @@
1
- from enum import Enum
2
- from typing import 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
12
-
13
- from fides.api.db.base_class import Base
14
-
15
-
16
- class TCFRestrictionType(str, Enum):
17
- """Enum for TCF restriction types"""
18
-
19
- purpose_restriction = "purpose_restriction"
20
- require_consent = "require_consent"
21
- require_legitimate_interest = "require_legitimate_interest"
22
-
23
-
24
- class TCFVendorRestriction(str, Enum):
25
- """Enum for TCF vendor restriction types"""
26
-
27
- restrict_all_vendors = "restrict_all_vendors"
28
- allow_specific_vendors = "allow_specific_vendors"
29
- restrict_specific_vendors = "restrict_specific_vendors"
30
-
31
-
32
- # This is Pydantic model used for validation, not a database model!
33
- class RangeEntry(BaseModel):
34
- """
35
- Pydantic model that represents a vendor range entry as per the TCF spec,
36
- used for Publisher Restrictions.
37
- A range entry must have a start_vendor_id and optionally an end_vendor_id.
38
- If end_vendor_id is present, it must be greater than start_vendor_id.
39
- """
40
-
41
- start_vendor_id: int = Field(description="The starting vendor ID in the range")
42
- end_vendor_id: Optional[int] = Field(
43
- default=None, description="The ending vendor ID in the range (inclusive)"
44
- )
45
-
46
- @model_validator(mode="after")
47
- def validate_vendor_range(self) -> "RangeEntry":
48
- """Validates that end_vendor_id is greater than start_vendor_id if present."""
49
- if (
50
- self.end_vendor_id is not None
51
- and self.end_vendor_id <= self.start_vendor_id
52
- ):
53
- raise ValueError("end_vendor_id must be greater than start_vendor_id")
54
- return self
55
-
56
- def get_end(self) -> int:
57
- """Get the effective end of the range."""
58
- return self.end_vendor_id or self.start_vendor_id
59
-
60
- def overlaps_with(self, other: "RangeEntry") -> bool:
61
- """
62
- Check if this range overlaps with another range.
63
- Two ranges overlap if the end of the range that starts first is greater than
64
- or equal to the start of the range that starts second.
65
- """
66
- # Sort ranges by start_vendor_id
67
- first = self if self.start_vendor_id <= other.start_vendor_id else other
68
- second = other if self.start_vendor_id <= other.start_vendor_id else self
69
-
70
- # If first range's end is >= second range's start, they overlap
71
- return first.get_end() >= second.start_vendor_id
72
-
73
-
74
- class TCFConfiguration(Base):
75
- """
76
- Stores TCF Configuration settings.
77
- """
78
-
79
- @declared_attr
80
- def __tablename__(self) -> str:
81
- return "tcf_configuration"
82
-
83
- name = Column(String, nullable=False, index=True, unique=True)
84
-
85
-
86
- class TCFPublisherRestriction(Base):
87
- """
88
- Stores TCF Publisher Restrictions. TCF Publisher Restrictions belong to a TCF Configuration,
89
- and specify the restriction type and vendor restriction for a given purpose.
90
- """
91
-
92
- @declared_attr
93
- def __tablename__(self) -> str:
94
- return "tcf_publisher_restriction"
95
-
96
- tcf_configuration_id = Column(
97
- String(255),
98
- ForeignKey("tcf_configuration.id", ondelete="CASCADE"),
99
- nullable=False,
100
- index=True,
101
- )
102
- purpose_id = Column(Integer, nullable=False)
103
- restriction_type = Column(EnumColumn(TCFRestrictionType), nullable=False)
104
- vendor_restriction = Column(EnumColumn(TCFVendorRestriction), nullable=False)
105
-
106
- # range_entries represents a list of RangeEntry objects as per the TCF spec.
107
- # A RangeEntry object will have a start_vendor_id and an end_vendor_id (the
108
- # end vendor id is included in the range).
109
- # If the range represents a single vendor, then the end_vendor_id can be omitted.
110
- # TCF spec also includes an IsARange boolean, which we are omitting because it
111
- # can be inferred from the presence of the end_vendor_id.
112
- range_entries = Column(
113
- ARRAY(JSONB),
114
- nullable=True,
115
- server_default="{}",
116
- default=list,
117
- )
118
-
119
- __table_args__ = (
120
- Index(
121
- "ix_tcf_publisher_restriction_config_purpose",
122
- "tcf_configuration_id",
123
- "purpose_id",
124
- ),
125
- )
126
-
127
- def __init__(self, **kwargs: Any) -> None:
128
- validated_kwargs = self.validate_publisher_restriction_data(kwargs)
129
- super().__init__(**validated_kwargs)
130
-
131
- @staticmethod
132
- def validate_entires_for_vendor_restriction(
133
- entries: List[RangeEntry], vendor_restriction: TCFVendorRestriction
134
- ) -> None:
135
- """
136
- Validates that if vendor_restriction is restrict_all_vendors, then the entries list is empty.
137
- """
138
- if vendor_restriction == TCFVendorRestriction.restrict_all_vendors and entries:
139
- raise ValueError("restrict_all_vendors cannot have any range entries")
140
-
141
- @staticmethod
142
- def check_for_overlaps(entries: List[RangeEntry]) -> None:
143
- """
144
- Check for overlapping ranges in a list of RangeEntry objects,
145
- raises a ValueError if any pair of RangeEntry overlaps with each other.
146
- Sorts the ranges by start_vendor_id and compares adjacent ranges.
147
- """
148
- # Sort ranges by start_vendor_id
149
- sorted_entries = sorted(entries, key=lambda x: x.start_vendor_id)
150
-
151
- # Compare each range with the next one
152
- for i in range(len(sorted_entries) - 1):
153
- current = sorted_entries[i]
154
- next_entry = sorted_entries[i + 1]
155
- if current.overlaps_with(next_entry):
156
- raise ValueError(
157
- f"Overlapping ranges found: {current.model_dump()} overlaps with {next_entry.model_dump()}"
158
- )
159
-
160
- @classmethod
161
- def validate_publisher_restriction_data(
162
- cls, data: Dict[str, Any]
163
- ) -> Dict[str, Any]:
164
- """
165
- Validate the restriction data.
166
- """
167
- raw_range_entries = data.get("range_entries", [])
168
-
169
- try:
170
- # Validate each range entry using the Pydantic model
171
- validated_entries = [
172
- RangeEntry.model_validate(entry) for entry in raw_range_entries
173
- ]
174
- except ValidationError as e:
175
- raise ValueError(f"Invalid range entry: {str(e)}")
176
-
177
- # Validate the entries for the vendor restriction
178
- cls.validate_entires_for_vendor_restriction(
179
- validated_entries, data["vendor_restriction"]
180
- )
181
- # Check for overlapping ranges
182
- cls.check_for_overlaps(validated_entries)
183
-
184
- data["range_entries"] = [entry.model_dump() for entry in validated_entries]
185
-
186
- return data
187
-
188
- @classmethod
189
- async def validate_vendor_overlaps_for_purpose(
190
- cls,
191
- async_db: AsyncSession,
192
- configuration_id: str,
193
- purpose_id: int,
194
- new_data: dict,
195
- ) -> None:
196
- """
197
- Validates that the new vendor ranges do not overlap with any existing vendor ranges for the purpose
198
- in the given configuration.
199
- Raises a ValueError if any vendor ranges overlap.
200
- """
201
- # First, get all the restrictions for the purpose in the given configuration
202
- query = (
203
- select(cls) # type: ignore[arg-type]
204
- .where(cls.tcf_configuration_id == configuration_id)
205
- .where(cls.purpose_id == purpose_id)
206
- )
207
- restrictions = await async_db.execute(query)
208
- restrictions = restrictions.scalars().all()
209
-
210
- # If we have an existing id, we need to exclude the current restriction from the list of existing restrictions
211
- # so that the new_data restrictions don't overlap with themselves
212
- if "id" in new_data:
213
- existing_entries = [
214
- entry
215
- for r in restrictions
216
- for entry in r.range_entries
217
- if r.id != new_data["id"]
218
- ]
219
- else:
220
- existing_entries = [
221
- entry for r in restrictions for entry in r.range_entries
222
- ]
223
-
224
- all_entries = [*existing_entries, *new_data.get("range_entries", [])]
225
- cls.check_for_overlaps(
226
- [RangeEntry.model_validate(entry) for entry in all_entries]
227
- )
228
-
229
- @classmethod
230
- def create(
231
- cls,
232
- db: Session,
233
- *,
234
- data: Dict[str, Any],
235
- check_name: bool = True,
236
- ) -> "TCFPublisherRestriction":
237
- raise NotImplementedError("Use create_async instead")
238
-
239
- @classmethod
240
- async def create_async(
241
- cls,
242
- async_db: AsyncSession,
243
- *,
244
- data: Dict[str, Any],
245
- ) -> "TCFPublisherRestriction":
246
- """
247
- Create a new TCFPublisherRestriction with validated range_entries.
248
- """
249
-
250
- data = cls.validate_publisher_restriction_data(data)
251
-
252
- values = {
253
- "tcf_configuration_id": data["tcf_configuration_id"],
254
- "purpose_id": data["purpose_id"],
255
- "restriction_type": data["restriction_type"],
256
- "vendor_restriction": data["vendor_restriction"],
257
- "range_entries": data["range_entries"],
258
- }
259
-
260
- # Validate that the new vendor ranges do not overlap with any existing vendor ranges for the purpose
261
- await cls.validate_vendor_overlaps_for_purpose(
262
- async_db=async_db,
263
- configuration_id=data["tcf_configuration_id"],
264
- purpose_id=data["purpose_id"],
265
- new_data=values,
266
- )
267
-
268
- # Insert the new restriction
269
- insert_stmt = insert(cls).values(values) # type: ignore[arg-type]
270
- result = await async_db.execute(insert_stmt)
271
- record_id = result.inserted_primary_key.id
272
-
273
- created_record = await async_db.execute(select(cls).where(cls.id == record_id)) # type: ignore[arg-type]
274
- return created_record.scalars().first()
275
-
276
- async def update_async(
277
- self, async_db: AsyncSession, data: Dict[str, Any]
278
- ) -> "TCFPublisherRestriction":
279
- """
280
- Update a TCFPublisherRestriction with the data.
281
- Validates the data and checks for vendor overlaps.
282
- """
283
- # Validate the data on its own
284
- data = self.validate_publisher_restriction_data(data)
285
-
286
- # Validate that the new vendor ranges do not overlap with any existing vendor ranges for the purpose
287
- await self.validate_vendor_overlaps_for_purpose(
288
- async_db=async_db,
289
- configuration_id=self.tcf_configuration_id,
290
- purpose_id=self.purpose_id,
291
- new_data={**data, "id": self.id}, # Pass in id explicitly
292
- )
293
-
294
- # Finally, make the update
295
- update_query = (
296
- update(TCFPublisherRestriction) # type: ignore[arg-type]
297
- .where(TCFPublisherRestriction.id == self.id)
298
- .values(**data)
299
- )
300
- await async_db.execute(update_query)
301
- await async_db.commit()
302
- await async_db.refresh(self)
303
-
304
- return self
File without changes
@@ -1,202 +0,0 @@
1
- from functools import wraps
2
- from typing import Any, Callable, Optional, TypeVar
3
-
4
- from fastapi import HTTPException
5
- from loguru import logger
6
- from starlette.status import HTTP_400_BAD_REQUEST, HTTP_422_UNPROCESSABLE_ENTITY
7
-
8
- T = TypeVar("T")
9
-
10
-
11
- class ErrorHandler:
12
- """Utility class for handling errors consistently throughout the application.
13
-
14
- Usage Examples:
15
- -----------------------------------------------------------------------------
16
-
17
- 1. Basic Validation:
18
- ```python
19
- from fastapi import FastAPI
20
- from fides.service.error_handling.error_handler import ErrorHandler
21
-
22
- app = FastAPI()
23
-
24
- @app.post("/users")
25
- def create_user(age: int):
26
- # Simple validation
27
- ErrorHandler.validate(age >= 18, "User must be 18 or older")
28
- return {"message": "User created"}
29
-
30
- @app.get("/items/{item_id}")
31
- def get_item(item_id: str):
32
- # Direct error raising
33
- if not item_id:
34
- ErrorHandler.raise_error("Item ID is required", status_code=400)
35
- return {"item_id": item_id}
36
- ```
37
-
38
- 2. Exception Handling Decorator:
39
- ```python
40
- @app.post("/orders")
41
- @ErrorHandler.handle_exceptions("Failed to create order")
42
- def create_order(order_data: dict):
43
- if not order_data.get("items"):
44
- raise ValueError("Order must contain items")
45
- # Process order...
46
- return {"message": "Order created"}
47
-
48
- @app.get("/products/{product_id}")
49
- @ErrorHandler.handle_exceptions("Failed to fetch product", status_code=404)
50
- def get_product(product_id: str):
51
- product = database.get_product(product_id)
52
- if not product:
53
- raise ValueError("Product not found")
54
- return product
55
- ```
56
-
57
- 3. Complex Validation:
58
- ```python
59
- @app.post("/payments")
60
- @ErrorHandler.handle_exceptions("Payment processing failed")
61
- def process_payment(payment: dict):
62
- # Validate amount
63
- ErrorHandler.validate(
64
- payment.get("amount", 0) > 0,
65
- "Payment amount must be positive",
66
- HTTP_400_BAD_REQUEST
67
- )
68
-
69
- # Validate currency
70
- ErrorHandler.validate(
71
- payment.get("currency") in ["USD", "EUR"],
72
- "Invalid currency",
73
- HTTP_400_BAD_REQUEST,
74
- "Unsupported currency provided" # Optional log message
75
- )
76
-
77
- # Custom error for insufficient funds
78
- if payment.get("amount", 0) > get_balance():
79
- ErrorHandler.raise_error(
80
- "Insufficient funds",
81
- status_code=HTTP_400_BAD_REQUEST,
82
- log_message="User attempted payment exceeding balance"
83
- )
84
-
85
- return {"status": "payment processed"}
86
- ```
87
-
88
- 4. Error Logging:
89
- ```python
90
- @app.post("/imports")
91
- @ErrorHandler.handle_exceptions("Import failed")
92
- def import_data(data: dict):
93
- try:
94
- process_import(data)
95
- except Exception as e:
96
- # Log error with custom message before raising
97
- ErrorHandler.raise_error(
98
- "Import failed: invalid format",
99
- status_code=400,
100
- log_message=f"Import failed with error: {str(e)}"
101
- )
102
- return {"status": "import complete"}
103
- ```
104
-
105
- Key Features:
106
- - Simple validation with custom error messages
107
- - Consistent error handling across endpoints
108
- - Built-in error logging
109
- - HTTP status code customization
110
- - Exception handling decorator for common patterns
111
- """
112
-
113
- @staticmethod
114
- def raise_error(
115
- detail: str,
116
- status_code: int = HTTP_422_UNPROCESSABLE_ENTITY,
117
- log_message: Optional[str] = None,
118
- ) -> None:
119
- """Raise an HTTPException with consistent logging.
120
-
121
- Args:
122
- detail: Error message to include in the HTTPException
123
- status_code: HTTP status code to use (default: 422)
124
- log_message: Optional message to log before raising the exception
125
-
126
- Raises:
127
- HTTPException: Always raised with the provided details
128
- """
129
- if log_message:
130
- logger.error(log_message)
131
- raise HTTPException(status_code=status_code, detail=detail)
132
-
133
- @staticmethod
134
- def validate(
135
- condition: bool,
136
- detail: str,
137
- status_code: int = HTTP_400_BAD_REQUEST,
138
- log_message: Optional[str] = None,
139
- ) -> None:
140
- """Validate a condition and raise an error if it's False.
141
-
142
- Args:
143
- condition: The condition to check
144
- detail: Error message if condition is False
145
- status_code: HTTP status code to use if condition is False
146
- log_message: Optional message to log before raising the exception
147
-
148
- Raises:
149
- HTTPException: If the condition is False
150
- """
151
- if not condition:
152
- ErrorHandler.raise_error(detail, status_code, log_message)
153
-
154
- @classmethod
155
- def handle_exceptions(
156
- cls, error_message: str, status_code: int = HTTP_422_UNPROCESSABLE_ENTITY
157
- ) -> Callable[[Callable[..., T]], Callable[..., T]]:
158
- """Decorator to handle exceptions consistently.
159
-
160
- Args:
161
- error_message: Base error message to use
162
- status_code: HTTP status code to use for unexpected errors
163
-
164
- Returns:
165
- Callable: The decorated function that handles exceptions
166
-
167
- Note:
168
- This decorator will catch specific exceptions and convert them to HTTPExceptions.
169
- HTTPExceptions are re-raised as is, while other exceptions are wrapped with
170
- additional context.
171
- """
172
-
173
- def decorator(func: Callable[..., T]) -> Callable[..., T]:
174
- @wraps(func)
175
- def wrapper(*args: Any, **kwargs: Any) -> Optional[T]:
176
- try:
177
- return func(*args, **kwargs)
178
- except HTTPException:
179
- # Re-raise HTTP exceptions without modification
180
- raise
181
- except (ValueError, TypeError, AttributeError, KeyError) as e:
182
- # Handle common validation and data access errors
183
- cls.raise_error(
184
- f"{error_message}: {str(e)}",
185
- status_code,
186
- f"{error_message}: {e}",
187
- )
188
- except Exception as e: # pylint: disable=broad-except
189
- # Log unexpected errors with full context but present a sanitized message
190
- logger.error(
191
- f"Unexpected error in {func.__name__}: {str(e)}", exc_info=True
192
- )
193
- cls.raise_error(
194
- f"{error_message}: An unexpected error occurred",
195
- status_code,
196
- f"{error_message}: Unexpected {type(e).__name__}",
197
- )
198
- return None # This line is never reached but satisfies the return type checker
199
-
200
- return wrapper # type: ignore[return-value]
201
-
202
- return decorator
File without changes