mage-ai 0.9.32__py3-none-any.whl → 0.9.34__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.

Potentially problematic release.


This version of mage-ai might be problematic. Click here for more details.

Files changed (365) hide show
  1. mage_ai/api/constants.py +37 -2
  2. mage_ai/api/errors.py +9 -5
  3. mage_ai/api/middleware.py +2 -2
  4. mage_ai/api/mixins/__init__.py +0 -0
  5. mage_ai/api/mixins/result_set.py +65 -0
  6. mage_ai/api/operations/base.py +41 -11
  7. mage_ai/api/operations/constants.py +7 -6
  8. mage_ai/api/parsers/BaseParser.py +6 -4
  9. mage_ai/api/parsers/PipelineScheduleParser.py +36 -2
  10. mage_ai/api/policies/BackfillPolicy.py +1 -0
  11. mage_ai/api/policies/BasePolicy.py +229 -40
  12. mage_ai/api/policies/PermissionPolicy.py +17 -0
  13. mage_ai/api/policies/PipelineSchedulePolicy.py +18 -2
  14. mage_ai/api/policies/RolePermissionPolicy.py +2 -1
  15. mage_ai/api/policies/RolePolicy.py +3 -0
  16. mage_ai/api/policies/SessionPolicy.py +36 -1
  17. mage_ai/api/policies/StatusPolicy.py +46 -3
  18. mage_ai/api/policies/UserPolicy.py +25 -2
  19. mage_ai/api/policies/mixins/__init__.py +0 -0
  20. mage_ai/api/policies/mixins/user_permissions.py +241 -0
  21. mage_ai/api/presenters/PermissionPresenter.py +35 -8
  22. mage_ai/api/presenters/RolePresenter.py +29 -12
  23. mage_ai/api/presenters/StatusPresenter.py +11 -0
  24. mage_ai/api/presenters/UserPresenter.py +21 -24
  25. mage_ai/api/resources/BaseResource.py +24 -9
  26. mage_ai/api/resources/BlockResource.py +3 -2
  27. mage_ai/api/resources/DatabaseResource.py +2 -2
  28. mage_ai/api/resources/PermissionResource.py +65 -3
  29. mage_ai/api/resources/Resource.py +8 -1
  30. mage_ai/api/resources/RolePermissionResource.py +23 -0
  31. mage_ai/api/resources/RoleResource.py +75 -4
  32. mage_ai/api/resources/StatusResource.py +34 -0
  33. mage_ai/api/resources/UserResource.py +35 -4
  34. mage_ai/api/result_set.py +8 -1
  35. mage_ai/authentication/permissions/constants.py +78 -0
  36. mage_ai/data_integrations/destinations/constants.py +1 -0
  37. mage_ai/data_integrations/utils/config.py +9 -0
  38. mage_ai/data_integrations/utils/scheduler.py +16 -7
  39. mage_ai/data_preparation/models/block/__init__.py +56 -16
  40. mage_ai/data_preparation/models/block/data_integration/mixins.py +92 -1
  41. mage_ai/data_preparation/models/block/data_integration/utils.py +5 -5
  42. mage_ai/data_preparation/models/block/integration/__init__.py +12 -7
  43. mage_ai/data_preparation/models/block/sql/__init__.py +5 -2
  44. mage_ai/data_preparation/models/block/sql/utils/shared.py +15 -1
  45. mage_ai/data_preparation/models/pipelines/interactions.py +15 -0
  46. mage_ai/data_preparation/shared/secrets.py +7 -17
  47. mage_ai/data_preparation/templates/data_exporters/streaming/google_cloud_pubsub.yaml +5 -0
  48. mage_ai/data_preparation/templates/repo/metadata.yaml +5 -0
  49. mage_ai/io/druid.py +9 -5
  50. mage_ai/io/mssql.py +52 -30
  51. mage_ai/io/postgres.py +1 -0
  52. mage_ai/io/sql.py +15 -1
  53. mage_ai/orchestration/db/models/oauth.py +181 -17
  54. mage_ai/orchestration/db/models/schedules.py +11 -0
  55. mage_ai/presenters/interactions/constants.py +1 -0
  56. mage_ai/presenters/pages/loaders/pipeline_schedules.py +9 -3
  57. mage_ai/server/api/base.py +16 -6
  58. mage_ai/server/api/v1.py +2 -1
  59. mage_ai/server/constants.py +1 -1
  60. mage_ai/server/frontend_dist/404.html +2 -2
  61. mage_ai/server/frontend_dist/_next/static/PBVuphyo_muEAj347ZP_b/_buildManifest.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/1124-d8fc76201b83b376.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/{1749-9ec0f4709f5a9284.js → 1749-a6bdce4ee8a09bce.js} +1 -1
  64. mage_ai/server/frontend_dist/_next/static/chunks/1769-613e23e361eb5bce.js +1 -0
  65. mage_ai/server/frontend_dist/_next/static/chunks/1821-953efd0da290d25f.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/2327-1a797c758f8b064a.js +1 -0
  67. mage_ai/server/frontend_dist/_next/static/chunks/2677-a85c5a72bb695304.js +1 -0
  68. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3419-6c8ec8db8c398c12.js → frontend_dist/_next/static/chunks/3419-0df6c5ef72f2e672.js} +1 -1
  69. mage_ai/server/frontend_dist/_next/static/chunks/3684-e1a713b7c16f0151.js +1 -0
  70. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3859-3501cdba0a33f9f2.js → frontend_dist/_next/static/chunks/3859-ba594d21a1260cd2.js} +1 -1
  71. mage_ai/server/frontend_dist/_next/static/chunks/4636-84f545d1d238df13.js +1 -0
  72. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4839-963da65cea58054f.js → frontend_dist/_next/static/chunks/4839-e5fe343a369734bc.js} +1 -1
  73. mage_ai/server/frontend_dist/_next/static/chunks/5457-97433bc45b42a88a.js +1 -0
  74. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/5499-63667ad5a785dba5.js → frontend_dist/_next/static/chunks/5499-b74459f6be5f9229.js} +1 -1
  75. mage_ai/server/frontend_dist/_next/static/chunks/6043-6ea109833b88eb1d.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/6333-ca4cd6a73a597a40.js +1 -0
  77. mage_ai/server/frontend_dist/_next/static/chunks/7022-80d082a1d7fd1234.js +1 -0
  78. mage_ai/server/frontend_dist/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
  79. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/8013-1d6b1f7c13264cb4.js → frontend_dist/_next/static/chunks/8013-e67c71ddea072a20.js} +1 -1
  80. mage_ai/server/frontend_dist/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
  81. mage_ai/server/frontend_dist/_next/static/chunks/9161-837b653aa849a76f.js +1 -0
  82. mage_ai/server/frontend_dist/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-752d991f239a128f.js +1 -0
  84. mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-a624972d126a3dbd.js → block-layout-a27a28d2a615e364.js} +1 -1
  85. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-98e27a4d7bd0da47.js +1 -0
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/{[...slug]-a95787fe1695f493.js → [...slug]-9eb5dad57da13efd.js} +1 -1
  87. mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-data-products-0d55711df91a78d0.js → global-data-products-26909dec66f00231.js} +1 -1
  88. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-b9eea6abc676ca81.js +1 -0
  89. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-11c601c6ef07fe86.js +1 -0
  90. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-ae6083077c9c1c41.js +1 -0
  91. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-bfce0ee677d57206.js +1 -0
  92. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-476c921d62f565fc.js +1 -0
  93. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/overview-9bc34ef66d84330a.js → frontend_dist/_next/static/chunks/pages/overview-2ec6b17e45a52be8.js} +1 -1
  94. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-605918f3a5c1aac4.js +1 -0
  95. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-84ec3ab0770bcd68.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ee65a62ed166bd85.js} +1 -1
  96. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-2402004a19a6ad53.js +1 -0
  97. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-9a5b4768a640cd68.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-8781db69f19759a1.js} +1 -1
  98. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
  99. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-bd4bd009146bab36.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-234007c99efdccf6.js} +1 -1
  100. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-8405a83adeaa8ff5.js → block-runs-da7510d4b277e47b.js} +1 -1
  101. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runtime-98aa0840a00cc661.js → block-runtime-eae853ff34b09481.js} +1 -1
  102. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-0fb48e1cc51f78b2.js → monitors-a057b17847b82468.js} +1 -1
  103. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-845c1f010d5ec380.js → [run]-99d11c86f8b15369.js} +1 -1
  104. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-9255f85760e1f57a.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-3f0980d8810a540b.js} +1 -1
  105. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{settings-187ac359020704e1.js → settings-9edf75d03460aaeb.js} +1 -1
  106. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-c52d0c49439ec620.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-e7692e54979f037d.js} +1 -1
  107. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-7b3b57523b226a0e.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-cb6a3bcaf4fa1a81.js} +1 -1
  108. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-5eff96c149584e87.js +1 -0
  109. mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipelines-efc080913a247e99.js → pipelines-270b912e1ac189b5.js} +1 -1
  110. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-2058d022972cdea4.js +1 -0
  111. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
  112. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
  113. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-58978256db4efbda.js +1 -0
  114. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/[...slug]-9ddd7eb842d5a911.js +1 -0
  115. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-1694c5eb1acbcf30.js +1 -0
  116. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-6850e854fbedbb61.js +1 -0
  117. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
  118. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
  119. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-6fe3657070f98aca.js → frontend_dist/_next/static/chunks/pages/sign-in-e779dbab123e626e.js} +1 -1
  120. mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/[...slug]-935113d252ada806.js +1 -0
  121. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/templates-25b6d24cfa81c306.js → frontend_dist/_next/static/chunks/pages/templates-7079d637e396f2a8.js} +1 -1
  122. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-67fdb4a3be93aa14.js +1 -0
  123. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9c0374c7c783b34a.js +1 -0
  124. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-ea3a0d48e5822b42.js +1 -0
  125. mage_ai/server/frontend_dist/block-layout.html +2 -2
  126. mage_ai/server/frontend_dist/files.html +2 -2
  127. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  128. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  129. mage_ai/server/frontend_dist/index.html +2 -2
  130. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  131. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  132. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  133. mage_ai/server/frontend_dist/manage/users.html +2 -2
  134. mage_ai/server/frontend_dist/manage.html +2 -2
  135. mage_ai/server/frontend_dist/overview.html +2 -2
  136. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  137. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  138. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  139. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  140. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  141. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  142. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  143. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  144. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  145. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  146. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  147. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  148. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  149. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  150. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  151. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  152. mage_ai/server/frontend_dist/pipelines.html +2 -2
  153. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  154. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +24 -0
  155. mage_ai/server/frontend_dist/settings/workspace/permissions.html +24 -0
  156. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  157. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +24 -0
  158. mage_ai/server/frontend_dist/settings/workspace/roles.html +24 -0
  159. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  160. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +24 -0
  161. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  162. mage_ai/server/frontend_dist/settings.html +2 -2
  163. mage_ai/server/frontend_dist/sign-in.html +5 -5
  164. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  165. mage_ai/server/frontend_dist/templates.html +2 -2
  166. mage_ai/server/frontend_dist/terminal.html +2 -2
  167. mage_ai/server/frontend_dist/test.html +2 -2
  168. mage_ai/server/frontend_dist/triggers.html +2 -2
  169. mage_ai/server/frontend_dist/version-control.html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/_next/static/L-IKw5_bRZUs-wyjnpN_j/_buildManifest.js +1 -0
  172. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1124-d8fc76201b83b376.js +1 -0
  173. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1749-9ec0f4709f5a9284.js → 1749-a6bdce4ee8a09bce.js} +1 -1
  174. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1769-613e23e361eb5bce.js +1 -0
  175. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1821-953efd0da290d25f.js +1 -0
  176. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2327-1a797c758f8b064a.js +1 -0
  177. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2677-a85c5a72bb695304.js +1 -0
  178. mage_ai/server/{frontend_dist/_next/static/chunks/3419-6c8ec8db8c398c12.js → frontend_dist_base_path_template/_next/static/chunks/3419-0df6c5ef72f2e672.js} +1 -1
  179. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3684-e1a713b7c16f0151.js +1 -0
  180. mage_ai/server/{frontend_dist/_next/static/chunks/3859-3501cdba0a33f9f2.js → frontend_dist_base_path_template/_next/static/chunks/3859-ba594d21a1260cd2.js} +1 -1
  181. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4636-84f545d1d238df13.js +1 -0
  182. mage_ai/server/{frontend_dist/_next/static/chunks/4839-963da65cea58054f.js → frontend_dist_base_path_template/_next/static/chunks/4839-e5fe343a369734bc.js} +1 -1
  183. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-97433bc45b42a88a.js +1 -0
  184. mage_ai/server/{frontend_dist/_next/static/chunks/5499-63667ad5a785dba5.js → frontend_dist_base_path_template/_next/static/chunks/5499-b74459f6be5f9229.js} +1 -1
  185. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6043-6ea109833b88eb1d.js +1 -0
  186. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-ca4cd6a73a597a40.js +1 -0
  187. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-80d082a1d7fd1234.js +1 -0
  188. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
  189. mage_ai/server/{frontend_dist/_next/static/chunks/8013-1d6b1f7c13264cb4.js → frontend_dist_base_path_template/_next/static/chunks/8013-e67c71ddea072a20.js} +1 -1
  190. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
  191. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9161-837b653aa849a76f.js +1 -0
  192. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
  193. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-752d991f239a128f.js +1 -0
  194. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-a624972d126a3dbd.js → block-layout-a27a28d2a615e364.js} +1 -1
  195. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-98e27a4d7bd0da47.js +1 -0
  196. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/{[...slug]-a95787fe1695f493.js → [...slug]-9eb5dad57da13efd.js} +1 -1
  197. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-data-products-0d55711df91a78d0.js → global-data-products-26909dec66f00231.js} +1 -1
  198. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-b9eea6abc676ca81.js +1 -0
  199. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-11c601c6ef07fe86.js +1 -0
  200. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-ae6083077c9c1c41.js +1 -0
  201. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-bfce0ee677d57206.js +1 -0
  202. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-476c921d62f565fc.js +1 -0
  203. mage_ai/server/{frontend_dist/_next/static/chunks/pages/overview-9bc34ef66d84330a.js → frontend_dist_base_path_template/_next/static/chunks/pages/overview-2ec6b17e45a52be8.js} +1 -1
  204. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-605918f3a5c1aac4.js +1 -0
  205. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-84ec3ab0770bcd68.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ee65a62ed166bd85.js} +1 -1
  206. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-2402004a19a6ad53.js +1 -0
  207. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-9a5b4768a640cd68.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-8781db69f19759a1.js} +1 -1
  208. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
  209. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-bd4bd009146bab36.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-234007c99efdccf6.js} +1 -1
  210. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-8405a83adeaa8ff5.js → block-runs-da7510d4b277e47b.js} +1 -1
  211. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runtime-98aa0840a00cc661.js → block-runtime-eae853ff34b09481.js} +1 -1
  212. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-0fb48e1cc51f78b2.js → monitors-a057b17847b82468.js} +1 -1
  213. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-845c1f010d5ec380.js → [run]-99d11c86f8b15369.js} +1 -1
  214. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-9255f85760e1f57a.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-3f0980d8810a540b.js} +1 -1
  215. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{settings-187ac359020704e1.js → settings-9edf75d03460aaeb.js} +1 -1
  216. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-c52d0c49439ec620.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-e7692e54979f037d.js} +1 -1
  217. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-7b3b57523b226a0e.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-cb6a3bcaf4fa1a81.js} +1 -1
  218. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-5eff96c149584e87.js +1 -0
  219. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipelines-efc080913a247e99.js → pipelines-270b912e1ac189b5.js} +1 -1
  220. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-2058d022972cdea4.js +1 -0
  221. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
  222. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
  223. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-58978256db4efbda.js +1 -0
  224. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/[...slug]-9ddd7eb842d5a911.js +1 -0
  225. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-1694c5eb1acbcf30.js +1 -0
  226. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-6850e854fbedbb61.js +1 -0
  227. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
  228. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
  229. mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-6fe3657070f98aca.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-e779dbab123e626e.js} +1 -1
  230. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-935113d252ada806.js +1 -0
  231. mage_ai/server/{frontend_dist/_next/static/chunks/pages/templates-25b6d24cfa81c306.js → frontend_dist_base_path_template/_next/static/chunks/pages/templates-7079d637e396f2a8.js} +1 -1
  232. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-67fdb4a3be93aa14.js +1 -0
  233. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9c0374c7c783b34a.js +1 -0
  234. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-ea3a0d48e5822b42.js +1 -0
  235. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  236. mage_ai/server/frontend_dist_base_path_template/files.html +5 -5
  237. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +5 -5
  238. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +5 -5
  239. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  240. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +5 -5
  241. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +5 -5
  242. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +5 -5
  243. mage_ai/server/frontend_dist_base_path_template/manage/users.html +5 -5
  244. mage_ai/server/frontend_dist_base_path_template/manage.html +5 -5
  245. mage_ai/server/frontend_dist_base_path_template/overview.html +5 -5
  246. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +5 -5
  247. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +5 -5
  248. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +5 -5
  249. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +5 -5
  250. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  251. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +5 -5
  252. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +5 -5
  253. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
  254. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +5 -5
  255. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +5 -5
  256. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +5 -5
  257. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +5 -5
  258. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +5 -5
  259. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +5 -5
  260. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +5 -5
  261. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  262. mage_ai/server/frontend_dist_base_path_template/pipelines.html +5 -5
  263. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +5 -5
  264. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +24 -0
  265. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +24 -0
  266. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +5 -5
  267. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +24 -0
  268. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +24 -0
  269. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +5 -5
  270. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +24 -0
  271. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +5 -5
  272. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  273. mage_ai/server/frontend_dist_base_path_template/sign-in.html +13 -13
  274. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +5 -5
  275. mage_ai/server/frontend_dist_base_path_template/templates.html +5 -5
  276. mage_ai/server/frontend_dist_base_path_template/terminal.html +5 -5
  277. mage_ai/server/frontend_dist_base_path_template/test.html +4 -4
  278. mage_ai/server/frontend_dist_base_path_template/triggers.html +5 -5
  279. mage_ai/server/frontend_dist_base_path_template/version-control.html +5 -5
  280. mage_ai/server/server.py +37 -2
  281. mage_ai/services/aws/__init__.py +19 -8
  282. mage_ai/services/spark/config.py +5 -1
  283. mage_ai/services/spark/spark.py +5 -4
  284. mage_ai/settings/__init__.py +2 -0
  285. mage_ai/streaming/constants.py +1 -0
  286. mage_ai/streaming/sinks/google_cloud_pubsub.py +66 -0
  287. mage_ai/streaming/sinks/sink_factory.py +6 -0
  288. mage_ai/tests/api/operations/test_operations.py +8 -2
  289. mage_ai/tests/api/operations/test_pipeline_schedules.py +3 -0
  290. mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +130 -5
  291. mage_ai/tests/factory.py +2 -0
  292. mage_ai/tests/orchestration/test_pipeline_scheduler.py +20 -3
  293. mage_ai/tests/streaming/sinks/test_google_cloud_pubsub.py +28 -0
  294. mage_ai/usage_statistics/logger.py +4 -1
  295. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/METADATA +1 -1
  296. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/RECORD +302 -268
  297. mage_ai/api/policies/utils.py +0 -14
  298. mage_ai/server/frontend_dist/_next/static/cbN7L4Ms6UUPoANozEh9w/_buildManifest.js +0 -1
  299. mage_ai/server/frontend_dist/_next/static/chunks/1769-e2efd4df8d09481f.js +0 -1
  300. mage_ai/server/frontend_dist/_next/static/chunks/2327-2d8a1555605cf4af.js +0 -1
  301. mage_ai/server/frontend_dist/_next/static/chunks/2369-cb9cd97052e18d27.js +0 -1
  302. mage_ai/server/frontend_dist/_next/static/chunks/2677-aea54e655c4a727f.js +0 -1
  303. mage_ai/server/frontend_dist/_next/static/chunks/5457-994e1044953f1425.js +0 -1
  304. mage_ai/server/frontend_dist/_next/static/chunks/5597-c034402ee26af3b4.js +0 -1
  305. mage_ai/server/frontend_dist/_next/static/chunks/6333-d1f8db4e7d9656a5.js +0 -1
  306. mage_ai/server/frontend_dist/_next/static/chunks/6648-9bd31397f1d1b551.js +0 -1
  307. mage_ai/server/frontend_dist/_next/static/chunks/9161-0101571a3635a938.js +0 -1
  308. mage_ai/server/frontend_dist/_next/static/chunks/9264-7c4fcfed1200046a.js +0 -1
  309. mage_ai/server/frontend_dist/_next/static/chunks/9696-3e8ab7786f0e3a0e.js +0 -1
  310. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-976b488b8aea327f.js +0 -1
  311. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-1a6c6654bfc953ac.js +0 -1
  312. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-49004d918b04c866.js +0 -1
  313. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-97177740fbb6eb9f.js +0 -1
  314. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-5b6411c9eb8c4ba4.js +0 -1
  315. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-0a7a746cc0998608.js +0 -1
  316. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-606012a580245001.js +0 -1
  317. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-0801de3c9a2976ea.js +0 -1
  318. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-0a5865d4cf012127.js +0 -1
  319. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-87b1a0601c4236cd.js +0 -1
  320. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-77ffaa2d721a0a4e.js +0 -1
  321. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-4e72d40881ac0605.js +0 -1
  322. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-8da8f8e2fdb1c99f.js +0 -1
  323. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-be029347e99fcea2.js +0 -1
  324. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-d4b07df78b3d6037.js +0 -1
  325. mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/[...slug]-87c492e9edc6064e.js +0 -1
  326. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-2ab9f3d0c50cce81.js +0 -1
  327. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-0ba40243a030ddf4.js +0 -1
  328. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-28a3a43d65074394.js +0 -1
  329. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1769-e2efd4df8d09481f.js +0 -1
  330. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2327-2d8a1555605cf4af.js +0 -1
  331. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2369-cb9cd97052e18d27.js +0 -1
  332. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2677-aea54e655c4a727f.js +0 -1
  333. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-994e1044953f1425.js +0 -1
  334. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5597-c034402ee26af3b4.js +0 -1
  335. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-d1f8db4e7d9656a5.js +0 -1
  336. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6648-9bd31397f1d1b551.js +0 -1
  337. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9161-0101571a3635a938.js +0 -1
  338. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-7c4fcfed1200046a.js +0 -1
  339. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9696-3e8ab7786f0e3a0e.js +0 -1
  340. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-976b488b8aea327f.js +0 -1
  341. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-1a6c6654bfc953ac.js +0 -1
  342. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-49004d918b04c866.js +0 -1
  343. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-97177740fbb6eb9f.js +0 -1
  344. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-5b6411c9eb8c4ba4.js +0 -1
  345. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-0a7a746cc0998608.js +0 -1
  346. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-606012a580245001.js +0 -1
  347. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-0801de3c9a2976ea.js +0 -1
  348. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-0a5865d4cf012127.js +0 -1
  349. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-87b1a0601c4236cd.js +0 -1
  350. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-77ffaa2d721a0a4e.js +0 -1
  351. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-4e72d40881ac0605.js +0 -1
  352. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-8da8f8e2fdb1c99f.js +0 -1
  353. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-be029347e99fcea2.js +0 -1
  354. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-d4b07df78b3d6037.js +0 -1
  355. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-87c492e9edc6064e.js +0 -1
  356. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-2ab9f3d0c50cce81.js +0 -1
  357. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-0ba40243a030ddf4.js +0 -1
  358. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-28a3a43d65074394.js +0 -1
  359. mage_ai/server/frontend_dist_base_path_template/_next/static/o_Yc57jh8Te2SI-VoipGQ/_buildManifest.js +0 -1
  360. /mage_ai/server/frontend_dist/_next/static/{cbN7L4Ms6UUPoANozEh9w → PBVuphyo_muEAj347ZP_b}/_ssgManifest.js +0 -0
  361. /mage_ai/server/frontend_dist_base_path_template/_next/static/{o_Yc57jh8Te2SI-VoipGQ → L-IKw5_bRZUs-wyjnpN_j}/_ssgManifest.js +0 -0
  362. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/LICENSE +0 -0
  363. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/WHEEL +0 -0
  364. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/entry_points.txt +0 -0
  365. {mage_ai-0.9.32.dist-info → mage_ai-0.9.34.dist-info}/top_level.txt +0 -0
