GeneralManager 0.10.6__tar.gz → 0.11.0__tar.gz
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.
- {generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/PKG-INFO +1 -1
- {generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/SOURCES.txt +2 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/PKG-INFO +1 -1
- {generalmanager-0.10.6 → generalmanager-0.11.0}/pyproject.toml +1 -1
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/api/mutation.py +15 -7
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/basePermission.py +7 -21
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/managerBasedPermission.py +2 -11
- generalmanager-0.11.0/src/general_manager/permission/mutationPermission.py +88 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/permissionDataManager.py +1 -5
- generalmanager-0.11.0/src/general_manager/permission/utils.py +35 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/LICENSE +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/README.md +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/setup.cfg +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/apps.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/baseBucket.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/calculationBucket.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/databaseBucket.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/groupBucket.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/cacheDecorator.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/cacheTracker.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/dependencyIndex.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/modelDependencyCollector.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/factory/autoFactory.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/factory/factoryMethods.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/baseInterface.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/calculationInterface.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/databaseBasedInterface.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/databaseInterface.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/models.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/readOnlyInterface.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/generalManager.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/groupManager.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/measurement/measurementField.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/fileBasedPermission.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/permissionChecks.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/argsToKwargs.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/filterParser.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/formatString.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/jsonEncoder.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/makeCacheKey.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/noneToZero.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/pathMapping.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/tests/test_settings.py +0 -0
- {generalmanager-0.10.6 → generalmanager-0.11.0}/tests/test_urls.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GeneralManager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.11.0
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
6
6
|
License-Expression: MIT
|
@@ -43,8 +43,10 @@ src/general_manager/permission/__init__.py
|
|
43
43
|
src/general_manager/permission/basePermission.py
|
44
44
|
src/general_manager/permission/fileBasedPermission.py
|
45
45
|
src/general_manager/permission/managerBasedPermission.py
|
46
|
+
src/general_manager/permission/mutationPermission.py
|
46
47
|
src/general_manager/permission/permissionChecks.py
|
47
48
|
src/general_manager/permission/permissionDataManager.py
|
49
|
+
src/general_manager/permission/utils.py
|
48
50
|
src/general_manager/rule/__init__.py
|
49
51
|
src/general_manager/rule/handler.py
|
50
52
|
src/general_manager/rule/rule.py
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GeneralManager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.11.0
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
6
6
|
License-Expression: MIT
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "GeneralManager"
|
7
|
-
version = "0.
|
7
|
+
version = "0.11.0"
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
@@ -1,5 +1,14 @@
|
|
1
1
|
import inspect
|
2
|
-
from typing import
|
2
|
+
from typing import (
|
3
|
+
get_type_hints,
|
4
|
+
Optional,
|
5
|
+
Union,
|
6
|
+
List,
|
7
|
+
Tuple,
|
8
|
+
get_origin,
|
9
|
+
get_args,
|
10
|
+
Type,
|
11
|
+
)
|
3
12
|
import graphene
|
4
13
|
|
5
14
|
from general_manager.api.graphql import GraphQL
|
@@ -7,9 +16,10 @@ from general_manager.manager.generalManager import GeneralManager
|
|
7
16
|
|
8
17
|
from general_manager.utils.formatString import snake_to_camel
|
9
18
|
from typing import TypeAliasType
|
19
|
+
from general_manager.permission.mutationPermission import MutationPermission
|
10
20
|
|
11
21
|
|
12
|
-
def graphQlMutation(
|
22
|
+
def graphQlMutation(permission: Optional[Type[MutationPermission]] = None):
|
13
23
|
"""
|
14
24
|
Decorator that transforms a function into a GraphQL mutation class and registers it for use in a Graphene-based API.
|
15
25
|
|
@@ -109,11 +119,9 @@ def graphQlMutation(needs_role: Optional[str] = None, auth_required: bool = Fals
|
|
109
119
|
|
110
120
|
# Define mutate method
|
111
121
|
def _mutate(root, info, **kwargs):
|
112
|
-
|
113
|
-
if
|
114
|
-
|
115
|
-
**{"success": False, "errors": ["Authentication required"]}
|
116
|
-
)
|
122
|
+
|
123
|
+
if permission:
|
124
|
+
permission.check(kwargs, info.context.user)
|
117
125
|
try:
|
118
126
|
result = fn(info, **kwargs)
|
119
127
|
data = {}
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/basePermission.py
RENAMED
@@ -8,6 +8,7 @@ from general_manager.permission.permissionChecks import (
|
|
8
8
|
|
9
9
|
from django.contrib.auth.models import AnonymousUser, AbstractUser
|
10
10
|
from general_manager.permission.permissionDataManager import PermissionDataManager
|
11
|
+
from general_manager.permission.utils import validatePermissionString
|
11
12
|
|
12
13
|
if TYPE_CHECKING:
|
13
14
|
from general_manager.manager.generalManager import GeneralManager
|
@@ -153,24 +154,9 @@ class BasePermission(ABC):
|
|
153
154
|
self,
|
154
155
|
permission: str,
|
155
156
|
) -> bool:
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
for sub_permission in permission.split("&")
|
163
|
-
]
|
164
|
-
)
|
165
|
-
|
166
|
-
def __validateSinglePermission(
|
167
|
-
self,
|
168
|
-
permission: str,
|
169
|
-
) -> bool:
|
170
|
-
permission_function, *config = permission.split(":")
|
171
|
-
if permission_function not in permission_functions:
|
172
|
-
raise ValueError(f"Permission {permission} not found")
|
173
|
-
|
174
|
-
return permission_functions[permission_function]["permission_method"](
|
175
|
-
self.instance, self.request_user, config
|
176
|
-
)
|
157
|
+
"""
|
158
|
+
Validates a permission string which can be a combination of multiple permissions
|
159
|
+
separated by "&" (e.g. "isAuthenticated&isMatchingKeyAccount").
|
160
|
+
This means that all sub_permissions must be true.
|
161
|
+
"""
|
162
|
+
return validatePermissionString(permission, self.instance, self.request_user)
|
@@ -30,8 +30,7 @@ class ManagerBasedPermission(BasePermission):
|
|
30
30
|
request_user: AbstractUser,
|
31
31
|
) -> None:
|
32
32
|
|
33
|
-
|
34
|
-
self.__request_user = request_user
|
33
|
+
super().__init__(instance, request_user)
|
35
34
|
self.__attribute_permissions = self.__getAttributePermissions()
|
36
35
|
self.__based_on_permission = self.__getBasedOnPermission()
|
37
36
|
self.__overall_results: Dict[permission_type, Optional[bool]] = {
|
@@ -51,7 +50,7 @@ class ManagerBasedPermission(BasePermission):
|
|
51
50
|
basis_object = getattr(self.instance, __based_on__, None)
|
52
51
|
if basis_object is None:
|
53
52
|
raise ValueError(
|
54
|
-
f"Based on object {__based_on__} not found in instance {self.
|
53
|
+
f"Based on object {__based_on__} not found in instance {self.instance}"
|
55
54
|
)
|
56
55
|
if not isinstance(basis_object, GeneralManager) and not issubclass(
|
57
56
|
basis_object, GeneralManager
|
@@ -71,14 +70,6 @@ class ManagerBasedPermission(BasePermission):
|
|
71
70
|
request_user=self.request_user,
|
72
71
|
)
|
73
72
|
|
74
|
-
@property
|
75
|
-
def instance(self) -> PermissionDataManager | GeneralManager:
|
76
|
-
return self.__instance
|
77
|
-
|
78
|
-
@property
|
79
|
-
def request_user(self) -> AbstractUser:
|
80
|
-
return self.__request_user
|
81
|
-
|
82
73
|
def __getAttributePermissions(
|
83
74
|
self,
|
84
75
|
) -> dict[str, dict[permission_type, list[str]]]:
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from django.contrib.auth.models import AbstractUser, AnonymousUser
|
3
|
+
from typing import Any
|
4
|
+
from general_manager.permission.basePermission import BasePermission
|
5
|
+
|
6
|
+
from general_manager.permission.permissionDataManager import PermissionDataManager
|
7
|
+
from general_manager.permission.utils import validatePermissionString
|
8
|
+
|
9
|
+
|
10
|
+
class MutationPermission:
|
11
|
+
__mutate__: list[str]
|
12
|
+
|
13
|
+
def __init__(
|
14
|
+
self, data: dict[str, Any], request_user: AbstractUser | AnonymousUser
|
15
|
+
) -> None:
|
16
|
+
self._data = PermissionDataManager(data)
|
17
|
+
self._request_user = request_user
|
18
|
+
self.__attribute_permissions = self.__getAttributePermissions()
|
19
|
+
|
20
|
+
self.__overall_result: bool | None = None
|
21
|
+
|
22
|
+
@property
|
23
|
+
def data(self) -> PermissionDataManager:
|
24
|
+
return self._data
|
25
|
+
|
26
|
+
@property
|
27
|
+
def request_user(self) -> AbstractUser | AnonymousUser:
|
28
|
+
return self._request_user
|
29
|
+
|
30
|
+
def __getAttributePermissions(
|
31
|
+
self,
|
32
|
+
) -> dict[str, list[str]]:
|
33
|
+
attribute_permissions = {}
|
34
|
+
for attribute in self.__class__.__dict__:
|
35
|
+
if not attribute.startswith("__"):
|
36
|
+
attribute_permissions[attribute] = getattr(self.__class__, attribute)
|
37
|
+
return attribute_permissions
|
38
|
+
|
39
|
+
@classmethod
|
40
|
+
def check(
|
41
|
+
cls,
|
42
|
+
data: dict[str, Any],
|
43
|
+
request_user: AbstractUser | AnonymousUser | Any,
|
44
|
+
) -> None:
|
45
|
+
"""
|
46
|
+
Check if the user has permission to perform the mutation based on the provided data.
|
47
|
+
Raises:
|
48
|
+
PermissionError: If the user does not have permission.
|
49
|
+
"""
|
50
|
+
errors = []
|
51
|
+
Permission = cls(data, BasePermission.getUserWithId(request_user))
|
52
|
+
for key in data:
|
53
|
+
if not Permission.checkPermission(key):
|
54
|
+
errors.append(
|
55
|
+
f"Permission denied for {key} with value {data[key]} for user {request_user}"
|
56
|
+
)
|
57
|
+
if errors:
|
58
|
+
raise PermissionError(f"Permission denied with errors: {errors}")
|
59
|
+
|
60
|
+
def checkPermission(
|
61
|
+
self,
|
62
|
+
attribute: str,
|
63
|
+
) -> bool:
|
64
|
+
|
65
|
+
has_attribute_permissions = attribute in self.__attribute_permissions
|
66
|
+
|
67
|
+
if not has_attribute_permissions:
|
68
|
+
last_result = self.__overall_result
|
69
|
+
if last_result is not None:
|
70
|
+
return last_result
|
71
|
+
attribute_permission = True
|
72
|
+
else:
|
73
|
+
attribute_permission = self.__checkSpecificPermission(
|
74
|
+
self.__attribute_permissions[attribute]
|
75
|
+
)
|
76
|
+
|
77
|
+
permission = self.__checkSpecificPermission(self.__mutate__)
|
78
|
+
self.__overall_result = permission
|
79
|
+
return permission and attribute_permission
|
80
|
+
|
81
|
+
def __checkSpecificPermission(
|
82
|
+
self,
|
83
|
+
permissions: list[str],
|
84
|
+
) -> bool:
|
85
|
+
for permission in permissions:
|
86
|
+
if validatePermissionString(permission, self.data, self.request_user):
|
87
|
+
return True
|
88
|
+
return False
|
@@ -24,10 +24,6 @@ class PermissionDataManager(Generic[GeneralManagerData]):
|
|
24
24
|
self.getData = (
|
25
25
|
lambda name, permission_data=permission_data: permission_data.get(name)
|
26
26
|
)
|
27
|
-
if manager is None:
|
28
|
-
raise ValueError(
|
29
|
-
"Manager must be provided if permission_data is a dict"
|
30
|
-
)
|
31
27
|
self._manager = manager
|
32
28
|
else:
|
33
29
|
raise TypeError(
|
@@ -48,7 +44,7 @@ class PermissionDataManager(Generic[GeneralManagerData]):
|
|
48
44
|
return self._permission_data
|
49
45
|
|
50
46
|
@property
|
51
|
-
def manager(self) -> type[GeneralManagerData]:
|
47
|
+
def manager(self) -> type[GeneralManagerData] | None:
|
52
48
|
return self._manager
|
53
49
|
|
54
50
|
def __getattr__(self, name: str) -> Any:
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from general_manager.permission.permissionChecks import (
|
2
|
+
permission_functions,
|
3
|
+
)
|
4
|
+
from general_manager.permission.permissionDataManager import PermissionDataManager
|
5
|
+
from django.contrib.auth.models import AbstractUser, AnonymousUser
|
6
|
+
|
7
|
+
from general_manager.manager.generalManager import GeneralManager
|
8
|
+
from general_manager.manager.meta import GeneralManagerMeta
|
9
|
+
|
10
|
+
|
11
|
+
def validatePermissionString(
|
12
|
+
permission: str,
|
13
|
+
data: PermissionDataManager | GeneralManager | GeneralManagerMeta,
|
14
|
+
request_user: AbstractUser | AnonymousUser,
|
15
|
+
) -> bool:
|
16
|
+
# permission can be a combination of multiple permissions
|
17
|
+
# separated by "&" (e.g. "isAuthenticated&isMatchingKeyAccount")
|
18
|
+
# this means that all sub_permissions must be true
|
19
|
+
def _validateSinglePermission(
|
20
|
+
permission: str,
|
21
|
+
) -> bool:
|
22
|
+
permission_function, *config = permission.split(":")
|
23
|
+
if permission_function not in permission_functions:
|
24
|
+
raise ValueError(f"Permission {permission} not found")
|
25
|
+
|
26
|
+
return permission_functions[permission_function]["permission_method"](
|
27
|
+
data, request_user, config
|
28
|
+
)
|
29
|
+
|
30
|
+
return all(
|
31
|
+
[
|
32
|
+
_validateSinglePermission(sub_permission)
|
33
|
+
for sub_permission in permission.split("&")
|
34
|
+
]
|
35
|
+
)
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/GeneralManager.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/calculationBucket.py
RENAMED
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/bucket/databaseBucket.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/cache/dependencyIndex.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/factory/factoryMethods.py
RENAMED
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/baseInterface.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/databaseInterface.py
RENAMED
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/interface/readOnlyInterface.py
RENAMED
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/manager/generalManager.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/measurement/measurement.py
RENAMED
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/measurement/measurementField.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{generalmanager-0.10.6 → generalmanager-0.11.0}/src/general_manager/permission/permissionChecks.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|