mage-ai 0.9.33__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.
- mage_ai/api/mixins/__init__.py +0 -0
- mage_ai/api/mixins/result_set.py +65 -0
- mage_ai/api/operations/base.py +8 -3
- mage_ai/api/policies/BasePolicy.py +127 -2
- mage_ai/api/policies/PermissionPolicy.py +5 -0
- mage_ai/api/policies/UserPolicy.py +25 -2
- mage_ai/api/policies/mixins/user_permissions.py +0 -9
- mage_ai/api/presenters/PermissionPresenter.py +2 -0
- mage_ai/api/presenters/RolePresenter.py +15 -0
- mage_ai/api/presenters/UserPresenter.py +9 -15
- mage_ai/api/resources/PermissionResource.py +40 -3
- mage_ai/api/resources/RoleResource.py +1 -0
- mage_ai/api/resources/UserResource.py +35 -4
- mage_ai/orchestration/db/models/oauth.py +126 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/PBVuphyo_muEAj347ZP_b/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{3859-3501cdba0a33f9f2.js → 3859-ba594d21a1260cd2.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7022-a0fb5af2ebd7bb45.js → frontend_dist/_next/static/chunks/7022-80d082a1d7fd1234.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/files.html +5 -5
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +5 -5
- mage_ai/server/frontend_dist/global-data-products.html +5 -5
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +5 -5
- mage_ai/server/frontend_dist/manage/users/[user].html +5 -5
- mage_ai/server/frontend_dist/manage/users/new.html +5 -5
- mage_ai/server/frontend_dist/manage/users.html +5 -5
- mage_ai/server/frontend_dist/manage.html +5 -5
- mage_ai/server/frontend_dist/overview.html +5 -5
- mage_ai/server/frontend_dist/pipeline-runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +5 -5
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +5 -5
- mage_ai/server/frontend_dist/settings/account/profile.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/roles.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +5 -5
- mage_ai/server/frontend_dist/settings/workspace/users.html +5 -5
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +10 -10
- mage_ai/server/frontend_dist/templates/[...slug].html +5 -5
- mage_ai/server/frontend_dist/templates.html +5 -5
- mage_ai/server/frontend_dist/terminal.html +5 -5
- mage_ai/server/frontend_dist/test.html +4 -4
- mage_ai/server/frontend_dist/triggers.html +5 -5
- mage_ai/server/frontend_dist/version-control.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/L-IKw5_bRZUs-wyjnpN_j/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3859-3501cdba0a33f9f2.js → 3859-ba594d21a1260cd2.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/7022-a0fb5af2ebd7bb45.js → frontend_dist_base_path_template/_next/static/chunks/7022-80d082a1d7fd1234.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-25f211ef377e5958.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-941c5155c3bfcc35.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-5730e4e059db40a8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-d7fd4857579e2b00.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-1a95628ea8d0d846.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions-cb1cdf5f8e5bf9c5.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/[...slug]-5061c073e1c0de07.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-f551c5665bfd3494.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/manage.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/overview.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +10 -10
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +5 -5
- mage_ai/server/frontend_dist_base_path_template/templates.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/terminal.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/test.html +4 -4
- mage_ai/server/frontend_dist_base_path_template/triggers.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/version-control.html +5 -5
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/METADATA +1 -1
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/RECORD +137 -133
- mage_ai/server/frontend_dist/_next/static/chunks/8146-6f46ffd7cbe2fd07.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9264-11c4f9e79f8a9fd5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-68f1591d3f4262f1.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-672599b18c4eb2a6.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions-b7bc84646325062c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/[...slug]-b7b99c3d2109fdea.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-fe480da25b026bb5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/sGWtg0x8VBmlqQeSOAw9E/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-6f46ffd7cbe2fd07.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-11c4f9e79f8a9fd5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-68f1591d3f4262f1.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/[...slug]-672599b18c4eb2a6.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions-b7bc84646325062c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/[...slug]-b7b99c3d2109fdea.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-fe480da25b026bb5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/dFD_SGZQKSOB83hTxog2E/_buildManifest.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{sGWtg0x8VBmlqQeSOAw9E → PBVuphyo_muEAj347ZP_b}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{dFD_SGZQKSOB83hTxog2E → L-IKw5_bRZUs-wyjnpN_j}/_ssgManifest.js +0 -0
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.33.dist-info → mage_ai-0.9.34.dist-info}/top_level.txt +0 -0
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from mage_ai.orchestration.db import safe_db_query
|
|
4
|
+
from mage_ai.orchestration.db.models.oauth import (
|
|
5
|
+
Permission,
|
|
6
|
+
Role,
|
|
7
|
+
RolePermission,
|
|
8
|
+
UserRole,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
CONTEXT_DATA_KEY_USER_PERMISSIONS = '__user_permissions'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ResultSetMixIn:
|
|
15
|
+
@safe_db_query
|
|
16
|
+
async def load_and_cache_user_permissions(self) -> List[Permission]:
|
|
17
|
+
# This will fetch the user permissions and store it on the context data
|
|
18
|
+
# so that repeat policy user permission validations won’t keep querying the
|
|
19
|
+
# database for permissions.
|
|
20
|
+
if not self.current_user:
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
permissions = self.result_set().context.data.get(CONTEXT_DATA_KEY_USER_PERMISSIONS)
|
|
24
|
+
if permissions:
|
|
25
|
+
return permissions
|
|
26
|
+
|
|
27
|
+
query = (
|
|
28
|
+
Permission.
|
|
29
|
+
select(
|
|
30
|
+
Permission.access,
|
|
31
|
+
Permission.entity,
|
|
32
|
+
Permission.entity_id,
|
|
33
|
+
Permission.entity_name,
|
|
34
|
+
Permission.entity_type,
|
|
35
|
+
Permission.id,
|
|
36
|
+
Permission.options,
|
|
37
|
+
).
|
|
38
|
+
join(
|
|
39
|
+
RolePermission,
|
|
40
|
+
RolePermission.permission_id == Permission.id).
|
|
41
|
+
join(
|
|
42
|
+
Role,
|
|
43
|
+
Role.id == RolePermission.role_id).
|
|
44
|
+
join(
|
|
45
|
+
UserRole,
|
|
46
|
+
UserRole.role_id == Role.id).
|
|
47
|
+
filter(UserRole.user_id == self.current_user.id)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
permissions = []
|
|
51
|
+
|
|
52
|
+
for row in query.all():
|
|
53
|
+
permission = Permission()
|
|
54
|
+
permission.access = row.access
|
|
55
|
+
permission.entity = row.entity
|
|
56
|
+
permission.entity_id = row.entity_id
|
|
57
|
+
permission.entity_name = row.entity_name
|
|
58
|
+
permission.entity_type = row.entity_type
|
|
59
|
+
permission.id = row.id
|
|
60
|
+
permission.options = row.options
|
|
61
|
+
permissions.append(permission)
|
|
62
|
+
|
|
63
|
+
self.result_set().context.data[CONTEXT_DATA_KEY_USER_PERMISSIONS] = permissions
|
|
64
|
+
|
|
65
|
+
return permissions
|
mage_ai/api/operations/base.py
CHANGED
|
@@ -27,6 +27,7 @@ from mage_ai.api.parsers.BaseParser import BaseParser
|
|
|
27
27
|
from mage_ai.api.presenters.BasePresenter import CustomDict, CustomList
|
|
28
28
|
from mage_ai.api.result_set import ResultSet
|
|
29
29
|
from mage_ai.orchestration.db.errors import DoesNotExistError
|
|
30
|
+
from mage_ai.settings import REQUIRE_USER_PERMISSIONS
|
|
30
31
|
from mage_ai.shared.array import flatten
|
|
31
32
|
from mage_ai.shared.hash import ignore_keys, merge_dict
|
|
32
33
|
from mage_ai.shared.strings import classify
|
|
@@ -170,9 +171,13 @@ class BaseOperation():
|
|
|
170
171
|
}
|
|
171
172
|
except ApiError as err:
|
|
172
173
|
if err.code == 403 and \
|
|
173
|
-
self.user and
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
self.user and \
|
|
175
|
+
self.user.project_access == 0 and \
|
|
176
|
+
not self.user.roles:
|
|
177
|
+
|
|
178
|
+
if not REQUIRE_USER_PERMISSIONS:
|
|
179
|
+
err.message = 'You don’t have access to this project. ' + \
|
|
180
|
+
'Please ask an admin or owner for permissions.'
|
|
176
181
|
if settings.DEBUG:
|
|
177
182
|
raise err
|
|
178
183
|
else:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
import inspect
|
|
3
3
|
from collections.abc import Iterable
|
|
4
|
-
from typing import List, Tuple, Union
|
|
4
|
+
from typing import Callable, List, Tuple, Union
|
|
5
5
|
|
|
6
6
|
import inflection
|
|
7
7
|
|
|
@@ -37,6 +37,10 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
37
37
|
query_rules = {}
|
|
38
38
|
read_rules = {}
|
|
39
39
|
write_rules = {}
|
|
40
|
+
override_permission_action_rules = {}
|
|
41
|
+
override_permission_query_rules = {}
|
|
42
|
+
override_permission_read_rules = {}
|
|
43
|
+
override_permission_write_rules = {}
|
|
40
44
|
|
|
41
45
|
def __init__(self, resource, current_user, **kwargs):
|
|
42
46
|
self.current_user = current_user
|
|
@@ -67,6 +71,12 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
67
71
|
self.action_rules[self.__name__] = {}
|
|
68
72
|
return self.action_rules[self.__name__].get(action)
|
|
69
73
|
|
|
74
|
+
@classmethod
|
|
75
|
+
def override_permission_action_rule(self, action):
|
|
76
|
+
if not self.override_permission_action_rules.get(self.__name__):
|
|
77
|
+
self.override_permission_action_rules[self.__name__] = {}
|
|
78
|
+
return self.override_permission_action_rules[self.__name__].get(action)
|
|
79
|
+
|
|
70
80
|
@classmethod
|
|
71
81
|
def query_rule(self, query):
|
|
72
82
|
if REQUIRE_USER_PERMISSIONS:
|
|
@@ -76,6 +86,12 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
76
86
|
self.query_rules[self.__name__] = {}
|
|
77
87
|
return self.query_rules[self.__name__].get(query)
|
|
78
88
|
|
|
89
|
+
@classmethod
|
|
90
|
+
def override_permission_query_rule(self, query):
|
|
91
|
+
if not self.override_permission_query_rules.get(self.__name__):
|
|
92
|
+
self.override_permission_query_rules[self.__name__] = {}
|
|
93
|
+
return self.override_permission_query_rules[self.__name__].get(query)
|
|
94
|
+
|
|
79
95
|
@classmethod
|
|
80
96
|
def read_rule(self, read):
|
|
81
97
|
if REQUIRE_USER_PERMISSIONS:
|
|
@@ -85,6 +101,12 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
85
101
|
self.read_rules[self.__name__] = {}
|
|
86
102
|
return self.read_rules[self.__name__].get(read)
|
|
87
103
|
|
|
104
|
+
@classmethod
|
|
105
|
+
def override_permission_read_rule(self, read):
|
|
106
|
+
if not self.override_permission_read_rules.get(self.__name__):
|
|
107
|
+
self.override_permission_read_rules[self.__name__] = {}
|
|
108
|
+
return self.override_permission_read_rules[self.__name__].get(read)
|
|
109
|
+
|
|
88
110
|
@classmethod
|
|
89
111
|
def write_rule(self, write):
|
|
90
112
|
if REQUIRE_USER_PERMISSIONS:
|
|
@@ -94,10 +116,18 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
94
116
|
self.write_rules[self.__name__] = {}
|
|
95
117
|
return self.write_rules[self.__name__].get(write)
|
|
96
118
|
|
|
119
|
+
@classmethod
|
|
120
|
+
def override_permission_write_rule(self, write):
|
|
121
|
+
if not self.override_permission_write_rules.get(self.__name__):
|
|
122
|
+
self.override_permission_write_rules[self.__name__] = {}
|
|
123
|
+
return self.override_permission_write_rules[self.__name__].get(write)
|
|
124
|
+
|
|
97
125
|
@classmethod
|
|
98
126
|
def allow_actions(self, array, **kwargs):
|
|
99
127
|
if not self.action_rules.get(self.__name__):
|
|
100
128
|
self.action_rules[self.__name__] = {}
|
|
129
|
+
if not self.override_permission_action_rules.get(self.__name__):
|
|
130
|
+
self.override_permission_action_rules[self.__name__] = {}
|
|
101
131
|
|
|
102
132
|
array_use = array or [OperationType.ALL]
|
|
103
133
|
for key in array_use:
|
|
@@ -106,18 +136,33 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
106
136
|
for scope in kwargs.get('scopes', []):
|
|
107
137
|
self.action_rules[self.__name__][key][scope] = extract(kwargs, [
|
|
108
138
|
'condition'])
|
|
139
|
+
if not self.override_permission_action_rules[self.__name__].get(key):
|
|
140
|
+
self.override_permission_action_rules[self.__name__][key] = {}
|
|
141
|
+
for scope in kwargs.get('scopes', []):
|
|
142
|
+
self.override_permission_action_rules[self.__name__][key][scope] = extract(
|
|
143
|
+
kwargs,
|
|
144
|
+
[
|
|
145
|
+
'override_permission_condition',
|
|
146
|
+
],
|
|
147
|
+
)
|
|
109
148
|
|
|
110
149
|
@classmethod
|
|
111
150
|
def allow_query(self, array: List = None, **kwargs):
|
|
112
151
|
if not self.query_rules.get(self.__name__):
|
|
113
152
|
self.query_rules[self.__name__] = {}
|
|
153
|
+
if not self.override_permission_query_rules.get(self.__name__):
|
|
154
|
+
self.override_permission_query_rules[self.__name__] = {}
|
|
114
155
|
|
|
115
156
|
array_use = array or [AttributeType.ALL]
|
|
116
157
|
for key in array_use:
|
|
117
158
|
if not self.query_rules[self.__name__].get(key):
|
|
118
159
|
self.query_rules[self.__name__][key] = {}
|
|
160
|
+
if not self.override_permission_query_rules[self.__name__].get(key):
|
|
161
|
+
self.override_permission_query_rules[self.__name__][key] = {}
|
|
162
|
+
|
|
119
163
|
actions = kwargs.get('on_action', [OperationType.ALL])
|
|
120
164
|
actions = actions if isinstance(actions, list) else [actions]
|
|
165
|
+
|
|
121
166
|
for scope in kwargs.get('scopes', []):
|
|
122
167
|
if not self.query_rules[self.__name__][key].get(scope):
|
|
123
168
|
self.query_rules[self.__name__][key][scope] = {}
|
|
@@ -129,15 +174,32 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
129
174
|
],
|
|
130
175
|
)
|
|
131
176
|
|
|
177
|
+
if not self.override_permission_query_rules[self.__name__][key].get(scope):
|
|
178
|
+
self.override_permission_query_rules[self.__name__][key][scope] = {}
|
|
179
|
+
for action in actions:
|
|
180
|
+
self.override_permission_query_rules[self.__name__][key][scope][action] = \
|
|
181
|
+
extract(
|
|
182
|
+
kwargs,
|
|
183
|
+
[
|
|
184
|
+
'override_permission_condition',
|
|
185
|
+
])
|
|
186
|
+
|
|
132
187
|
@classmethod
|
|
133
188
|
def allow_read(self, array, **kwargs):
|
|
134
189
|
if not self.read_rules.get(self.__name__):
|
|
135
190
|
self.read_rules[self.__name__] = {}
|
|
191
|
+
if not self.override_permission_read_rules.get(self.__name__):
|
|
192
|
+
self.override_permission_read_rules[self.__name__] = {}
|
|
193
|
+
|
|
136
194
|
for key in array:
|
|
137
195
|
if not self.read_rules[self.__name__].get(key):
|
|
138
196
|
self.read_rules[self.__name__][key] = {}
|
|
197
|
+
if not self.override_permission_read_rules[self.__name__].get(key):
|
|
198
|
+
self.override_permission_read_rules[self.__name__][key] = {}
|
|
199
|
+
|
|
139
200
|
actions = kwargs.get('on_action', [OperationType.ALL])
|
|
140
201
|
actions = actions if isinstance(actions, list) else [actions]
|
|
202
|
+
|
|
141
203
|
for scope in kwargs.get('scopes', []):
|
|
142
204
|
if not self.read_rules[self.__name__][key].get(scope):
|
|
143
205
|
self.read_rules[self.__name__][key][scope] = {}
|
|
@@ -145,15 +207,32 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
145
207
|
self.read_rules[self.__name__][key][scope][action] = extract(kwargs, [
|
|
146
208
|
'condition'])
|
|
147
209
|
|
|
210
|
+
if not self.override_permission_read_rules[self.__name__][key].get(scope):
|
|
211
|
+
self.override_permission_read_rules[self.__name__][key][scope] = {}
|
|
212
|
+
for action in actions:
|
|
213
|
+
self.override_permission_read_rules[self.__name__][key][scope][action] = \
|
|
214
|
+
extract(
|
|
215
|
+
kwargs,
|
|
216
|
+
[
|
|
217
|
+
'override_permission_condition',
|
|
218
|
+
])
|
|
219
|
+
|
|
148
220
|
@classmethod
|
|
149
221
|
def allow_write(self, array, **kwargs):
|
|
150
222
|
if not self.write_rules.get(self.__name__):
|
|
151
223
|
self.write_rules[self.__name__] = {}
|
|
224
|
+
if not self.override_permission_write_rules.get(self.__name__):
|
|
225
|
+
self.override_permission_write_rules[self.__name__] = {}
|
|
226
|
+
|
|
152
227
|
for key in array:
|
|
153
228
|
if not self.write_rules[self.__name__].get(key):
|
|
154
229
|
self.write_rules[self.__name__][key] = {}
|
|
230
|
+
if not self.override_permission_write_rules[self.__name__].get(key):
|
|
231
|
+
self.override_permission_write_rules[self.__name__][key] = {}
|
|
232
|
+
|
|
155
233
|
actions = kwargs.get('on_action', [OperationType.ALL])
|
|
156
234
|
actions = actions if isinstance(actions, list) else [actions]
|
|
235
|
+
|
|
157
236
|
for scope in kwargs.get('scopes', []):
|
|
158
237
|
if not self.write_rules[self.__name__][key].get(scope):
|
|
159
238
|
self.write_rules[self.__name__][key][scope] = {}
|
|
@@ -161,6 +240,16 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
161
240
|
self.write_rules[self.__name__][key][scope][action] = extract(kwargs, [
|
|
162
241
|
'condition'])
|
|
163
242
|
|
|
243
|
+
if not self.override_permission_write_rules[self.__name__][key].get(scope):
|
|
244
|
+
self.override_permission_write_rules[self.__name__][key][scope] = {}
|
|
245
|
+
for action in actions:
|
|
246
|
+
self.override_permission_write_rules[self.__name__][key][scope][action] = \
|
|
247
|
+
extract(
|
|
248
|
+
kwargs,
|
|
249
|
+
[
|
|
250
|
+
'override_permission_condition',
|
|
251
|
+
])
|
|
252
|
+
|
|
164
253
|
@classmethod
|
|
165
254
|
def resource_name(self):
|
|
166
255
|
return inflection.pluralize(self.resource_name_singular())
|
|
@@ -230,6 +319,9 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
230
319
|
action,
|
|
231
320
|
config[self.current_scope()]['condition'],
|
|
232
321
|
operation=action,
|
|
322
|
+
override_permission_condition=(self.__class__.override_permission_action_rule(
|
|
323
|
+
action,
|
|
324
|
+
) or {}).get(self.current_scope(), {}).get('override_permission_condition'),
|
|
233
325
|
)
|
|
234
326
|
else:
|
|
235
327
|
error = ApiError.UNAUTHORIZED_ACCESS
|
|
@@ -250,9 +342,11 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
250
342
|
if 'read' == read_or_write:
|
|
251
343
|
attribute_operation = AttributeOperationType.READ
|
|
252
344
|
orig_config = self.__class__.read_rule(attrb)
|
|
345
|
+
orig_config_override = self.__class__.override_permission_read_rule(attrb)
|
|
253
346
|
else:
|
|
254
|
-
orig_config = self.__class__.write_rule(attrb)
|
|
255
347
|
attribute_operation = AttributeOperationType.WRITE
|
|
348
|
+
orig_config = self.__class__.write_rule(attrb)
|
|
349
|
+
orig_config_override = self.__class__.override_permission_write_rule(attrb)
|
|
256
350
|
|
|
257
351
|
config = None
|
|
258
352
|
if orig_config:
|
|
@@ -263,6 +357,15 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
263
357
|
if config is None:
|
|
264
358
|
config = config_scope.get(OperationType.ALL)
|
|
265
359
|
|
|
360
|
+
config_override = None
|
|
361
|
+
if orig_config_override:
|
|
362
|
+
await self.__validate_scopes(attrb, orig_config_override.keys())
|
|
363
|
+
config_override_scope = orig_config_override.get(self.current_scope(), {})
|
|
364
|
+
config_override = config_override_scope.get(api_operation_action)
|
|
365
|
+
|
|
366
|
+
if config_override is None:
|
|
367
|
+
config_override = config_override_scope.get(OperationType.ALL)
|
|
368
|
+
|
|
266
369
|
if config is None:
|
|
267
370
|
error = ApiError.UNAUTHORIZED_ACCESS
|
|
268
371
|
error.update({
|
|
@@ -274,13 +377,16 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
274
377
|
),
|
|
275
378
|
})
|
|
276
379
|
raise ApiError(error)
|
|
380
|
+
|
|
277
381
|
cond = config.get('condition')
|
|
382
|
+
|
|
278
383
|
if cond:
|
|
279
384
|
await self.__validate_condition(
|
|
280
385
|
attrb,
|
|
281
386
|
cond,
|
|
282
387
|
attribute_operation=attribute_operation,
|
|
283
388
|
operation=api_operation_action,
|
|
389
|
+
override_permission_condition=config_override.get('override_permission_condition'),
|
|
284
390
|
**kwargs,
|
|
285
391
|
)
|
|
286
392
|
|
|
@@ -320,6 +426,18 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
320
426
|
if config is None:
|
|
321
427
|
config = config_scope.get(OperationType.ALL)
|
|
322
428
|
|
|
429
|
+
orig_config_override = self.__class__.override_permission_query_rule(key) or \
|
|
430
|
+
self.__class__.override_permission_query_rule(AttributeType.ALL)
|
|
431
|
+
|
|
432
|
+
config_override = None
|
|
433
|
+
if orig_config_override:
|
|
434
|
+
await self.__validate_scopes(key, orig_config_override.keys())
|
|
435
|
+
config_override_scope = orig_config_override.get(self.current_scope(), {})
|
|
436
|
+
config_override = config_override_scope.get(api_operation_action)
|
|
437
|
+
|
|
438
|
+
if config_override is None:
|
|
439
|
+
config_override = config_override_scope.get(OperationType.ALL)
|
|
440
|
+
|
|
323
441
|
if config is None:
|
|
324
442
|
error = ApiError.UNAUTHORIZED_ACCESS
|
|
325
443
|
error.update({
|
|
@@ -334,6 +452,7 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
334
452
|
cond,
|
|
335
453
|
message=error_message,
|
|
336
454
|
operation=api_operation_action,
|
|
455
|
+
override_permission_condition=config_override.get('override_permission_condition'),
|
|
337
456
|
)
|
|
338
457
|
|
|
339
458
|
def parent_model(self):
|
|
@@ -375,6 +494,7 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
375
494
|
cond,
|
|
376
495
|
attribute_operation: AttributeOperationType = None,
|
|
377
496
|
operation: OperationType = None,
|
|
497
|
+
override_permission_condition: Callable = None,
|
|
378
498
|
**kwargs,
|
|
379
499
|
):
|
|
380
500
|
if not cond:
|
|
@@ -384,6 +504,11 @@ class BasePolicy(UserPermissionMixIn, ResultSetMixIn):
|
|
|
384
504
|
if validation and inspect.isawaitable(validation):
|
|
385
505
|
validation = await validation
|
|
386
506
|
|
|
507
|
+
if not validation and override_permission_condition:
|
|
508
|
+
validation = override_permission_condition(self)
|
|
509
|
+
if validation and inspect.isawaitable(validation):
|
|
510
|
+
validation = await validation
|
|
511
|
+
|
|
387
512
|
if not validation:
|
|
388
513
|
r_name = self.resource_name()
|
|
389
514
|
error = ApiError.UNAUTHORIZED_ACCESS
|
|
@@ -45,10 +45,14 @@ PermissionPolicy.allow_read(PermissionPresenter.default_attributes + [
|
|
|
45
45
|
'role',
|
|
46
46
|
'user',
|
|
47
47
|
'user_id',
|
|
48
|
+
'users',
|
|
48
49
|
], scopes=[
|
|
49
50
|
OauthScope.CLIENT_PRIVATE,
|
|
50
51
|
], on_action=[
|
|
52
|
+
constants.CREATE,
|
|
53
|
+
constants.DELETE,
|
|
51
54
|
constants.DETAIL,
|
|
55
|
+
constants.UPDATE,
|
|
52
56
|
], condition=lambda policy: policy.has_at_least_viewer_role())
|
|
53
57
|
|
|
54
58
|
|
|
@@ -59,6 +63,7 @@ PermissionPolicy.allow_write([
|
|
|
59
63
|
'entity_name',
|
|
60
64
|
'entity_type',
|
|
61
65
|
'role_id',
|
|
66
|
+
'role_ids',
|
|
62
67
|
], scopes=[
|
|
63
68
|
OauthScope.CLIENT_PRIVATE,
|
|
64
69
|
], on_action=[
|
|
@@ -16,6 +16,7 @@ UserPolicy.allow_actions([
|
|
|
16
16
|
OauthScope.CLIENT_PRIVATE,
|
|
17
17
|
], condition=lambda policy: policy.is_owner())
|
|
18
18
|
|
|
19
|
+
|
|
19
20
|
UserPolicy.allow_actions([
|
|
20
21
|
constants.DETAIL,
|
|
21
22
|
constants.UPDATE,
|
|
@@ -23,24 +24,40 @@ UserPolicy.allow_actions([
|
|
|
23
24
|
OauthScope.CLIENT_PRIVATE,
|
|
24
25
|
], condition=lambda policy: policy.is_current_user() or policy.has_at_least_admin_role())
|
|
25
26
|
|
|
27
|
+
|
|
26
28
|
UserPolicy.allow_actions([
|
|
27
29
|
constants.LIST,
|
|
28
30
|
], scopes=[
|
|
29
31
|
OauthScope.CLIENT_PRIVATE,
|
|
30
32
|
], condition=lambda policy: policy.has_at_least_admin_role())
|
|
31
33
|
|
|
34
|
+
|
|
32
35
|
UserPolicy.allow_read(UserPresenter.default_attributes, scopes=[
|
|
33
36
|
OauthScope.CLIENT_PRIVATE,
|
|
34
37
|
], condition=lambda policy: policy.is_current_user() or policy.has_at_least_admin_role())
|
|
35
38
|
|
|
39
|
+
|
|
36
40
|
UserPolicy.allow_read(UserPresenter.default_attributes + [
|
|
41
|
+
'permissions',
|
|
42
|
+
'token',
|
|
43
|
+
], scopes=[
|
|
44
|
+
OauthScope.CLIENT_PRIVATE,
|
|
45
|
+
], on_action=[
|
|
46
|
+
constants.DETAIL,
|
|
47
|
+
constants.UPDATE,
|
|
48
|
+
], condition=lambda policy: policy.is_current_user() or policy.has_at_least_admin_role())
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
UserPolicy.allow_read(UserPresenter.default_attributes + [
|
|
52
|
+
'permissions',
|
|
37
53
|
'token',
|
|
38
54
|
], scopes=[
|
|
39
55
|
OauthScope.CLIENT_PRIVATE,
|
|
40
56
|
], on_action=[
|
|
41
57
|
constants.CREATE,
|
|
42
58
|
constants.DELETE,
|
|
43
|
-
], condition=lambda policy: policy.
|
|
59
|
+
], condition=lambda policy: policy.is_owner())
|
|
60
|
+
|
|
44
61
|
|
|
45
62
|
UserPolicy.allow_write([
|
|
46
63
|
'avatar',
|
|
@@ -57,15 +74,19 @@ UserPolicy.allow_write([
|
|
|
57
74
|
constants.UPDATE,
|
|
58
75
|
], condition=lambda policy: policy.is_current_user() or policy.has_at_least_admin_role())
|
|
59
76
|
|
|
77
|
+
|
|
60
78
|
UserPolicy.allow_write([
|
|
79
|
+
'role_ids',
|
|
61
80
|
'roles',
|
|
62
|
-
'roles_new'
|
|
81
|
+
'roles_new',
|
|
63
82
|
], scopes=[
|
|
64
83
|
OauthScope.CLIENT_PRIVATE,
|
|
65
84
|
], on_action=[
|
|
85
|
+
constants.DELETE,
|
|
66
86
|
constants.UPDATE,
|
|
67
87
|
], condition=lambda policy: policy.has_at_least_admin_role())
|
|
68
88
|
|
|
89
|
+
|
|
69
90
|
UserPolicy.allow_write([
|
|
70
91
|
'owner',
|
|
71
92
|
], scopes=[
|
|
@@ -74,6 +95,7 @@ UserPolicy.allow_write([
|
|
|
74
95
|
constants.UPDATE,
|
|
75
96
|
], condition=lambda policy: policy.is_owner())
|
|
76
97
|
|
|
98
|
+
|
|
77
99
|
UserPolicy.allow_write([
|
|
78
100
|
'avatar',
|
|
79
101
|
'email',
|
|
@@ -81,6 +103,7 @@ UserPolicy.allow_write([
|
|
|
81
103
|
'last_name',
|
|
82
104
|
'password',
|
|
83
105
|
'password_confirmation',
|
|
106
|
+
'role_ids',
|
|
84
107
|
'roles',
|
|
85
108
|
'roles_new',
|
|
86
109
|
'username',
|
|
@@ -135,15 +135,6 @@ async def validate_condition_with_permissions(
|
|
|
135
135
|
has_access_for_all_attributes
|
|
136
136
|
)
|
|
137
137
|
|
|
138
|
-
print(
|
|
139
|
-
'WTFFFFFFFFFFFFFFFFFFFFFF',
|
|
140
|
-
disable_access_for_attribute_operation,
|
|
141
|
-
resource_attribute,
|
|
142
|
-
permission.id,
|
|
143
|
-
permission.access,
|
|
144
|
-
permission.access & disable_access_for_attribute_operation,
|
|
145
|
-
)
|
|
146
|
-
|
|
147
138
|
# Don’t grant access if permission disables access to this entity’s attributes
|
|
148
139
|
# for this attribute operation.
|
|
149
140
|
if disable_access_for_attribute_operation is not None and \
|
|
@@ -42,6 +42,7 @@ PermissionPresenter.register_format(
|
|
|
42
42
|
|
|
43
43
|
PermissionPresenter.register_formats([
|
|
44
44
|
constants.CREATE,
|
|
45
|
+
constants.DELETE,
|
|
45
46
|
constants.DETAIL,
|
|
46
47
|
constants.UPDATE,
|
|
47
48
|
], PermissionPresenter.default_attributes + [
|
|
@@ -53,6 +54,7 @@ PermissionPresenter.register_formats([
|
|
|
53
54
|
'roles',
|
|
54
55
|
'user',
|
|
55
56
|
'user_id',
|
|
57
|
+
'users',
|
|
56
58
|
'write_attributes',
|
|
57
59
|
])
|
|
58
60
|
|
|
@@ -47,3 +47,18 @@ RolePresenter.register_formats([
|
|
|
47
47
|
'updated_at',
|
|
48
48
|
'users',
|
|
49
49
|
])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
RolePresenter.register_formats([
|
|
53
|
+
f'user/{constants.CREATE}',
|
|
54
|
+
f'user/{constants.DELETE}',
|
|
55
|
+
f'user/{constants.DETAIL}',
|
|
56
|
+
f'user/{constants.LIST}',
|
|
57
|
+
f'user/{constants.UPDATE}',
|
|
58
|
+
], [
|
|
59
|
+
'created_at',
|
|
60
|
+
'id',
|
|
61
|
+
'name',
|
|
62
|
+
'permissions',
|
|
63
|
+
'updated_at',
|
|
64
|
+
])
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from mage_ai.api.operations import constants
|
|
2
2
|
from mage_ai.api.presenters.BasePresenter import BasePresenter
|
|
3
|
-
from mage_ai.shared.hash import extract
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
class UserPresenter(BasePresenter):
|
|
@@ -20,21 +19,16 @@ class UserPresenter(BasePresenter):
|
|
|
20
19
|
'username',
|
|
21
20
|
]
|
|
22
21
|
|
|
23
|
-
async def prepare_present(self, **kwargs):
|
|
24
|
-
data = self.model.to_dict(include_attributes=self.default_attributes)
|
|
25
|
-
data = extract(data, self.default_attributes, include_blank_values=True)
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
UserPresenter.register_format(
|
|
37
|
-
constants.CREATE, UserPresenter.default_attributes + ['token', ])
|
|
23
|
+
UserPresenter.register_formats([
|
|
24
|
+
constants.CREATE,
|
|
25
|
+
constants.DELETE,
|
|
26
|
+
constants.DETAIL,
|
|
27
|
+
constants.UPDATE,
|
|
28
|
+
], UserPresenter.default_attributes + [
|
|
29
|
+
'permissions',
|
|
30
|
+
'token',
|
|
31
|
+
])
|
|
38
32
|
|
|
39
33
|
|
|
40
34
|
UserPresenter.register_formats([
|
|
@@ -1,7 +1,7 @@
|
|
|
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):
|
|
@@ -42,5 +42,42 @@ class PermissionResource(DatabaseResource):
|
|
|
42
42
|
user_id=user.id if user else None,
|
|
43
43
|
)), user, **kwargs)
|
|
44
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
|
+
|
|
45
82
|
|
|
46
83
|
PermissionResource.register_parent_model('role_id', Role)
|