zenml-nightly 0.75.0.dev20250311__py3-none-any.whl → 0.75.0.dev20250313__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 (163) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/artifacts/utils.py +0 -2
  5. zenml/cli/login.py +6 -0
  6. zenml/cli/model.py +7 -15
  7. zenml/cli/secret.py +47 -44
  8. zenml/cli/service_connectors.py +0 -1
  9. zenml/cli/stack.py +0 -1
  10. zenml/cli/tag.py +3 -5
  11. zenml/cli/utils.py +25 -23
  12. zenml/cli/workspace.py +79 -5
  13. zenml/client.py +618 -348
  14. zenml/config/global_config.py +16 -3
  15. zenml/config/pipeline_configurations.py +3 -2
  16. zenml/config/pipeline_run_configuration.py +2 -1
  17. zenml/config/secret_reference_mixin.py +1 -1
  18. zenml/constants.py +1 -3
  19. zenml/enums.py +0 -7
  20. zenml/event_hub/event_hub.py +3 -1
  21. zenml/exceptions.py +0 -24
  22. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  23. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  24. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  25. zenml/integrations/mlflow/steps/mlflow_registry.py +1 -1
  26. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  27. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +3 -3
  28. zenml/model/model.py +8 -8
  29. zenml/models/__init__.py +18 -1
  30. zenml/models/v2/base/base.py +0 -5
  31. zenml/models/v2/base/filter.py +1 -1
  32. zenml/models/v2/base/scoped.py +104 -121
  33. zenml/models/v2/core/api_key.py +1 -1
  34. zenml/models/v2/core/artifact.py +31 -18
  35. zenml/models/v2/core/artifact_version.py +42 -25
  36. zenml/models/v2/core/component.py +22 -33
  37. zenml/models/v2/core/device.py +3 -2
  38. zenml/models/v2/core/event_source.py +2 -2
  39. zenml/models/v2/core/flavor.py +19 -47
  40. zenml/models/v2/core/logs.py +1 -2
  41. zenml/models/v2/core/model.py +7 -4
  42. zenml/models/v2/core/model_version.py +36 -27
  43. zenml/models/v2/core/pipeline.py +1 -1
  44. zenml/models/v2/core/pipeline_build.py +18 -0
  45. zenml/models/v2/core/pipeline_run.py +5 -13
  46. zenml/models/v2/core/run_template.py +1 -2
  47. zenml/models/v2/core/schedule.py +0 -9
  48. zenml/models/v2/core/secret.py +93 -127
  49. zenml/models/v2/core/server_settings.py +2 -2
  50. zenml/models/v2/core/service.py +43 -12
  51. zenml/models/v2/core/service_connector.py +14 -16
  52. zenml/models/v2/core/stack.py +24 -26
  53. zenml/models/v2/core/step_run.py +3 -15
  54. zenml/models/v2/core/tag.py +41 -15
  55. zenml/models/v2/core/user.py +19 -2
  56. zenml/models/v2/misc/statistics.py +45 -0
  57. zenml/models/v2/misc/tag.py +27 -0
  58. zenml/orchestrators/cache_utils.py +1 -1
  59. zenml/orchestrators/input_utils.py +1 -0
  60. zenml/orchestrators/step_launcher.py +0 -1
  61. zenml/orchestrators/step_run_utils.py +0 -2
  62. zenml/orchestrators/step_runner.py +10 -1
  63. zenml/pipelines/build_utils.py +4 -2
  64. zenml/pipelines/pipeline_decorator.py +3 -2
  65. zenml/pipelines/pipeline_definition.py +4 -5
  66. zenml/pipelines/run_utils.py +3 -3
  67. zenml/service_connectors/service_connector.py +0 -7
  68. zenml/service_connectors/service_connector_utils.py +0 -1
  69. zenml/stack/authentication_mixin.py +1 -1
  70. zenml/stack/flavor.py +3 -14
  71. zenml/stack/stack_component.py +1 -5
  72. zenml/steps/step_context.py +19 -0
  73. zenml/utils/string_utils.py +1 -1
  74. zenml/utils/tag_utils.py +642 -0
  75. zenml/zen_server/cloud_utils.py +21 -0
  76. zenml/zen_server/exceptions.py +0 -6
  77. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  78. zenml/zen_server/rbac/models.py +65 -3
  79. zenml/zen_server/rbac/rbac_interface.py +9 -0
  80. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  81. zenml/zen_server/rbac/utils.py +156 -29
  82. zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -11
  83. zenml/zen_server/routers/actions_endpoints.py +3 -5
  84. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  85. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  86. zenml/zen_server/routers/auth_endpoints.py +22 -7
  87. zenml/zen_server/routers/code_repositories_endpoints.py +56 -3
  88. zenml/zen_server/routers/devices_endpoints.py +0 -4
  89. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  90. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  91. zenml/zen_server/routers/logs_endpoints.py +0 -1
  92. zenml/zen_server/routers/model_versions_endpoints.py +102 -23
  93. zenml/zen_server/routers/models_endpoints.py +51 -68
  94. zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
  95. zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
  96. zenml/zen_server/routers/pipelines_endpoints.py +73 -4
  97. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  98. zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
  99. zenml/zen_server/routers/run_templates_endpoints.py +66 -3
  100. zenml/zen_server/routers/runs_endpoints.py +60 -8
  101. zenml/zen_server/routers/schedule_endpoints.py +69 -6
  102. zenml/zen_server/routers/secrets_endpoints.py +40 -4
  103. zenml/zen_server/routers/server_endpoints.py +53 -1
  104. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  105. zenml/zen_server/routers/service_connectors_endpoints.py +96 -14
  106. zenml/zen_server/routers/service_endpoints.py +20 -7
  107. zenml/zen_server/routers/stack_components_endpoints.py +68 -7
  108. zenml/zen_server/routers/stacks_endpoints.py +98 -7
  109. zenml/zen_server/routers/steps_endpoints.py +17 -11
  110. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  111. zenml/zen_server/routers/tags_endpoints.py +6 -17
  112. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  113. zenml/zen_server/routers/users_endpoints.py +47 -12
  114. zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
  115. zenml/zen_server/template_execution/utils.py +5 -4
  116. zenml/zen_server/utils.py +21 -0
  117. zenml/zen_server/zen_server_api.py +4 -0
  118. zenml/zen_stores/base_zen_store.py +29 -44
  119. zenml/zen_stores/migrations/versions/0392807467dc_add_build_duration.py +34 -0
  120. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  121. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  122. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  123. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  124. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  125. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  126. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  127. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  128. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  129. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  130. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  131. zenml/zen_stores/rest_zen_store.py +172 -171
  132. zenml/zen_stores/schemas/action_schemas.py +8 -1
  133. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  134. zenml/zen_stores/schemas/artifact_schemas.py +28 -1
  135. zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
  136. zenml/zen_stores/schemas/component_schemas.py +9 -14
  137. zenml/zen_stores/schemas/event_source_schemas.py +8 -1
  138. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  139. zenml/zen_stores/schemas/model_schemas.py +3 -0
  140. zenml/zen_stores/schemas/pipeline_build_schemas.py +4 -0
  141. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
  142. zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
  143. zenml/zen_stores/schemas/run_template_schemas.py +8 -4
  144. zenml/zen_stores/schemas/schedule_schema.py +9 -14
  145. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  146. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  147. zenml/zen_stores/schemas/service_schemas.py +0 -1
  148. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  149. zenml/zen_stores/schemas/step_run_schemas.py +7 -8
  150. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  151. zenml/zen_stores/schemas/trigger_schemas.py +8 -1
  152. zenml/zen_stores/schemas/user_schemas.py +24 -2
  153. zenml/zen_stores/schemas/utils.py +16 -0
  154. zenml/zen_stores/schemas/workspace_schemas.py +7 -25
  155. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  156. zenml/zen_stores/sql_zen_store.py +2905 -2280
  157. zenml/zen_stores/template_utils.py +1 -1
  158. zenml/zen_stores/zen_store_interface.py +82 -58
  159. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
  160. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +163 -149
  161. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
  162. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
  163. {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
@@ -13,12 +13,19 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for stacks."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
19
20
 
20
21
  from zenml.constants import API, STACKS, VERSION_1
21
- from zenml.models import Page, StackFilter, StackResponse, StackUpdate
22
+ from zenml.models import (
23
+ Page,
24
+ StackFilter,
25
+ StackRequest,
26
+ StackResponse,
27
+ StackUpdate,
28
+ )
22
29
  from zenml.zen_server.auth import AuthContext, authorize
23
30
  from zenml.zen_server.exceptions import error_response
24
31
  from zenml.zen_server.rbac.endpoint_utils import (
@@ -28,7 +35,14 @@ from zenml.zen_server.rbac.endpoint_utils import (
28
35
  verify_permissions_and_update_entity,
29
36
  )
30
37
  from zenml.zen_server.rbac.models import Action, ResourceType
31
- from zenml.zen_server.rbac.utils import batch_verify_permissions_for_models
38
+ from zenml.zen_server.rbac.utils import (
39
+ batch_verify_permissions_for_models,
40
+ verify_permission,
41
+ verify_permission_for_model,
42
+ )
43
+ from zenml.zen_server.routers.workspaces_endpoints import (
44
+ router as workspace_router,
45
+ )
32
46
  from zenml.zen_server.utils import (
33
47
  handle_exceptions,
34
48
  make_dependable,
@@ -42,27 +56,106 @@ router = APIRouter(
42
56
  )
43
57
 
44
58
 
59
+ @router.post(
60
+ "",
61
+ responses={401: error_response, 409: error_response, 422: error_response},
62
+ )
63
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
64
+ # and can be removed after the migration
65
+ @workspace_router.post(
66
+ "/{workspace_name_or_id}" + STACKS,
67
+ responses={401: error_response, 409: error_response, 422: error_response},
68
+ deprecated=True,
69
+ tags=["stacks"],
70
+ )
71
+ @handle_exceptions
72
+ def create_stack(
73
+ stack: StackRequest,
74
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
75
+ auth_context: AuthContext = Security(authorize),
76
+ ) -> StackResponse:
77
+ """Creates a stack, optionally in a specific workspace.
78
+
79
+ Args:
80
+ stack: Stack to register.
81
+ workspace_name_or_id: Optional name or ID of the workspace.
82
+ auth_context: Authentication context.
83
+
84
+ Returns:
85
+ The created stack.
86
+ """
87
+ # Check the service connector creation
88
+ is_connector_create_needed = False
89
+ for connector_id_or_info in stack.service_connectors:
90
+ if isinstance(connector_id_or_info, UUID):
91
+ service_connector = zen_store().get_service_connector(
92
+ connector_id_or_info, hydrate=False
93
+ )
94
+ verify_permission_for_model(
95
+ model=service_connector, action=Action.READ
96
+ )
97
+ else:
98
+ is_connector_create_needed = True
99
+
100
+ # Check the component creation
101
+ if is_connector_create_needed:
102
+ verify_permission(
103
+ resource_type=ResourceType.SERVICE_CONNECTOR, action=Action.CREATE
104
+ )
105
+ is_component_create_needed = False
106
+ for components in stack.components.values():
107
+ for component_id_or_info in components:
108
+ if isinstance(component_id_or_info, UUID):
109
+ component = zen_store().get_stack_component(
110
+ component_id_or_info, hydrate=False
111
+ )
112
+ verify_permission_for_model(
113
+ model=component, action=Action.READ
114
+ )
115
+ else:
116
+ is_component_create_needed = True
117
+ if is_component_create_needed:
118
+ verify_permission(
119
+ resource_type=ResourceType.STACK_COMPONENT,
120
+ action=Action.CREATE,
121
+ )
122
+
123
+ # Check the stack creation
124
+ verify_permission_for_model(model=stack, action=Action.CREATE)
125
+
126
+ return zen_store().create_stack(stack)
127
+
128
+
45
129
  @router.get(
46
130
  "",
47
- response_model=Page[StackResponse],
48
131
  responses={401: error_response, 404: error_response, 422: error_response},
49
132
  )
133
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
134
+ # and can be removed after the migration
135
+ @workspace_router.get(
136
+ "/{workspace_name_or_id}" + STACKS,
137
+ responses={401: error_response, 404: error_response, 422: error_response},
138
+ deprecated=True,
139
+ tags=["stacks"],
140
+ )
50
141
  @handle_exceptions
51
142
  def list_stacks(
143
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
52
144
  stack_filter_model: StackFilter = Depends(make_dependable(StackFilter)),
53
145
  hydrate: bool = False,
54
146
  _: AuthContext = Security(authorize),
55
147
  ) -> Page[StackResponse]:
56
- """Returns all stacks.
148
+ """Returns all stacks, optionally filtered by workspace.
57
149
 
58
150
  Args:
151
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
59
152
  stack_filter_model: Filter model used for pagination, sorting,
60
153
  filtering.
61
154
  hydrate: Flag deciding whether to hydrate the output model(s)
62
155
  by including metadata fields in the response.
63
156
 
64
157
  Returns:
65
- All stacks.
158
+ All stacks matching the filter criteria.
66
159
  """
67
160
  return verify_permissions_and_list_entities(
68
161
  filter_model=stack_filter_model,
@@ -74,7 +167,6 @@ def list_stacks(
74
167
 
75
168
  @router.get(
76
169
  "/{stack_id}",
77
- response_model=StackResponse,
78
170
  responses={401: error_response, 404: error_response, 422: error_response},
79
171
  )
80
172
  @handle_exceptions
@@ -100,7 +192,6 @@ def get_stack(
100
192
 
101
193
  @router.put(
102
194
  "/{stack_id}",
103
- response_model=StackResponse,
104
195
  responses={401: error_response, 404: error_response, 422: error_response},
105
196
  )
106
197
  @handle_exceptions
@@ -37,6 +37,9 @@ from zenml.models import (
37
37
  )
38
38
  from zenml.zen_server.auth import AuthContext, authorize
39
39
  from zenml.zen_server.exceptions import error_response
40
+ from zenml.zen_server.rbac.endpoint_utils import (
41
+ verify_permissions_and_create_entity,
42
+ )
40
43
  from zenml.zen_server.rbac.models import Action, ResourceType
41
44
  from zenml.zen_server.rbac.utils import (
42
45
  dehydrate_page,
@@ -47,6 +50,7 @@ from zenml.zen_server.rbac.utils import (
47
50
  from zenml.zen_server.utils import (
48
51
  handle_exceptions,
49
52
  make_dependable,
53
+ set_filter_workspace_scope,
50
54
  zen_store,
51
55
  )
52
56
 
@@ -59,7 +63,6 @@ router = APIRouter(
59
63
 
60
64
  @router.get(
61
65
  "",
62
- response_model=Page[StepRunResponse],
63
66
  responses={401: error_response, 404: error_response, 422: error_response},
64
67
  )
65
68
  @handle_exceptions
@@ -82,8 +85,14 @@ def list_run_steps(
82
85
  Returns:
83
86
  The run steps according to query filters.
84
87
  """
88
+ # A workspace scoped request must always be scoped to a specific
89
+ # workspace. This is required for the RBAC check to work.
90
+ set_filter_workspace_scope(step_run_filter_model)
91
+ assert isinstance(step_run_filter_model.workspace, UUID)
92
+
85
93
  allowed_pipeline_run_ids = get_allowed_resource_ids(
86
- resource_type=ResourceType.PIPELINE_RUN
94
+ resource_type=ResourceType.PIPELINE_RUN,
95
+ workspace_id=step_run_filter_model.workspace,
87
96
  )
88
97
  step_run_filter_model.configure_rbac(
89
98
  authenticated_user_id=auth_context.user.id,
@@ -98,7 +107,6 @@ def list_run_steps(
98
107
 
99
108
  @router.post(
100
109
  "",
101
- response_model=StepRunResponse,
102
110
  responses={401: error_response, 409: error_response, 422: error_response},
103
111
  )
104
112
  @handle_exceptions
@@ -110,20 +118,22 @@ def create_run_step(
110
118
 
111
119
  Args:
112
120
  step: The run step to create.
121
+ _: Authentication context.
113
122
 
114
123
  Returns:
115
124
  The created run step.
116
125
  """
117
126
  pipeline_run = zen_store().get_run(step.pipeline_run_id)
118
- verify_permission_for_model(pipeline_run, action=Action.UPDATE)
119
127
 
120
- step_response = zen_store().create_run_step(step_run=step)
121
- return dehydrate_response_model(step_response)
128
+ return verify_permissions_and_create_entity(
129
+ request_model=step,
130
+ create_method=zen_store().create_run_step,
131
+ surrogate_models=[pipeline_run],
132
+ )
122
133
 
123
134
 
124
135
  @router.get(
125
136
  "/{step_id}",
126
- response_model=StepRunResponse,
127
137
  responses={401: error_response, 404: error_response, 422: error_response},
128
138
  )
129
139
  @handle_exceptions
@@ -157,7 +167,6 @@ def get_step(
157
167
 
158
168
  @router.put(
159
169
  "/{step_id}",
160
- response_model=StepRunResponse,
161
170
  responses={401: error_response, 404: error_response, 422: error_response},
162
171
  )
163
172
  @handle_exceptions
@@ -187,7 +196,6 @@ def update_step(
187
196
 
188
197
  @router.get(
189
198
  "/{step_id}" + STEP_CONFIGURATION,
190
- response_model=Dict[str, Any],
191
199
  responses={401: error_response, 404: error_response, 422: error_response},
192
200
  )
193
201
  @handle_exceptions
@@ -212,7 +220,6 @@ def get_step_configuration(
212
220
 
213
221
  @router.get(
214
222
  "/{step_id}" + STATUS,
215
- response_model=ExecutionStatus,
216
223
  responses={401: error_response, 404: error_response, 422: error_response},
217
224
  )
218
225
  @handle_exceptions
@@ -237,7 +244,6 @@ def get_step_status(
237
244
 
238
245
  @router.get(
239
246
  "/{step_id}" + LOGS,
240
- response_model=str,
241
247
  responses={401: error_response, 404: error_response, 422: error_response},
242
248
  )
243
249
  @handle_exceptions
@@ -0,0 +1,115 @@
1
+ # Copyright (c) ZenML GmbH 2023. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at:
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12
+ # or implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+ """Endpoint definitions for the link between tags and resources."""
15
+
16
+ from typing import List
17
+
18
+ from fastapi import APIRouter, Security
19
+
20
+ from zenml.constants import (
21
+ API,
22
+ BATCH,
23
+ TAG_RESOURCES,
24
+ VERSION_1,
25
+ )
26
+ from zenml.models import TagResourceRequest, TagResourceResponse
27
+ from zenml.zen_server.auth import AuthContext, authorize
28
+ from zenml.zen_server.exceptions import error_response
29
+ from zenml.zen_server.utils import (
30
+ handle_exceptions,
31
+ zen_store,
32
+ )
33
+
34
+ router = APIRouter(
35
+ prefix=API + VERSION_1 + TAG_RESOURCES,
36
+ tags=["tag_resources"],
37
+ responses={401: error_response, 403: error_response},
38
+ )
39
+
40
+
41
+ @router.post(
42
+ "",
43
+ responses={401: error_response, 404: error_response, 422: error_response},
44
+ )
45
+ @handle_exceptions
46
+ def create_tag_resource(
47
+ tag_resource: TagResourceRequest,
48
+ _: AuthContext = Security(authorize),
49
+ ) -> TagResourceResponse:
50
+ """Attach different tags to different resources.
51
+
52
+ Args:
53
+ tag_resource: A tag resource request.
54
+
55
+ Returns:
56
+ A tag resource response.
57
+ """
58
+ return zen_store().create_tag_resource(tag_resource=tag_resource)
59
+
60
+
61
+ @router.post(
62
+ BATCH,
63
+ responses={401: error_response, 409: error_response, 422: error_response},
64
+ )
65
+ @handle_exceptions
66
+ def batch_create_tag_resource(
67
+ tag_resources: List[TagResourceRequest],
68
+ _: AuthContext = Security(authorize),
69
+ ) -> List[TagResourceResponse]:
70
+ """Attach different tags to different resources.
71
+
72
+ Args:
73
+ tag_resources: A list of tag resource requests.
74
+
75
+ Returns:
76
+ A list of tag resource responses.
77
+ """
78
+ return [
79
+ zen_store().create_tag_resource(tag_resource=tag_resource)
80
+ for tag_resource in tag_resources
81
+ ]
82
+
83
+
84
+ @router.delete(
85
+ "",
86
+ responses={401: error_response, 404: error_response, 422: error_response},
87
+ )
88
+ @handle_exceptions
89
+ def delete_tag_resource(
90
+ tag_resource: TagResourceRequest,
91
+ _: AuthContext = Security(authorize),
92
+ ) -> None:
93
+ """Detach a tag from a resource.
94
+
95
+ Args:
96
+ tag_resource: The tag resource relationship to delete.
97
+ """
98
+ zen_store().delete_tag_resource(tag_resource=tag_resource)
99
+
100
+
101
+ @router.delete(
102
+ BATCH,
103
+ responses={401: error_response, 404: error_response, 422: error_response},
104
+ )
105
+ @handle_exceptions
106
+ def batch_delete_tag_resource(
107
+ tag_resources: List[TagResourceRequest],
108
+ _: AuthContext = Security(authorize),
109
+ ) -> None:
110
+ """Detach different tags from different resources.
111
+
112
+ Args:
113
+ tag_resources: A list of tag resource requests.
114
+ """
115
+ zen_store().batch_delete_tag_resource(tag_resources=tag_resources)
@@ -33,13 +33,10 @@ from zenml.models import (
33
33
  from zenml.zen_server.auth import AuthContext, authorize
34
34
  from zenml.zen_server.exceptions import error_response
35
35
  from zenml.zen_server.rbac.endpoint_utils import (
36
- verify_permissions_and_create_entity,
37
36
  verify_permissions_and_delete_entity,
38
37
  verify_permissions_and_get_entity,
39
- verify_permissions_and_list_entities,
40
38
  verify_permissions_and_update_entity,
41
39
  )
42
- from zenml.zen_server.rbac.models import ResourceType
43
40
  from zenml.zen_server.utils import (
44
41
  handle_exceptions,
45
42
  make_dependable,
@@ -59,7 +56,6 @@ router = APIRouter(
59
56
 
60
57
  @router.post(
61
58
  "",
62
- response_model=TagResponse,
63
59
  responses={401: error_response, 409: error_response, 422: error_response},
64
60
  )
65
61
  @handle_exceptions
@@ -75,16 +71,11 @@ def create_tag(
75
71
  Returns:
76
72
  The created tag.
77
73
  """
78
- return verify_permissions_and_create_entity(
79
- request_model=tag,
80
- resource_type=ResourceType.TAG,
81
- create_method=zen_store().create_tag,
82
- )
74
+ return zen_store().create_tag(tag=tag)
83
75
 
84
76
 
85
77
  @router.get(
86
78
  "",
87
- response_model=Page[TagResponse],
88
79
  responses={401: error_response, 404: error_response, 422: error_response},
89
80
  )
90
81
  @handle_exceptions
@@ -104,17 +95,14 @@ def list_tags(
104
95
  Returns:
105
96
  The tags according to query filters.
106
97
  """
107
- return verify_permissions_and_list_entities(
108
- filter_model=tag_filter_model,
109
- resource_type=ResourceType.TAG,
110
- list_method=zen_store().list_tags,
98
+ return zen_store().list_tags(
99
+ tag_filter_model=tag_filter_model,
111
100
  hydrate=hydrate,
112
101
  )
113
102
 
114
103
 
115
104
  @router.get(
116
105
  "/{tag_name_or_id}",
117
- response_model=TagResponse,
118
106
  responses={401: error_response, 404: error_response, 422: error_response},
119
107
  )
120
108
  @handle_exceptions
@@ -134,13 +122,14 @@ def get_tag(
134
122
  The tag with the given name or ID.
135
123
  """
136
124
  return verify_permissions_and_get_entity(
137
- id=tag_name_or_id, get_method=zen_store().get_tag, hydrate=hydrate
125
+ id=tag_name_or_id,
126
+ get_method=zen_store().get_tag,
127
+ hydrate=hydrate,
138
128
  )
139
129
 
140
130
 
141
131
  @router.put(
142
132
  "/{tag_id}",
143
- response_model=TagResponse,
144
133
  responses={401: error_response, 404: error_response, 422: error_response},
145
134
  )
146
135
  @handle_exceptions
@@ -58,7 +58,6 @@ router = APIRouter(
58
58
 
59
59
  @router.get(
60
60
  "",
61
- response_model=Page[TriggerResponse],
62
61
  responses={401: error_response, 404: error_response, 422: error_response},
63
62
  )
64
63
  @handle_exceptions
@@ -90,7 +89,6 @@ def list_triggers(
90
89
 
91
90
  @router.get(
92
91
  "/{trigger_id}",
93
- response_model=TriggerResponse,
94
92
  responses={401: error_response, 404: error_response, 422: error_response},
95
93
  )
96
94
  @handle_exceptions
@@ -116,7 +114,6 @@ def get_trigger(
116
114
 
117
115
  @router.post(
118
116
  "",
119
- response_model=TriggerResponse,
120
117
  responses={401: error_response, 409: error_response, 422: error_response},
121
118
  )
122
119
  @handle_exceptions
@@ -162,14 +159,12 @@ def create_trigger(
162
159
 
163
160
  return verify_permissions_and_create_entity(
164
161
  request_model=trigger,
165
- resource_type=ResourceType.TRIGGER,
166
162
  create_method=zen_store().create_trigger,
167
163
  )
168
164
 
169
165
 
170
166
  @router.put(
171
167
  "/{trigger_id}",
172
- response_model=TriggerResponse,
173
168
  responses={401: error_response, 404: error_response, 422: error_response},
174
169
  )
175
170
  @handle_exceptions
@@ -245,9 +240,11 @@ def delete_trigger(
245
240
  Args:
246
241
  trigger_id: Name of the trigger.
247
242
  """
248
- trigger = zen_store().get_trigger(trigger_id=trigger_id)
249
- verify_permission_for_model(trigger, action=Action.DELETE)
250
- zen_store().delete_trigger(trigger_id=trigger_id)
243
+ verify_permissions_and_delete_entity(
244
+ id=trigger_id,
245
+ get_method=zen_store().get_trigger,
246
+ delete_method=zen_store().delete_trigger,
247
+ )
251
248
 
252
249
 
253
250
  executions_router = APIRouter(
@@ -38,6 +38,7 @@ from zenml.models import (
38
38
  UserRequest,
39
39
  UserResponse,
40
40
  UserUpdate,
41
+ WorkspaceScopedResponse,
41
42
  )
42
43
  from zenml.zen_server.auth import (
43
44
  AuthContext,
@@ -46,6 +47,9 @@ from zenml.zen_server.auth import (
46
47
  )
47
48
  from zenml.zen_server.exceptions import error_response
48
49
  from zenml.zen_server.rate_limit import RequestLimiter
50
+ from zenml.zen_server.rbac.endpoint_utils import (
51
+ verify_permissions_and_get_entity,
52
+ )
49
53
  from zenml.zen_server.rbac.models import Action, Resource, ResourceType
50
54
  from zenml.zen_server.rbac.utils import (
51
55
  dehydrate_page,
@@ -87,7 +91,6 @@ current_user_router = APIRouter(
87
91
 
88
92
  @router.get(
89
93
  "",
90
- response_model=Page[UserResponse],
91
94
  responses={401: error_response, 404: error_response, 422: error_response},
92
95
  )
93
96
  @handle_exceptions
@@ -133,7 +136,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
133
136
 
134
137
  @router.post(
135
138
  "",
136
- response_model=UserResponse,
137
139
  responses={
138
140
  401: error_response,
139
141
  409: error_response,
@@ -174,7 +176,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
174
176
 
175
177
  # new_user = verify_permissions_and_create_entity(
176
178
  # request_model=user,
177
- # resource_type=ResourceType.USER,
178
179
  # create_method=zen_store().create_user,
179
180
  # )
180
181
  new_user = zen_store().create_user(user)
@@ -188,7 +189,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
188
189
 
189
190
  @router.get(
190
191
  "/{user_name_or_id}",
191
- response_model=UserResponse,
192
192
  responses={401: error_response, 404: error_response, 422: error_response},
193
193
  )
194
194
  @handle_exceptions
@@ -233,7 +233,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
233
233
 
234
234
  @router.put(
235
235
  "/{user_name_or_id}",
236
- response_model=UserResponse,
237
236
  responses={
238
237
  401: error_response,
239
238
  404: error_response,
@@ -403,7 +402,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
403
402
 
404
403
  @activation_router.put(
405
404
  "/{user_name_or_id}" + ACTIVATE,
406
- response_model=UserResponse,
407
405
  responses={
408
406
  401: error_response,
409
407
  404: error_response,
@@ -464,7 +462,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
464
462
 
465
463
  @router.put(
466
464
  "/{user_name_or_id}" + DEACTIVATE,
467
- response_model=UserResponse,
468
465
  responses={
469
466
  401: error_response,
470
467
  404: error_response,
@@ -555,7 +552,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
555
552
 
556
553
  @router.put(
557
554
  "/{user_name_or_id}" + EMAIL_ANALYTICS,
558
- response_model=UserResponse,
559
555
  responses={
560
556
  401: error_response,
561
557
  404: error_response,
@@ -608,7 +604,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
608
604
 
609
605
  @current_user_router.get(
610
606
  "/current-user",
611
- response_model=UserResponse,
612
607
  responses={401: error_response, 404: error_response, 422: error_response},
613
608
  )
614
609
  @handle_exceptions
@@ -632,7 +627,6 @@ if server_config().auth_scheme != AuthScheme.EXTERNAL:
632
627
 
633
628
  @current_user_router.put(
634
629
  "/current-user",
635
- response_model=UserResponse,
636
630
  responses={
637
631
  401: error_response,
638
632
  404: error_response,
@@ -752,8 +746,6 @@ if server_config().rbac_enabled:
752
746
  )
753
747
 
754
748
  resource_type = ResourceType(resource_type)
755
- resource = Resource(type=resource_type, id=resource_id)
756
-
757
749
  schema_class = get_schema_for_resource_type(resource_type)
758
750
  model = zen_store().get_entity_by_id(
759
751
  entity_id=resource_id, schema_class=schema_class
@@ -765,6 +757,14 @@ if server_config().rbac_enabled:
765
757
  "not exist."
766
758
  )
767
759
 
760
+ workspace_id = None
761
+ if isinstance(model, WorkspaceScopedResponse):
762
+ workspace_id = model.workspace.id
763
+
764
+ resource = Resource(
765
+ type=resource_type, id=resource_id, workspace_id=workspace_id
766
+ )
767
+
768
768
  verify_permission_for_model(model=model, action=Action.SHARE)
769
769
  for action in actions:
770
770
  # Make sure users aren't able to share permissions they don't have
@@ -776,3 +776,38 @@ if server_config().rbac_enabled:
776
776
  resource=resource,
777
777
  actions=[Action(action) for action in actions],
778
778
  )
779
+
780
+
781
+ @current_user_router.put(
782
+ "/default-workspace",
783
+ responses={
784
+ 401: error_response,
785
+ 404: error_response,
786
+ 422: error_response,
787
+ },
788
+ )
789
+ @handle_exceptions
790
+ def update_user_default_workspace(
791
+ workspace_name_or_id: Union[str, UUID],
792
+ auth_context: AuthContext = Security(authorize),
793
+ ) -> UserResponse:
794
+ """Updates the default workspace of the current user.
795
+
796
+ Args:
797
+ workspace_name_or_id: Name or ID of the workspace.
798
+ auth_context: Authentication context.
799
+
800
+ Returns:
801
+ The updated user.
802
+ """
803
+ workspace = verify_permissions_and_get_entity(
804
+ id=workspace_name_or_id,
805
+ get_method=zen_store().get_workspace,
806
+ )
807
+
808
+ user = zen_store().update_user(
809
+ user_id=auth_context.user.id,
810
+ user_update=UserUpdate(default_workspace_id=workspace.id),
811
+ )
812
+
813
+ return dehydrate_response_model(user)