@@ -632,8 +632,9 @@ class BlockResource(GenericResource):
632
632
 
633
633
  block.update_content(content)
634
634
 
635
- cache = await BlockCache.initialize_cache()
636
- cache.add_pipeline(block, pipeline)
635
+ if pipeline:
636
+ cache = await BlockCache.initialize_cache()
637
+ cache.add_pipeline(block, pipeline)
637
638
 
638
639
  cache_block_action_object = await BlockActionObjectCache.initialize_cache()
639
640
  cache_block_action_object.update_block(block)
@@ -67,9 +67,9 @@ class DatabaseResource(BaseResource):
67
67
  for _col, _val in merge_dict(query, where).items():
68
68
  filters.append(self.model_class)
69
69
  return self.model_class.query.filter(
70
- **merge_dict(query, where)).all()
70
+ **merge_dict(query, where))
71
71
  else:
72
- return self.model_class.query.filter(**query).all()
72
+ return self.model_class.query.filter(**query)
73
73
 
74
74
  @classmethod
75
75
  @safe_db_query
@@ -1,12 +1,37 @@
1
1
  from mage_ai.api.resources.DatabaseResource import DatabaseResource
2
- from mage_ai.orchestration.db import safe_db_query
3
- from mage_ai.orchestration.db.models.oauth import Permission, Role
4
- from mage_ai.shared.hash import merge_dict
2
+ from mage_ai.orchestration.db import db_connection, safe_db_query
3
+ from mage_ai.orchestration.db.models.oauth import Permission, Role, RolePermission
4
+ from mage_ai.shared.hash import ignore_keys, index_by, merge_dict
5
5
 
