apexauthlib 0.1.8__tar.gz → 0.1.10__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.
@@ -1,15 +1,17 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: apexauthlib
3
- Version: 0.1.8
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
@@ -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
- superuser: str
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
- is_superuser: bool
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}")
@@ -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
- is_superuser=bool(result["is_superuser"]),
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
- is_superuser=bool(raw_user["is_superuser"]),
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "apexauthlib"
3
- version = "0.1.8"
3
+ version = "0.1.10"
4
4
  description = "Apex authorization library for services"
5
5
  authors = [{ name = "Apex Dev", email = "dev@apex.ge" }]
6
6
  readme = "README.md"
@@ -9,7 +9,7 @@ requires-python = ">=3.11"
9
9
  [tool.poetry.dependencies]
10
10
  python = "^3.12"
11
11
  httpx = "*"
12
- fastapi = "*"
12
+ fastapi = "0.120.*"
13
13
  uvicorn = "*"
14
14
  apexdevkit = "*"
15
15
 
File without changes
File without changes