apexauthlib 0.1.8__py3-none-any.whl → 0.1.10__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.
- apexauthlib/entities/auth.py +32 -2
- apexauthlib/integration/api.py +57 -3
- apexauthlib/integration/formatter.py +58 -0
- {apexauthlib-0.1.8.dist-info → apexauthlib-0.1.10.dist-info}/METADATA +5 -3
- apexauthlib-0.1.10.dist-info/RECORD +12 -0
- {apexauthlib-0.1.8.dist-info → apexauthlib-0.1.10.dist-info}/WHEEL +1 -1
- apexauthlib-0.1.8.dist-info/RECORD +0 -11
- {apexauthlib-0.1.8.dist-info → apexauthlib-0.1.10.dist-info/licenses}/LICENSE +0 -0
apexauthlib/entities/auth.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
2
5
|
from typing import Any, Generic, TypeVar
|
|
3
6
|
from uuid import uuid4
|
|
4
7
|
|
|
@@ -22,7 +25,7 @@ class User:
|
|
|
22
25
|
@dataclass(frozen=True)
|
|
23
26
|
class Service:
|
|
24
27
|
service: str
|
|
25
|
-
|
|
28
|
+
admins: list[str]
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
@dataclass(frozen=True)
|
|
@@ -46,5 +49,32 @@ class Client:
|
|
|
46
49
|
@dataclass(frozen=True)
|
|
47
50
|
class ServiceUserInfo(Generic[ItemT]):
|
|
48
51
|
user: User
|
|
49
|
-
|
|
52
|
+
is_service_admin: bool
|
|
50
53
|
metadata: ItemT
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class ServicePermission:
|
|
58
|
+
name: str
|
|
59
|
+
label: str
|
|
60
|
+
description: str
|
|
61
|
+
type: FieldType
|
|
62
|
+
default: str | int | bool
|
|
63
|
+
|
|
64
|
+
values: list[str] | list[int] = field(default_factory=list)
|
|
65
|
+
id: str = field(default_factory=lambda: str(uuid4()))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class FieldType(str, Enum):
|
|
69
|
+
string = "string"
|
|
70
|
+
integer = "integer"
|
|
71
|
+
boolean = "boolean"
|
|
72
|
+
|
|
73
|
+
def valid_type(self) -> type:
|
|
74
|
+
if self.value == FieldType.string:
|
|
75
|
+
return str
|
|
76
|
+
if self.value == FieldType.integer:
|
|
77
|
+
return int
|
|
78
|
+
if self.value == FieldType.boolean:
|
|
79
|
+
return bool
|
|
80
|
+
raise ValueError(f"Invalid type {self.value}")
|
apexauthlib/integration/api.py
CHANGED
|
@@ -7,7 +7,8 @@ from apexdevkit.formatter import DataclassFormatter, Formatter
|
|
|
7
7
|
from apexdevkit.http import FluentHttp, JsonDict
|
|
8
8
|
|
|
9
9
|
from apexauthlib.entities import User
|
|
10
|
-
from apexauthlib.entities.auth import ItemT, ServiceUserInfo
|
|
10
|
+
from apexauthlib.entities.auth import ItemT, ServicePermission, ServiceUserInfo
|
|
11
|
+
from apexauthlib.integration.formatter import ServicePermissionFormatter
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@dataclass(frozen=True)
|
|
@@ -91,7 +92,7 @@ class AuthApi(Generic[ItemT]):
|
|
|
91
92
|
|
|
92
93
|
return ServiceUserInfo[ItemT](
|
|
93
94
|
user=self.user_formatter.load(user),
|
|
94
|
-
|
|
95
|
+
is_service_admin=bool(result["is_service_admin"]),
|
|
95
96
|
metadata=self.formatter.load(result["metadata"]),
|
|
96
97
|
)
|
|
97
98
|
|
|
@@ -114,10 +115,63 @@ class AuthApi(Generic[ItemT]):
|
|
|
114
115
|
|
|
115
116
|
yield ServiceUserInfo[ItemT](
|
|
116
117
|
user=self.user_formatter.load(user),
|
|
117
|
-
|
|
118
|
+
is_service_admin=bool(raw_user["is_service_admin"]),
|
|
118
119
|
metadata=self.formatter.load(raw_user["metadata"]),
|
|
119
120
|
)
|
|
120
121
|
|
|
122
|
+
def update_permissions(
|
|
123
|
+
self, permissions: list[ServicePermission]
|
|
124
|
+
) -> list[ServicePermission]:
|
|
125
|
+
existing = {
|
|
126
|
+
permission.name: permission
|
|
127
|
+
for permission in self._retrieve_existing_permissions()
|
|
128
|
+
}
|
|
129
|
+
new = {new_permission.name: new_permission for new_permission in permissions}
|
|
130
|
+
|
|
131
|
+
for current, current_permission in existing.items():
|
|
132
|
+
if current not in new.keys():
|
|
133
|
+
self._delete_permission(current_permission.id)
|
|
134
|
+
|
|
135
|
+
for current, current_permission in new.items():
|
|
136
|
+
if current not in existing.keys():
|
|
137
|
+
self._create_permission(current_permission)
|
|
138
|
+
|
|
139
|
+
return self._retrieve_existing_permissions()
|
|
140
|
+
|
|
141
|
+
def _retrieve_existing_permissions(self) -> list[ServicePermission]:
|
|
142
|
+
existing = list(
|
|
143
|
+
JsonDict(
|
|
144
|
+
(
|
|
145
|
+
self.http.with_header("Authorization", f"Bearer {self.token}")
|
|
146
|
+
.get()
|
|
147
|
+
.on_endpoint(f"/services/{self.service_name}/permissions")
|
|
148
|
+
.on_failure(raises=RuntimeError)
|
|
149
|
+
.json()
|
|
150
|
+
)
|
|
151
|
+
)["data"]["permissions"]
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return [ServicePermissionFormatter().load(item) for item in existing]
|
|
155
|
+
|
|
156
|
+
def _delete_permission(self, permission_id: str) -> None:
|
|
157
|
+
(
|
|
158
|
+
self.http.with_header("Authorization", f"Bearer {self.token}")
|
|
159
|
+
.delete()
|
|
160
|
+
.on_endpoint(f"/services/{self.service_name}/permissions/{permission_id}")
|
|
161
|
+
.on_failure(raises=RuntimeError)
|
|
162
|
+
.json()
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def _create_permission(self, permission: ServicePermission) -> None:
|
|
166
|
+
(
|
|
167
|
+
self.http.with_header("Authorization", f"Bearer {self.token}")
|
|
168
|
+
.with_json(JsonDict(ServicePermissionFormatter().dump(permission)))
|
|
169
|
+
.post()
|
|
170
|
+
.on_endpoint(f"/services/{self.service_name}/permissions")
|
|
171
|
+
.on_failure(raises=RuntimeError)
|
|
172
|
+
.json()
|
|
173
|
+
)
|
|
174
|
+
|
|
121
175
|
|
|
122
176
|
@dataclass
|
|
123
177
|
class AuthCodeApi:
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, Mapping
|
|
3
|
+
|
|
4
|
+
from apexauthlib.entities.auth import FieldType, ServicePermission
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class ServicePermissionFormatter:
|
|
9
|
+
def dump(self, permission: ServicePermission) -> Mapping[str, Any]:
|
|
10
|
+
raw = {
|
|
11
|
+
"name": permission.name,
|
|
12
|
+
"description": permission.description,
|
|
13
|
+
"label": permission.label,
|
|
14
|
+
"type": permission.type.value,
|
|
15
|
+
"values": permission.values,
|
|
16
|
+
"default": permission.default,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if permission.id.isdigit():
|
|
20
|
+
raw["id"] = permission.id
|
|
21
|
+
|
|
22
|
+
return raw
|
|
23
|
+
|
|
24
|
+
def load(self, raw: Mapping[str, Any]) -> ServicePermission:
|
|
25
|
+
permission_type = FieldType[str(raw["type"])]
|
|
26
|
+
|
|
27
|
+
return ServicePermission(
|
|
28
|
+
id=str(raw["id"]),
|
|
29
|
+
name=str(raw["name"]),
|
|
30
|
+
label=str(raw["label"]),
|
|
31
|
+
description=str(raw["description"]),
|
|
32
|
+
type=permission_type,
|
|
33
|
+
values=self._load_combos(permission_type, raw),
|
|
34
|
+
default=self._load_default(permission_type, raw),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def _load_combos(
|
|
38
|
+
self, permission_type: FieldType, raw: Mapping[str, Any]
|
|
39
|
+
) -> list[str] | list[int]:
|
|
40
|
+
if permission_type == FieldType.boolean:
|
|
41
|
+
return []
|
|
42
|
+
if permission_type == FieldType.string:
|
|
43
|
+
return [str(item) for item in list(raw["values"])]
|
|
44
|
+
if permission_type == FieldType.integer:
|
|
45
|
+
return [int(item) for item in list(raw["values"])]
|
|
46
|
+
|
|
47
|
+
raise ValueError(f"Unexpected type: {permission_type}")
|
|
48
|
+
|
|
49
|
+
def _load_default(
|
|
50
|
+
self, permission_type: FieldType, raw: Mapping[str, Any]
|
|
51
|
+
) -> str | int | bool:
|
|
52
|
+
if permission_type == FieldType.string:
|
|
53
|
+
return str(raw["default"])
|
|
54
|
+
if permission_type == FieldType.integer:
|
|
55
|
+
return int(raw["default"])
|
|
56
|
+
if permission_type == FieldType.boolean:
|
|
57
|
+
return bool(raw["default"])
|
|
58
|
+
raise ValueError(f"Unexpected type: {permission_type}")
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: apexauthlib
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Apex authorization library for services
|
|
5
|
+
License-File: LICENSE
|
|
5
6
|
Author: Apex Dev
|
|
6
7
|
Author-email: dev@apex.ge
|
|
7
8
|
Requires-Python: >=3.11
|
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
|
9
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
13
|
Requires-Dist: apexdevkit
|
|
12
|
-
Requires-Dist: fastapi
|
|
14
|
+
Requires-Dist: fastapi (==0.120.*)
|
|
13
15
|
Requires-Dist: httpx
|
|
14
16
|
Requires-Dist: uvicorn
|
|
15
17
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
apexauthlib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
apexauthlib/entities/__init__.py,sha256=KghMo6a2QWdPzWlMqdGAKOaVvRmTCOIVhXtIHrX7A_M,149
|
|
3
|
+
apexauthlib/entities/auth.py,sha256=AY34GnOhVhu0WCrpp0LoJ__r6ou-hORFiVExvCyCzmE,1566
|
|
4
|
+
apexauthlib/fastapi/__init__.py,sha256=G77C3ZIqjsXdh4fiH5FZyF_hyzVtS3waJJGa_TBGMWE,103
|
|
5
|
+
apexauthlib/fastapi/auth.py,sha256=hkvG2BougydElkYbEpwsuSgRoLOLANe6DbVSoa-zBRM,3917
|
|
6
|
+
apexauthlib/integration/__init__.py,sha256=f2lGbyoGct4kpZ2CUTExHhtQHs-1YR_xanvrj9Y4GiI,87
|
|
7
|
+
apexauthlib/integration/api.py,sha256=iSjaq6FrLOvnC86Y4DtV8O2fNqy09Tt5HjyAp707C4I,6478
|
|
8
|
+
apexauthlib/integration/formatter.py,sha256=DyVRMWYkZErZBeP_f4aYdSbe9g9zck-x2ONFPxwVNfY,2037
|
|
9
|
+
apexauthlib-0.1.10.dist-info/METADATA,sha256=I_SRgou9OOCkcl2eKC1ENrw6pvXN7SR6GsMk_CrsmQA,604
|
|
10
|
+
apexauthlib-0.1.10.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
11
|
+
apexauthlib-0.1.10.dist-info/licenses/LICENSE,sha256=iai0ILQTDgUXV1cIXl0UzSeOdFpMFK3shn5aqnz_Uro,1065
|
|
12
|
+
apexauthlib-0.1.10.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
apexauthlib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
apexauthlib/entities/__init__.py,sha256=KghMo6a2QWdPzWlMqdGAKOaVvRmTCOIVhXtIHrX7A_M,149
|
|
3
|
-
apexauthlib/entities/auth.py,sha256=TOs-3eNWodjrI8iFpozsNnn1KQTbPKCllbGzHSPYah8,836
|
|
4
|
-
apexauthlib/fastapi/__init__.py,sha256=G77C3ZIqjsXdh4fiH5FZyF_hyzVtS3waJJGa_TBGMWE,103
|
|
5
|
-
apexauthlib/fastapi/auth.py,sha256=hkvG2BougydElkYbEpwsuSgRoLOLANe6DbVSoa-zBRM,3917
|
|
6
|
-
apexauthlib/integration/__init__.py,sha256=f2lGbyoGct4kpZ2CUTExHhtQHs-1YR_xanvrj9Y4GiI,87
|
|
7
|
-
apexauthlib/integration/api.py,sha256=5GfD0K0abUjrK74hGB9dsUhqGkt2SFsg_cS7He4GQnk,4356
|
|
8
|
-
apexauthlib-0.1.8.dist-info/LICENSE,sha256=iai0ILQTDgUXV1cIXl0UzSeOdFpMFK3shn5aqnz_Uro,1065
|
|
9
|
-
apexauthlib-0.1.8.dist-info/METADATA,sha256=8oZ1_Zjfpuk838nqy7gLI5DR2iDf2vVQB7A7pUhqNko,518
|
|
10
|
-
apexauthlib-0.1.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
11
|
-
apexauthlib-0.1.8.dist-info/RECORD,,
|
|
File without changes
|