6
6
 
7
7
  class PermissionResource(DatabaseResource):
8
8
  model_class = Permission
9
9
 
10
+ @classmethod
11
+ @safe_db_query
12
+ def collection(self, query_arg, meta, user, **kwargs):
13
+ only_entity_options = query_arg.get('only_entity_options', [False])
14
+ if only_entity_options:
15
+ only_entity_options = only_entity_options[0]
16
+
17
+ if only_entity_options:
18
+ return self.build_result_set(
19
+ [Permission()],
20
+ user,
21
+ **kwargs,
22
+ )
23
+
24
+ return super().collection(
25
+ query_arg,
26
+ meta,
27
+ user,
28
+ **kwargs,
29
+ ).order_by(
30
+ Permission.entity_name.asc(),
31
+ Permission.entity_type.asc(),
32
+ Permission.entity_id.asc(),
33
+ )
34
+
10
35
  @classmethod
11
36
  @safe_db_query
12
37
  def create(self, payload, user, **kwargs):
@@ -17,5 +42,42 @@ class PermissionResource(DatabaseResource):
17
42
  user_id=user.id if user else None,
18
43
  )), user, **kwargs)
19
44
 
45
+ @safe_db_query
46
+ def update(self, payload, **kwargs):
47
+ role_ids = [int(i) for i in payload.get('role_ids') or []]
48
+ roles_mapping = index_by(lambda x: x.id, self.roles or [])
49
+
50
+ role_ids_create = []
51
+ role_ids_delete = []
52
+
53
+ for role_id in role_ids:
54
+ if role_id not in roles_mapping:
55
+ role_ids_create.append(role_id)
56
+
57
+ for role_id in roles_mapping.keys():
58
+ if role_id not in role_ids:
59
+ role_ids_delete.append(role_id)
60
+
61
+ if role_ids_create:
62
+ db_connection.session.bulk_save_objects(
63
+ [RolePermission(
64
+ permission_id=self.model.id,
65
+ role_id=role_id,
66
+ user_id=self.current_user.id,
67
+ ) for role_id in role_ids_create],
68
+ return_defaults=True,
69
+ )
70
+
71
+ if role_ids_delete:
72
+ delete_statement = RolePermission.__table__.delete().where(
73
+ RolePermission.permission_id == self.id,
74
+ RolePermission.role_id.in_(role_ids_delete),
75
+ )
76
+ db_connection.session.execute(delete_statement)
77
+
78
+ return super().update(ignore_keys(payload, [
79
+ 'role_ids',
80
+ ]), **kwargs)
81
+
20
82
 
21
83
  PermissionResource.register_parent_model('role_id', Role)
@@ -1,6 +1,13 @@
1
1
  class Resource():
2
- def __init__(self, model, current_user, **kwargs):
2
+ def __init__(
3
+ self,
4
+ model,
5
+ current_user,
6
+ result_set_from_external=None,
7
+ **kwargs,
8
+ ):
3
9
  self.current_user = current_user
4
10
  self.model = model
5
11
  self.model_options = kwargs
6
12
  self.result_set_attr = None
13
+ self.result_set_from_external = result_set_from_external
@@ -1,9 +1,32 @@
1
1
  from mage_ai.api.resources.DatabaseResource import DatabaseResource
2
+ from mage_ai.orchestration.db import safe_db_query
2
3
  from mage_ai.orchestration.db.models.oauth import Role, RolePermission
4
+ from mage_ai.shared.hash import ignore_keys, merge_dict
3
5
 
4
6
 
5
7
  class RolePermissionResource(DatabaseResource):
6
8
  model_class = RolePermission
7
9
 
10
+ @classmethod
11
+ @safe_db_query
12
+ def create(self, payload, user, **kwargs):
13
+ payload_updated = merge_dict(payload, dict(
14
+ user_id=user.id if user else None,
15
+ ))
16
+
17
+ resources = []
18
+ if 'permission_ids' in payload_updated:
19
+ permission_ids = payload_updated.get('permission_ids') or []
20
+
21
+ for permission_id in permission_ids:
22
+ resources.append(super().create(merge_dict(
23
+ ignore_keys(payload_updated, ['permission_ids']),
24
+ dict(permission_id=permission_id),
25
+ ), user, **kwargs))
26
+
27
+ return resources[0] if len(resources) >= 1 else self(None, user, **kwargs)
28
+
29
+ return super().create(payload_updated, user, **kwargs)
30
+
8
31
 
9
32
  RolePermissionResource.register_parent_model('role_id', Role)
@@ -1,9 +1,9 @@
1
1
  from mage_ai.api.resources.DatabaseResource import DatabaseResource
2
2
  from mage_ai.data_preparation.repo_manager import get_project_uuid
3
3
  from mage_ai.orchestration.constants import Entity
4
- from mage_ai.orchestration.db import safe_db_query
5
- from mage_ai.orchestration.db.models.oauth import Role
6
- from mage_ai.shared.hash import merge_dict
4
+ from mage_ai.orchestration.db import db_connection, safe_db_query
5
+ from mage_ai.orchestration.db.models.oauth import Role, RolePermission, UserRole
6
+ from mage_ai.shared.hash import extract, ignore_keys, index_by, merge_dict
7
7
 
8
8
 
9
9
  class RoleResource(DatabaseResource):
@@ -41,6 +41,7 @@ class RoleResource(DatabaseResource):
41
41
  roles = []
42
42
  for permission in permissions:
43
43
  roles.append(permission.role)
44
+ roles = list(filter(lambda x: x, roles))
44
45
  else:
45
46
  roles = Role.query.all()
46
47
 
@@ -63,6 +64,76 @@ class RoleResource(DatabaseResource):
63
64
  @classmethod
64
65
  @safe_db_query
65
66
  def create(self, payload, user, **kwargs):
66
- return super().create(merge_dict(payload, dict(
67
+ return super().create(merge_dict(extract(payload, [
68
+ 'name',
69
+ ]), dict(
67
70
  user_id=user.id if user else None,
68
71
  )), user, **kwargs)
72
+
73
+ @safe_db_query
74
+ def update(self, payload, **kwargs):
75
+ permission_ids = [int(i) for i in payload.get('permission_ids') or []]
76
+ role_permissions_mapping = index_by(lambda x: x.id, self.role_permissions or [])
77
+
78
+ permission_ids_create = []
79
+ permission_ids_delete = []
80
+
81
+ for permission_id in permission_ids:
82
+ if permission_id not in role_permissions_mapping:
83
+ permission_ids_create.append(permission_id)
84
+
85
+ for permission_id in role_permissions_mapping.keys():
86
+ if permission_id not in permission_ids:
87
+ permission_ids_delete.append(permission_id)
88
+
89
+ if permission_ids_create:
90
+ db_connection.session.bulk_save_objects(
91
+ [RolePermission(
92
+ permission_id=permission_id,
93
+ role_id=self.model.id,
94
+ user_id=self.current_user.id,
95
+ ) for permission_id in permission_ids_create],
96
+ return_defaults=True,
97
+ )
98
+
99
+ if permission_ids_delete:
100
+ delete_statement = RolePermission.__table__.delete().where(
101
+ RolePermission.permission_id.in_(permission_ids_delete),
102
+ RolePermission.role_id == self.id,
103
+ )
104
+ db_connection.session.execute(delete_statement)
105
+
106
+ user_ids = [int(i) for i in payload.get('user_ids') or []]
107
+ user_role_mapping = index_by(lambda x: x.id, self.users or [])
108
+
109
+ user_ids_create = []
110
+ user_ids_delete = []
111
+
112
+ for permission_id in user_ids:
113
+ if permission_id not in user_role_mapping:
114
+ user_ids_create.append(permission_id)
115
+
116
+ for permission_id in user_role_mapping.keys():
117
+ if permission_id not in user_ids:
118
+ user_ids_delete.append(permission_id)
119
+
120
+ if user_ids_create:
121
+ db_connection.session.bulk_save_objects(
122
+ [UserRole(
123
+ role_id=self.model.id,
124
+ user_id=user_id,
125
+ ) for user_id in user_ids_create],
126
+ return_defaults=True,
127
+ )
128
+
129
+ if user_ids_delete:
130
+ delete_statement = UserRole.__table__.delete().where(
131
+ UserRole.role_id == self.id,
132
+ UserRole.user_id.in_(user_ids_delete),
133
+ )
134
+ db_connection.session.execute(delete_statement)
135
+
136
+ return super().update(ignore_keys(payload, [
137
+ 'permission_ids',
138
+ 'user_ids',
139
+ ]), **kwargs)
@@ -9,13 +9,16 @@ from mage_ai.data_preparation.repo_manager import (
9
9
  )
10
10
  from mage_ai.data_preparation.shared.constants import MANAGE_ENV_VAR
11
11
  from mage_ai.orchestration.db import safe_db_query
12
+ from mage_ai.orchestration.db.models.schedules import PipelineRun, PipelineSchedule
12
13
  from mage_ai.server.api.clusters import ClusterType
13
14
  from mage_ai.server.scheduler_manager import scheduler_manager
14
15
  from mage_ai.settings import (
15
16
  REQUIRE_USER_AUTHENTICATION,
17
+ REQUIRE_USER_PERMISSIONS,
16
18
  is_disable_pipeline_edit_access,
17
19
  )
18
20
  from mage_ai.settings.repo import get_repo_path
21
+ from mage_ai.shared.hash import merge_dict
19
22
 
20
23
 
21
24
  class StatusResource(GenericResource):
@@ -23,6 +26,7 @@ class StatusResource(GenericResource):
23
26
  Resource to fetch block output for the notebook. Created to support legacy
24
27
  endpoint /api/pipelines/<pipeline_uuid>/blocks/<block_uuid>/outputs
25
28
  """
29
+
26
30
  @classmethod
27
31
  @safe_db_query
28
32
  def collection(self, query, meta, user, **kwargs):
@@ -31,6 +35,7 @@ class StatusResource(GenericResource):
31
35
  GCP_PROJECT_ID,
32
36
  KUBE_NAMESPACE,
33
37
  )
38
+
34
39
  instance_type = None
35
40
  project_type = get_project_type()
36
41
  repo_config = get_repo_config()
@@ -45,6 +50,7 @@ class StatusResource(GenericResource):
45
50
  from mage_ai.cluster_manager.kubernetes.workload_manager import (
46
51
  WorkloadManager,
47
52
  )
53
+
48
54
  if WorkloadManager.load_config() or os.getenv(KUBE_NAMESPACE):
49
55
  instance_type = ClusterType.K8S
50
56
  except ModuleNotFoundError:
@@ -58,7 +64,35 @@ class StatusResource(GenericResource):
58
64
  'disable_pipeline_edit_access': is_disable_pipeline_edit_access(),
59
65
  'max_print_output_lines': MAX_PRINT_OUTPUT_LINES,
60
66
  'require_user_authentication': REQUIRE_USER_AUTHENTICATION,
67
+ 'require_user_permissions': REQUIRE_USER_PERMISSIONS,
61
68
  'project_type': project_type,
62
69
  'project_uuid': get_project_uuid(),
63
70
  }
71
+
72
+ display_format = meta.get('_format')
73
+ if 'with_activity_details' == display_format:
74
+ from mage_ai.server.server import latest_user_activity
75
+
76
+ project_schedules = PipelineSchedule.repo_query.all()
77
+ project_schedule_ids = [schedule.id for schedule in project_schedules]
78
+ project_pipeline_runs = PipelineRun.query.filter(
79
+ PipelineRun.pipeline_schedule_id.in_(project_schedule_ids)
80
+ )
81
+ sorted_pipeline_runs = project_pipeline_runs.order_by(
82
+ PipelineRun.updated_at.desc()
83
+ )
84
+ if sorted_pipeline_runs.count() > 0:
85
+ last_scheduler_activity = sorted_pipeline_runs[0].updated_at
86
+ active_pipeline_run_count = project_pipeline_runs.filter(
87
+ PipelineRun.status == PipelineRun.PipelineRunStatus.RUNNING
88
+ ).count()
89
+
90
+ activity_details = {
91
+ 'active_pipeline_run_count': active_pipeline_run_count,
92
+ 'last_scheduler_activity': last_scheduler_activity,
93
+ 'last_user_request': latest_user_activity.latest_activity,
94
+ }
95
+
96
+ status = merge_dict(status, activity_details)
97
+
64
98
  return self.build_result_set([status], user, **kwargs)
@@ -9,9 +9,9 @@ from mage_ai.authentication.passwords import (
9
9
  )
10
10
  from mage_ai.data_preparation.repo_manager import get_project_uuid
11
11
  from mage_ai.orchestration.constants import Entity
12
- from mage_ai.orchestration.db import safe_db_query
13
- from mage_ai.orchestration.db.models.oauth import Permission, Role, User
14
- from mage_ai.shared.hash import extract, ignore_keys
12
+ from mage_ai.orchestration.db import db_connection, safe_db_query
13
+ from mage_ai.orchestration.db.models.oauth import Permission, Role, User, UserRole
14
+ from mage_ai.shared.hash import extract, ignore_keys, index_by
15
15
  from mage_ai.usage_statistics.logger import UsageStatisticLogger
16
16
 
17
17
 
@@ -176,12 +176,43 @@ class UserResource(DatabaseResource):
176
176
  payload['password_hash'] = create_bcrypt_hash(password, password_salt)
177
177
  payload['password_salt'] = password_salt
178
178
 
179
+ role_ids = [int(i) for i in payload.get('role_ids') or []]
180
+ role_mapping = index_by(lambda x: x.id, self.roles_new or [])
181
+
182
+ role_ids_create = []
183
+ role_ids_delete = []
184
+
185
+ for role_id in role_ids:
186
+ if role_id not in role_mapping:
187
+ role_ids_create.append(role_id)
188
+
189
+ for role_id in role_mapping.keys():
190
+ if role_id not in role_ids:
191
+ role_ids_delete.append(role_id)
192
+
193
+ if role_ids_create:
194
+ db_connection.session.bulk_save_objects(
195
+ [UserRole(
196
+ role_id=role_id,
197
+ user_id=self.id,
198
+ ) for role_id in role_ids_create],
199
+ return_defaults=True,
200
+ )
201
+
202
+ if role_ids_delete:
203
+ delete_statement = UserRole.__table__.delete().where(
204
+ UserRole.role_id.in_(role_ids_delete),
205
+ UserRole.user_id == self.id,
206
+ )
207
+ db_connection.session.execute(delete_statement)
208
+
179
209
  return super().update(ignore_keys(payload, [
210
+ 'owner',
180
211
  'password',
181
212
  'password_confirmation',
182
213
  'password_current',
183
- 'owner',
184
214
  'project_access',
215
+ 'role_ids',
185
216
  'roles_display',
186
217
  ]), **kwargs)
187
218
 
mage_ai/api/result_set.py CHANGED
@@ -1,13 +1,20 @@
1
1
  from collections import UserList
2
+ from typing import List
3
+
2
4
  from mage_ai.api.api_context import ApiContext
3
5
  from mage_ai.api.resources.Resource import Resource
4
6
 
5
7
 
6
8
  class ResultSet(UserList):
7
- def __init__(self, results):
9
+ def __init__(self, results: List[Resource] = None):
8
10
  self.context = ApiContext()
9
11
  self.data = []
10
12
  self.metadata = {}
13
+
14
+ if results is not None:
15
+ self.add_results(results)
16
+
17
+ def add_results(self, results: List[Resource]) -> None:
11
18
  for r in results:
12
19
  if issubclass(r.__class__, Resource):
13
20
  key = r.__class__.__name__
@@ -4,6 +4,8 @@ from mage_ai.data_preparation.models.constants import BlockType, PipelineType
4
4
 
5
5
 
6
6
  class EntityName(str, Enum):
7
+ ALL = 'ALL'
8
+ ALL_EXCEPT_RESERVED = 'ALL_EXCEPT_RESERVED'
7
9
  AutocompleteItem = 'AutocompleteItem'
8
10
  Backfill = 'Backfill'
9
11
  Block = 'Block'
@@ -67,6 +69,14 @@ class EntityName(str, Enum):
67
69
  Workspace = 'Workspace'
68
70
 
69
71
 
72
+ RESERVED_ENTITY_NAMES = [
73
+ EntityName.Oauth,
74
+ EntityName.OauthAccessToken,
75
+ EntityName.OauthApplication,
76
+ EntityName.Workspace,
77
+ ]
78
+
79
+
70
80
  class BaseEntityType(str, Enum):
71
81
  pass
72
82
 
@@ -93,3 +103,71 @@ class PipelineEntityType(BaseEntityType):
93
103
  PYTHON = PipelineType.PYTHON.value
94
104
  PYSPARK = PipelineType.PYSPARK.value
95
105
  STREAMING = PipelineType.STREAMING.value
106
+
107
+
108
+ class PermissionAccess(int, Enum):
109
+ OWNER = 1
110
+ ADMIN = 2
111
+ # Editor: list, detail, create, update, delete
112
+ EDITOR = 4
113
+ # Viewer: list, detail
114
+ VIEWER = 8
115
+ LIST = 16
116
+ DETAIL = 32
117
+ CREATE = 64
118
+ UPDATE = 128
119
+ DELETE = 512
120
+ # Operation all will allow user to perform list, detail, create, update, delete
121
+ # but doesn’t include granting access for query, read, and write attributes.
122
+ # Query, read, and write will still need to be manually granted.
123
+ OPERATION_ALL = 1024
124
+ QUERY = 2048
125
+ QUERY_ALL = 4096
126
+ READ = 8192
127
+ READ_ALL = 16384
128
+ WRITE = 32768
129
+ WRITE_ALL = 65536
130
+ # All will allow operation all, query all, read all, and write all.
131
+ ALL = 131072
132
+ DISABLE_LIST = 262144
133
+ DISABLE_DETAIL = 524288
134
+ DISABLE_CREATE = 1048576
135
+ DISABLE_UPDATE = 2097152
136
+ DISABLE_DELETE = 4194304
137
+ # Disable all operations: list, detail, create, update, delete.
138
+ DISABLE_OPERATION_ALL = 8388608
139
+ DISABLE_QUERY = 16777216
140
+ DISABLE_QUERY_ALL = 33554432
141
+ DISABLE_READ = 67108864
142
+ DISABLE_READ_ALL = 134217728
143
+ DISABLE_WRITE = 268435456
144
+ DISABLE_WRITE_ALL = 536870912
145
+
146
+
147
+ ACCESS_FOR_VIEWER = [
148
+ PermissionAccess.DETAIL,
149
+ PermissionAccess.LIST,
150
+ PermissionAccess.READ,
151
+ PermissionAccess.VIEWER,
152
+ ]
153
+ ACCESS_FOR_EDITOR = ACCESS_FOR_VIEWER + [
154
+ PermissionAccess.CREATE,
155
+ PermissionAccess.DELETE,
156
+ PermissionAccess.EDITOR,
157
+ PermissionAccess.QUERY,
158
+ PermissionAccess.UPDATE,
159
+ PermissionAccess.WRITE,
160
+ ]
161
+ ACCESS_FOR_ADMIN = ACCESS_FOR_VIEWER + ACCESS_FOR_EDITOR + [
162
+ PermissionAccess.ADMIN,
163
+ ]
164
+ ACCESS_FOR_OWNER = ACCESS_FOR_ADMIN + [
165
+ PermissionAccess.OWNER,
166
+ ]
167
+
168
+ PERMISSION_ACCESS_WITH_MULTIPLE_ACCESS = {
169
+ f'{PermissionAccess.ADMIN}': ACCESS_FOR_ADMIN,
170
+ f'{PermissionAccess.EDITOR}': ACCESS_FOR_EDITOR,
171
+ f'{PermissionAccess.OWNER}': ACCESS_FOR_OWNER,
172
+ f'{PermissionAccess.VIEWER}': ACCESS_FOR_VIEWER,
173
+ }
@@ -11,6 +11,7 @@ DESTINATIONS = [
11
11
  uuid='mssql',
12
12
  ),
13
13
  dict(name='MySQL'),
14
+ dict(name='Opensearch'),
14
15
  dict(name='OracleDB'),
15
16
  dict(name='PostgreSQL'),
16
17
  dict(name='Redshift'),
@@ -57,6 +57,15 @@ def __get_settings(absolute_file_path, variables: Dict = None, pipeline=None) ->
57
57
  return settings
58
58
 
59
59
 
60
+ def get_batch_fetch_limit(source_config: Dict):
61
+ from mage_integrations.sources.constants import (
62
+ BATCH_FETCH_LIMIT,
63
+ BATCH_FETCH_LIMIT_KEY,
64
+ )
65
+
66
+ return source_config.get(BATCH_FETCH_LIMIT_KEY, BATCH_FETCH_LIMIT)
67
+
68
+
60
69
  def get_catalog(block, variables: Dict = None, pipeline=None) -> Dict:
61
70
  return get_settings(block, variables or {}, pipeline=pipeline)['catalog']
62
71
 
@@ -5,6 +5,7 @@ import shutil
5
5
  from typing import Dict, List, Union
6
6
 
7
7
  from mage_ai.data_integrations.sources.constants import SQL_SOURCES
8
+ from mage_ai.data_integrations.utils.config import build_config, get_batch_fetch_limit
8
9
  from mage_ai.data_preparation.logging.logger import DictLogger
9
10
  from mage_ai.data_preparation.models.block.data_integration.constants import (
10
11
  MAX_QUERY_STRING_SIZE,
@@ -73,7 +74,7 @@ def initialize_state_and_runs(
73
74
  try:
74
75
  update_stream_states(pipeline_run, logger, variables)
75
76
 
76
- block_runs = create_block_runs(pipeline_run, logger)
77
+ block_runs = create_block_runs(pipeline_run, logger, variables=variables)
77
78
 
78
79
  calculate_metrics(pipeline_run, logger=logger, logging_tags=tags)
79
80
 
@@ -90,8 +91,13 @@ def initialize_state_and_runs(
90
91
  raise err
91
92
 
92
93
 
93
- def create_block_runs(pipeline_run: PipelineRun, logger: DictLogger) -> List[BlockRun]:
94
- from mage_integrations.sources.constants import BATCH_FETCH_LIMIT
94
+ def create_block_runs(
95
+ pipeline_run: PipelineRun,
96
+ logger: DictLogger,
97
+ variables: Dict = None,
98
+ ) -> List[BlockRun]:
99
+ if variables is None:
100
+ variables = dict()
95
101
 
96
102
  integration_pipeline = IntegrationPipeline.get(pipeline_run.pipeline_uuid)
97
103
 
@@ -116,6 +122,10 @@ def create_block_runs(pipeline_run: PipelineRun, logger: DictLogger) -> List[Blo
116
122
  raise Exception("No Destination Block was found. \
117
123
  Mage expects 1 Source and 1 Destination Block")
118
124
 
125
+ # Get batch fetch limit
126
+ source_config, _ = build_config(data_loader_block.file_path, variables)
127
+ batch_fetch_limit = get_batch_fetch_limit(source_config)
128
+
119
129
  transformer_blocks = [b for b in executable_blocks if b.uuid not in [
120
130
  data_loader_block.uuid,
121
131
  data_exporter_block.uuid,
@@ -139,7 +149,7 @@ def create_block_runs(pipeline_run: PipelineRun, logger: DictLogger) -> List[Blo
139
149
  record_counts = None
140
150
  if is_sql_source:
141
151
  record_counts = record_counts_by_stream[tap_stream_id]['count']
142
- number_of_batches = math.ceil((record_counts or 1) / BATCH_FETCH_LIMIT)
152
+ number_of_batches = math.ceil((record_counts or 1) / batch_fetch_limit)
143
153
  tags2 = merge_dict(tags, dict(
144
154
  number_of_batches=number_of_batches,
145
155
  record_counts=record_counts,
@@ -372,12 +382,11 @@ def __build_block_run_metadata_for_source(
372
382
  logging_tags: Dict = None,
373
383
  selected_streams: List[str] = None,
374
384
  ) -> List[Dict]:
375
- from mage_integrations.sources.constants import BATCH_FETCH_LIMIT
376
-
377
385
  block_run_metadata = []
378
386
 
379
387
  catalog = data_integration_settings.get('catalog')
380
388
  config = data_integration_settings.get('config')
389
+ batch_fetch_limit = get_batch_fetch_limit(config)
381
390
 
382
391
  streams = selected_streams or \
383
392
  [s.get('tap_stream_id') for s in get_selected_streams(catalog)]
@@ -405,7 +414,7 @@ def __build_block_run_metadata_for_source(
405
414
  record_counts = None
406
415
  if is_sql_source:
407
416
  record_counts = record_counts_by_stream[tap_stream_id]['count']
408
- number_of_batches = math.ceil((record_counts or 1) / BATCH_FETCH_LIMIT)
417
+ number_of_batches = math.ceil((record_counts or 1) / batch_fetch_limit)
409
418
  tags2 = merge_dict(tags, dict(
410
419
  number_of_batches=number_of_batches,
411
420
  record_counts=record_counts,