guardcoreapi 0.1.0__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 guardcoreapi might be problematic. Click here for more details.

@@ -0,0 +1,3 @@
1
+ from .manager import GuardCoreApi
2
+
3
+ __all__ = ["GuardCoreApi"]
@@ -0,0 +1,17 @@
1
+ from .request import RequestCore
2
+ from .exceptions import (
3
+ GuardCoreApiException,
4
+ RequestAuthenticationError,
5
+ RequestConnectionError,
6
+ RequestResponseError,
7
+ RequestTimeoutError,
8
+ )
9
+
10
+ __all__ = [
11
+ "RequestCore",
12
+ "GuardCoreApiException",
13
+ "RequestAuthenticationError",
14
+ "RequestConnectionError",
15
+ "RequestResponseError",
16
+ "RequestTimeoutError",
17
+ ]
@@ -0,0 +1,28 @@
1
+ class GuardCoreApiException(Exception):
2
+ """Base class for request errors."""
3
+
4
+ pass
5
+
6
+
7
+ class RequestTimeoutError(GuardCoreApiException):
8
+ """Exception raised for request timeouts."""
9
+
10
+ pass
11
+
12
+
13
+ class RequestConnectionError(GuardCoreApiException):
14
+ """Exception raised for connection errors."""
15
+
16
+ pass
17
+
18
+
19
+ class RequestResponseError(GuardCoreApiException):
20
+ """Exception raised for invalid responses."""
21
+
22
+ pass
23
+
24
+
25
+ class RequestAuthenticationError(GuardCoreApiException):
26
+ """Exception raised for authentication failures."""
27
+
28
+ pass
@@ -0,0 +1,140 @@
1
+ import asyncio
2
+ from typing import Optional
3
+
4
+ import aiohttp
5
+ from pydantic import BaseModel
6
+ from .exceptions import (
7
+ RequestAuthenticationError,
8
+ RequestConnectionError,
9
+ RequestResponseError,
10
+ RequestTimeoutError,
11
+ )
12
+
13
+
14
+ class RequestCore:
15
+ _BASE_URL = "https://core.erfjab.com"
16
+
17
+ @staticmethod
18
+ def generate_headers(access_token: Optional[str] = None) -> dict:
19
+ headers = {
20
+ "Accept": "application/json",
21
+ "Content-Type": "application/json",
22
+ }
23
+ if access_token:
24
+ headers["Authorization"] = f"Bearer {access_token}"
25
+ return headers
26
+
27
+ @staticmethod
28
+ async def fetch(
29
+ endpoint: str,
30
+ method: str = "GET",
31
+ headers: Optional[dict] = None,
32
+ params: Optional[dict] = None,
33
+ data: Optional[dict] = None,
34
+ json: Optional[dict] = None,
35
+ response_model: Optional[BaseModel] = None,
36
+ use_list: bool = False,
37
+ timeout: float = 10.0,
38
+ ) -> dict:
39
+ try:
40
+ async with aiohttp.ClientSession(
41
+ timeout=aiohttp.ClientTimeout(total=timeout)
42
+ ) as session:
43
+ async with session.request(
44
+ method=method,
45
+ url=RequestCore._BASE_URL + endpoint,
46
+ headers=headers,
47
+ params=params,
48
+ data=data,
49
+ json=json,
50
+ ) as response:
51
+ response.raise_for_status()
52
+ resp_json = await response.json()
53
+ if response_model:
54
+ if use_list:
55
+ return [response_model(**item) for item in resp_json]
56
+ return response_model(**resp_json)
57
+ return resp_json
58
+ except aiohttp.ClientResponseError as e:
59
+ if e.status == 401:
60
+ raise RequestAuthenticationError("Authentication failed") from e
61
+ else:
62
+ raise RequestResponseError(f"Invalid response: {e.status}") from e
63
+ except aiohttp.ClientConnectionError as e:
64
+ raise RequestConnectionError("Connection error occurred") from e
65
+ except asyncio.TimeoutError as e:
66
+ raise RequestTimeoutError("Request timed out") from e
67
+
68
+ @staticmethod
69
+ async def get(
70
+ endpoint: str,
71
+ headers: Optional[dict] = None,
72
+ params: Optional[dict] = None,
73
+ response_model: Optional[BaseModel] = None,
74
+ use_list: bool = False,
75
+ timeout: float = 10.0,
76
+ ) -> dict:
77
+ return await RequestCore.fetch(
78
+ endpoint=endpoint,
79
+ method="GET",
80
+ headers=headers,
81
+ params=params,
82
+ timeout=timeout,
83
+ use_list=use_list,
84
+ response_model=response_model,
85
+ )
86
+
87
+ @staticmethod
88
+ async def post(
89
+ endpoint: str,
90
+ headers: Optional[dict] = None,
91
+ data: Optional[dict] = None,
92
+ json: Optional[dict] = None,
93
+ timeout: float = 10.0,
94
+ response_model: Optional[BaseModel] = None,
95
+ use_list: bool = False,
96
+ ) -> dict:
97
+ return await RequestCore.fetch(
98
+ endpoint=endpoint,
99
+ method="POST",
100
+ headers=headers,
101
+ data=data,
102
+ json=json,
103
+ timeout=timeout,
104
+ response_model=response_model,
105
+ use_list=use_list,
106
+ )
107
+
108
+ @staticmethod
109
+ async def put(
110
+ endpoint: str,
111
+ headers: Optional[dict] = None,
112
+ data: Optional[dict] = None,
113
+ json: Optional[dict] = None,
114
+ timeout: float = 10.0,
115
+ response_model: Optional[BaseModel] = None,
116
+ use_list: bool = False,
117
+ ) -> dict:
118
+ return await RequestCore.fetch(
119
+ endpoint=endpoint,
120
+ method="PUT",
121
+ headers=headers,
122
+ data=data,
123
+ json=json,
124
+ timeout=timeout,
125
+ response_model=response_model,
126
+ use_list=use_list,
127
+ )
128
+
129
+ @staticmethod
130
+ async def delete(
131
+ endpoint: str,
132
+ headers: Optional[dict] = None,
133
+ timeout: float = 10.0,
134
+ ) -> dict:
135
+ return await RequestCore.fetch(
136
+ endpoint=endpoint,
137
+ method="DELETE",
138
+ headers=headers,
139
+ timeout=timeout,
140
+ )
@@ -0,0 +1,374 @@
1
+ from .core import RequestCore
2
+ from .types import (
3
+ AdminToken,
4
+ AdminResponse,
5
+ AdminCreate,
6
+ AdminCurrentUpdate,
7
+ AdminUsageLogsResponse,
8
+ AdminUpdate,
9
+ SubscriptionResponse,
10
+ SubscriptionCreate,
11
+ SubscriptionStatsResponse,
12
+ SubscriptionUpdate,
13
+ SubscriptionUsageLogsResponse,
14
+ NodeResponse,
15
+ NodeCreate,
16
+ NodeUpdate,
17
+ NodeStatsResponse,
18
+ ServiceCreate,
19
+ ServiceResponse,
20
+ ServiceUpdate,
21
+ )
22
+
23
+
24
+ class GuardCoreApi:
25
+ @staticmethod
26
+ async def get_all_admin(access: str) -> list[AdminResponse]:
27
+ return await RequestCore.get(
28
+ "/api/admins",
29
+ headers=RequestCore.generate_headers(access),
30
+ response_model=AdminResponse,
31
+ use_list=True,
32
+ )
33
+
34
+ @staticmethod
35
+ async def create_admin(data: AdminCreate, access: str) -> AdminResponse:
36
+ return await RequestCore.post(
37
+ "/api/admins",
38
+ headers=RequestCore.generate_headers(access),
39
+ json=data.dict(),
40
+ response_model=AdminResponse,
41
+ )
42
+
43
+ @staticmethod
44
+ async def generate_admin_token(username: str, password: str) -> AdminToken:
45
+ return await RequestCore.post(
46
+ "/api/admins/token",
47
+ data={
48
+ "username": username,
49
+ "password": password,
50
+ },
51
+ response_model=AdminToken,
52
+ )
53
+
54
+ @staticmethod
55
+ async def get_current_admin(access: str) -> AdminResponse:
56
+ return await RequestCore.get(
57
+ "/api/admins/current",
58
+ headers=RequestCore.generate_headers(access),
59
+ response_model=AdminResponse,
60
+ )
61
+
62
+ @staticmethod
63
+ async def update_current_admin(
64
+ data: AdminCurrentUpdate, access: str
65
+ ) -> AdminResponse:
66
+ return await RequestCore.put(
67
+ "/api/admins/current",
68
+ headers=RequestCore.generate_headers(access),
69
+ json=data.dict(),
70
+ response_model=AdminResponse,
71
+ )
72
+
73
+ @staticmethod
74
+ async def get_current_admin_usages(access: str) -> dict:
75
+ return await RequestCore.get(
76
+ "/api/admins/current/usages",
77
+ headers=RequestCore.generate_headers(access),
78
+ response_model=AdminUsageLogsResponse,
79
+ )
80
+
81
+ @staticmethod
82
+ async def get_admin(username: str, access: str) -> AdminResponse:
83
+ return await RequestCore.get(
84
+ f"/api/admins/{username}",
85
+ headers=RequestCore.generate_headers(access),
86
+ response_model=AdminResponse,
87
+ )
88
+
89
+ @staticmethod
90
+ async def update_admin(
91
+ username: str, data: AdminUpdate, access: str
92
+ ) -> AdminResponse:
93
+ return await RequestCore.put(
94
+ f"/api/admins/{username}",
95
+ headers=RequestCore.generate_headers(access),
96
+ json=data.dict(),
97
+ response_model=AdminResponse,
98
+ )
99
+
100
+ @staticmethod
101
+ async def delete_admin(username: str, access: str) -> dict:
102
+ return await RequestCore.post(
103
+ f"/api/admins/{username}/delete",
104
+ headers=RequestCore.generate_headers(access),
105
+ )
106
+
107
+ @staticmethod
108
+ async def get_admin_usages(username: str, access: str) -> dict:
109
+ return await RequestCore.get(
110
+ f"/api/admins/{username}/usages",
111
+ headers=RequestCore.generate_headers(access),
112
+ response_model=AdminUsageLogsResponse,
113
+ )
114
+
115
+ @staticmethod
116
+ async def enable_admin(username: str, access: str) -> AdminResponse:
117
+ return await RequestCore.post(
118
+ f"/api/admins/{username}/enable",
119
+ headers=RequestCore.generate_headers(access),
120
+ response_model=AdminResponse,
121
+ )
122
+
123
+ @staticmethod
124
+ async def disable_admin(username: str, access: str) -> AdminResponse:
125
+ return await RequestCore.post(
126
+ f"/api/admins/{username}/disable",
127
+ headers=RequestCore.generate_headers(access),
128
+ response_model=AdminResponse,
129
+ )
130
+
131
+ @staticmethod
132
+ async def get_admin_subscriptions(
133
+ username: str, access: str
134
+ ) -> list[SubscriptionResponse]:
135
+ return await RequestCore.get(
136
+ f"/api/admins/{username}/subscriptions",
137
+ headers=RequestCore.generate_headers(access),
138
+ response_model=SubscriptionResponse,
139
+ use_list=True,
140
+ )
141
+
142
+ @staticmethod
143
+ async def delete_admin_subscriptions(username: str, access: str) -> dict:
144
+ return await RequestCore.delete(
145
+ f"/api/admins/{username}/subscriptions",
146
+ headers=RequestCore.generate_headers(access),
147
+ )
148
+
149
+ @staticmethod
150
+ async def activate_admin_subscriptions(username: str, access: str) -> dict:
151
+ return await RequestCore.post(
152
+ f"/api/admins/{username}/subscriptions/activate",
153
+ headers=RequestCore.generate_headers(access),
154
+ )
155
+
156
+ @staticmethod
157
+ async def deactivate_admin_subscriptions(username: str, access: str) -> dict:
158
+ return await RequestCore.post(
159
+ f"/api/admins/{username}/subscriptions/deactivate",
160
+ headers=RequestCore.generate_headers(access),
161
+ )
162
+
163
+ @staticmethod
164
+ async def get_all_subscriptions(access: str) -> list[SubscriptionResponse]:
165
+ return await RequestCore.get(
166
+ "/api/subscriptions",
167
+ headers=RequestCore.generate_headers(access),
168
+ response_model=SubscriptionResponse,
169
+ use_list=True,
170
+ )
171
+
172
+ @staticmethod
173
+ async def create_subscription(
174
+ data: list[SubscriptionCreate], access: str
175
+ ) -> SubscriptionResponse:
176
+ return await RequestCore.post(
177
+ "/api/subscriptions",
178
+ headers=RequestCore.generate_headers(access),
179
+ json=[item.dict() for item in data],
180
+ response_model=SubscriptionResponse,
181
+ use_list=True,
182
+ )
183
+
184
+ @staticmethod
185
+ async def get_subscription_stats(access: str) -> SubscriptionStatsResponse:
186
+ return await RequestCore.get(
187
+ "/api/subscriptions/stats",
188
+ headers=RequestCore.generate_headers(access),
189
+ response_model=SubscriptionStatsResponse,
190
+ )
191
+
192
+ @staticmethod
193
+ async def get_subscription(username: str, access: str) -> SubscriptionResponse:
194
+ return await RequestCore.get(
195
+ f"/api/subscriptions/{username}",
196
+ headers=RequestCore.generate_headers(access),
197
+ response_model=SubscriptionResponse,
198
+ )
199
+
200
+ @staticmethod
201
+ async def update_subscription(
202
+ username: str, data: SubscriptionUpdate, access: str
203
+ ) -> SubscriptionResponse:
204
+ return await RequestCore.put(
205
+ f"/api/subscriptions/{username}",
206
+ headers=RequestCore.generate_headers(access),
207
+ json=data.dict(),
208
+ response_model=SubscriptionResponse,
209
+ )
210
+
211
+ @staticmethod
212
+ async def delete_subscription(username: str, access: str) -> dict:
213
+ return await RequestCore.delete(
214
+ f"/api/subscriptions/{username}",
215
+ headers=RequestCore.generate_headers(access),
216
+ )
217
+
218
+ @staticmethod
219
+ async def get_subscription_usages(
220
+ username: str, access: str
221
+ ) -> SubscriptionUsageLogsResponse:
222
+ return await RequestCore.get(
223
+ f"/api/subscriptions/{username}/usages",
224
+ headers=RequestCore.generate_headers(access),
225
+ response_model=SubscriptionUsageLogsResponse,
226
+ )
227
+
228
+ @staticmethod
229
+ async def enable_subscription(username: str, access: str) -> SubscriptionResponse:
230
+ return await RequestCore.post(
231
+ f"/api/subscriptions/{username}/enable",
232
+ headers=RequestCore.generate_headers(access),
233
+ response_model=SubscriptionResponse,
234
+ )
235
+
236
+ @staticmethod
237
+ async def disable_subscription(username: str, access: str) -> SubscriptionResponse:
238
+ return await RequestCore.post(
239
+ f"/api/subscriptions/{username}/disable",
240
+ headers=RequestCore.generate_headers(access),
241
+ response_model=SubscriptionResponse,
242
+ )
243
+
244
+ @staticmethod
245
+ async def revoke_subscription(username: str, access: str) -> SubscriptionResponse:
246
+ return await RequestCore.post(
247
+ f"/api/subscriptions/{username}/revoke",
248
+ headers=RequestCore.generate_headers(access),
249
+ response_model=SubscriptionResponse,
250
+ )
251
+
252
+ @staticmethod
253
+ async def reset_subscription(username: str, access: str) -> SubscriptionResponse:
254
+ return await RequestCore.post(
255
+ f"/api/subscriptions/{username}/reset",
256
+ headers=RequestCore.generate_headers(access),
257
+ response_model=SubscriptionResponse,
258
+ )
259
+
260
+ @staticmethod
261
+ async def get_nodes(access: str) -> list[NodeResponse]:
262
+ return await RequestCore.get(
263
+ "/api/nodes",
264
+ headers=RequestCore.generate_headers(access),
265
+ response_model=NodeResponse,
266
+ use_list=True,
267
+ )
268
+
269
+ @staticmethod
270
+ async def create_node(data: NodeCreate, access: str) -> NodeResponse:
271
+ return await RequestCore.post(
272
+ "/api/nodes",
273
+ headers=RequestCore.generate_headers(access),
274
+ json=data.dict(),
275
+ response_model=NodeResponse,
276
+ )
277
+
278
+ @staticmethod
279
+ async def get_node_stats(access: str) -> NodeStatsResponse:
280
+ return await RequestCore.get(
281
+ "/api/nodes/stats",
282
+ headers=RequestCore.generate_headers(access),
283
+ response_model=NodeStatsResponse,
284
+ )
285
+
286
+ @staticmethod
287
+ async def get_node(node_id: int, access: str) -> NodeResponse:
288
+ return await RequestCore.get(
289
+ f"/api/nodes/{node_id}",
290
+ headers=RequestCore.generate_headers(access),
291
+ response_model=NodeResponse,
292
+ )
293
+
294
+ @staticmethod
295
+ async def update_node(node_id: int, data: NodeUpdate, access: str) -> NodeResponse:
296
+ return await RequestCore.put(
297
+ f"/api/nodes/{node_id}",
298
+ headers=RequestCore.generate_headers(access),
299
+ json=data.dict(),
300
+ response_model=NodeResponse,
301
+ )
302
+
303
+ @staticmethod
304
+ async def delete_node(node_id: int, access: str) -> dict:
305
+ return await RequestCore.delete(
306
+ f"/api/nodes/{node_id}",
307
+ headers=RequestCore.generate_headers(access),
308
+ )
309
+
310
+ @staticmethod
311
+ async def enable_node(node_id: int, access: str) -> NodeResponse:
312
+ return await RequestCore.post(
313
+ f"/api/nodes/{node_id}/enable",
314
+ headers=RequestCore.generate_headers(access),
315
+ response_model=NodeResponse,
316
+ )
317
+
318
+ @staticmethod
319
+ async def disable_node(node_id: int, access: str) -> NodeResponse:
320
+ return await RequestCore.post(
321
+ f"/api/nodes/{node_id}/disable",
322
+ headers=RequestCore.generate_headers(access),
323
+ response_model=NodeResponse,
324
+ )
325
+
326
+ @staticmethod
327
+ async def get_services(access: str) -> list[ServiceResponse]:
328
+ return await RequestCore.get(
329
+ "/api/services",
330
+ headers=RequestCore.generate_headers(access),
331
+ response_model=ServiceResponse,
332
+ use_list=True,
333
+ )
334
+
335
+ @staticmethod
336
+ async def create_service(data: ServiceCreate, access: str) -> ServiceResponse:
337
+ return await RequestCore.post(
338
+ "/api/services",
339
+ headers=RequestCore.generate_headers(access),
340
+ json=data.dict(),
341
+ response_model=ServiceResponse,
342
+ )
343
+
344
+ @staticmethod
345
+ async def get_service(service_id: int, access: str) -> ServiceResponse:
346
+ return await RequestCore.get(
347
+ f"/api/services/{service_id}",
348
+ headers=RequestCore.generate_headers(access),
349
+ response_model=ServiceResponse,
350
+ )
351
+
352
+ @staticmethod
353
+ async def update_service(
354
+ service_id: int, data: ServiceUpdate, access: str
355
+ ) -> ServiceResponse:
356
+ return await RequestCore.put(
357
+ f"/api/services/{service_id}",
358
+ headers=RequestCore.generate_headers(access),
359
+ json=data.dict(),
360
+ response_model=ServiceResponse,
361
+ )
362
+
363
+ @staticmethod
364
+ async def delete_service(service_id: int, access: str) -> dict:
365
+ return await RequestCore.delete(
366
+ f"/api/services/{service_id}",
367
+ headers=RequestCore.generate_headers(access),
368
+ )
369
+
370
+ @staticmethod
371
+ async def get_guard(secret: str) -> list[str]:
372
+ return await RequestCore.get(
373
+ f"/api/guards/{secret}",
374
+ )
@@ -0,0 +1,58 @@
1
+ from .admins import (
2
+ AdminPlaceHolderCategory,
3
+ AdminPlaceHolder,
4
+ AdminRole,
5
+ AdminToken,
6
+ AdminResponse,
7
+ ADMIN_PLACEHOLDER_REMARK_FORMATS,
8
+ AdminCreate,
9
+ AdminCurrentUpdate,
10
+ AdminUpdate,
11
+ AdminUsageLog,
12
+ AdminUsageLogsResponse,
13
+ )
14
+ from .subscriptions import (
15
+ SubscriptionCreate,
16
+ SubscriptionResponse,
17
+ SubscriptionUpdate,
18
+ SubscriptionUsageLog,
19
+ SubscriptionUsageLogsResponse,
20
+ SubscriptionStatsResponse,
21
+ )
22
+ from .nodes import (
23
+ NodeCategory,
24
+ NodeResponse,
25
+ NodeCreate,
26
+ NodeUpdate,
27
+ NodeStatsResponse,
28
+ )
29
+ from .services import ServiceResponse, ServiceCreate, ServiceUpdate
30
+
31
+
32
+ __all__ = [
33
+ "AdminPlaceHolderCategory",
34
+ "AdminPlaceHolder",
35
+ "AdminRole",
36
+ "AdminToken",
37
+ "AdminResponse",
38
+ "ADMIN_PLACEHOLDER_REMARK_FORMATS",
39
+ "AdminCreate",
40
+ "AdminCurrentUpdate",
41
+ "AdminUpdate",
42
+ "AdminUsageLog",
43
+ "AdminUsageLogsResponse",
44
+ "SubscriptionCreate",
45
+ "SubscriptionResponse",
46
+ "SubscriptionUpdate",
47
+ "SubscriptionUsageLog",
48
+ "SubscriptionUsageLogsResponse",
49
+ "SubscriptionStatsResponse",
50
+ "NodeCategory",
51
+ "NodeResponse",
52
+ "NodeCreate",
53
+ "NodeUpdate",
54
+ "NodeStatsResponse",
55
+ "ServiceResponse",
56
+ "ServiceCreate",
57
+ "ServiceUpdate",
58
+ ]
@@ -0,0 +1,117 @@
1
+ from enum import StrEnum
2
+ from typing import Optional
3
+ from datetime import datetime
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class AdminPlaceHolderCategory(StrEnum):
8
+ INFO = "info"
9
+ LIMITED = "limited"
10
+ EXPIRED = "expired"
11
+ DISABLED = "disabled"
12
+
13
+
14
+ ADMIN_PLACEHOLDER_REMARK_FORMATS = [
15
+ "id",
16
+ "username",
17
+ "owner_username",
18
+ "enabled",
19
+ "activated",
20
+ "limited",
21
+ "expired",
22
+ "is_active",
23
+ "limit_usage",
24
+ "current_usage",
25
+ "left_usage",
26
+ "expire_date",
27
+ "expire_in",
28
+ "expire_in_days",
29
+ ]
30
+
31
+
32
+ class AdminPlaceHolder(BaseModel):
33
+ remark: str
34
+ categories: list[AdminPlaceHolderCategory]
35
+
36
+
37
+ class AdminRole(StrEnum):
38
+ OWNER = "owner"
39
+ RESELLER = "reseller"
40
+
41
+
42
+ class AdminToken(BaseModel):
43
+ access_token: str
44
+ token_type: str = "bearer"
45
+
46
+
47
+ class AdminResponse(BaseModel):
48
+ id: int
49
+ enabled: bool
50
+ removed: bool
51
+ username: str
52
+ role: AdminRole
53
+ service_ids: list[int]
54
+ create_access: Optional[bool]
55
+ update_access: Optional[bool]
56
+ remove_access: Optional[bool]
57
+ count_limit: Optional[int]
58
+ current_count: Optional[int]
59
+ left_count: Optional[int]
60
+ reached_count_limit: Optional[bool]
61
+ usage_limit: Optional[int]
62
+ current_usage: Optional[int]
63
+ left_usage: Optional[int]
64
+ reached_usage_limit: Optional[bool]
65
+ placeholders: Optional[list[AdminPlaceHolder]]
66
+ max_links: Optional[int]
67
+ last_login_at: Optional[datetime]
68
+ last_online_at: Optional[datetime]
69
+ created_at: datetime
70
+ updated_at: datetime
71
+
72
+ class Config:
73
+ from_attributes = True
74
+
75
+
76
+ class AdminCreate(BaseModel):
77
+ username: str
78
+ password: str
79
+ role: AdminRole
80
+ service_ids: Optional[list[int]]
81
+ create_access: Optional[bool] = False
82
+ update_access: Optional[bool] = False
83
+ remove_access: Optional[bool] = False
84
+ count_limit: Optional[int] = None
85
+ usage_limit: Optional[int] = None
86
+ access_prefix: Optional[str] = None
87
+
88
+
89
+ class AdminUpdate(BaseModel):
90
+ password: Optional[str] = None
91
+ create_access: Optional[bool] = None
92
+ update_access: Optional[bool] = None
93
+ remove_access: Optional[bool] = None
94
+ count_limit: Optional[int] = None
95
+ usage_limit: Optional[int] = None
96
+ service_ids: Optional[list[int]] = None
97
+ placeholders: Optional[list[AdminPlaceHolder]] = None
98
+ max_links: Optional[int] = None
99
+ shuffle_links: Optional[bool] = None
100
+ access_prefix: Optional[str] = None
101
+
102
+
103
+ class AdminCurrentUpdate(BaseModel):
104
+ password: Optional[str] = None
105
+ placeholders: Optional[list[AdminPlaceHolder]] = None
106
+ max_links: Optional[int] = None
107
+ shuffle_links: Optional[bool] = None
108
+
109
+
110
+ class AdminUsageLog(BaseModel):
111
+ usage: int
112
+ created_at: datetime
113
+
114
+
115
+ class AdminUsageLogsResponse(BaseModel):
116
+ admin: AdminResponse
117
+ usages: list[AdminUsageLog]
@@ -0,0 +1,49 @@
1
+ from enum import StrEnum
2
+ from datetime import datetime
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class NodeCategory(StrEnum):
7
+ marzban = "marzban"
8
+ marzneshin = "marzneshin"
9
+
10
+
11
+ class NodeResponse(BaseModel):
12
+ id: int
13
+ enabled: bool
14
+ remark: str
15
+ category: NodeCategory
16
+ username: str
17
+ password: str
18
+ host: str
19
+ created_at: datetime
20
+ updated_at: datetime
21
+
22
+ class Config:
23
+ from_attributes = True
24
+
25
+
26
+ class NodeCreate(BaseModel):
27
+ remark: str
28
+ category: NodeCategory
29
+ username: str
30
+ password: str
31
+ host: str
32
+ offset_link: int = 0
33
+
34
+
35
+ class NodeUpdate(BaseModel):
36
+ remark: str | None = None
37
+ username: str | None = None
38
+ password: str | None = None
39
+ host: str | None = None
40
+ offset_link: int | None = None
41
+
42
+
43
+ class NodeStatsResponse(BaseModel):
44
+ total_nodes: int
45
+ active_nodes: int
46
+ inactive_nodes: int
47
+
48
+ class Config:
49
+ from_attributes = True
@@ -0,0 +1,21 @@
1
+ from typing import List
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class ServiceResponse(BaseModel):
6
+ id: int
7
+ remark: str
8
+ node_ids: List[int]
9
+
10
+ class Config:
11
+ from_attributes = True
12
+
13
+
14
+ class ServiceCreate(BaseModel):
15
+ remark: str
16
+ node_ids: List[int]
17
+
18
+
19
+ class ServiceUpdate(BaseModel):
20
+ remark: str | None = None
21
+ node_ids: List[int] | None = None
@@ -0,0 +1,68 @@
1
+ from typing import Optional
2
+ from datetime import datetime
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class SubscriptionResponse(BaseModel):
7
+ id: int
8
+ username: str
9
+ owner_username: str
10
+ access_key: str
11
+
12
+ enabled: bool
13
+ activated: bool
14
+ limited: bool
15
+ expired: bool
16
+ is_active: bool
17
+
18
+ link: str
19
+
20
+ limit_usage: int
21
+ reset_usage: int
22
+ total_usage: int
23
+ current_usage: int
24
+ limit_expire: int
25
+
26
+ last_reset_at: Optional[datetime]
27
+ last_revoke_at: Optional[datetime]
28
+ last_request_at: Optional[datetime]
29
+ last_client_agent: Optional[str]
30
+ created_at: datetime
31
+ updated_at: datetime
32
+
33
+ class Config:
34
+ from_attributes = True
35
+
36
+
37
+ class SubscriptionCreate(BaseModel):
38
+ username: str
39
+ limit_usage: int
40
+ limit_expire: int
41
+
42
+
43
+ class SubscriptionUpdate(BaseModel):
44
+ limit_usage: Optional[int] = None
45
+ limit_expire: Optional[int] = None
46
+
47
+
48
+ class SubscriptionUsageLog(BaseModel):
49
+ usage: int
50
+ created_at: datetime
51
+
52
+
53
+ class SubscriptionUsageLogsResponse(BaseModel):
54
+ subscription: SubscriptionResponse
55
+ usages: list[SubscriptionUsageLog]
56
+
57
+
58
+ class SubscriptionStatsResponse(BaseModel):
59
+ total: int
60
+ active: int
61
+ inactive: int
62
+ disabled: int
63
+ expired: int
64
+ limited: int
65
+ has_revoked: int
66
+ has_reseted: int
67
+ total_removed: int
68
+ total_usage: int
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: guardcoreapi
3
+ Version: 0.1.0
4
+ Summary: Guard Management Core Api Python lib
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: aiohttp>=3.13.1
9
+ Requires-Dist: pydantic>=2.12.3
10
+ Dynamic: license-file
@@ -0,0 +1,15 @@
1
+ guardcoreapi/__init__.py,sha256=GohrmPFFH_Bfa5Ex3n0u-c4RjU47KbmoBYi38k8S_NI,62
2
+ guardcoreapi/manager.py,sha256=D0wKFdCb7kFCa9ZbUX-pDxJ8XffSxIiXUjx6tgtvx7M,12570
3
+ guardcoreapi/core/__init__.py,sha256=QJhZCPZui7zDpnQJbmWZsEijiAAP3rglUZb_w6E61_M,381
4
+ guardcoreapi/core/exceptions.py,sha256=KbmdV8p31gSlKXjmJoW3lR9wGOQSvaaZKl9oGb7qlFI,555
5
+ guardcoreapi/core/request.py,sha256=HMPHwReoxCPIop2rnQxPN5A1icU0JBI11HuG2kO_-XM,4327
6
+ guardcoreapi/types/__init__.py,sha256=AtHWIIQoso_L5jb6nozhNBs6_0Tm2Zvvj8VvaH5eKwg,1275
7
+ guardcoreapi/types/admins.py,sha256=sOF8dODF9cNABCOVJJd3Cqc9juggIYq0sAyphJT5PFk,2800
8
+ guardcoreapi/types/nodes.py,sha256=m89zmH_f9iNGkU8wC7HHPlDAxQZy6reptEk_X84H8CA,919
9
+ guardcoreapi/types/services.py,sha256=3lpP76Q9iij2zSEXutDg1IatIslLokQ-DNPvSdckRCQ,369
10
+ guardcoreapi/types/subscriptions.py,sha256=3AwwNmyXVYq7KLaiGdCuECRMsqWCNdrZbRpC2LkhGjQ,1336
11
+ guardcoreapi-0.1.0.dist-info/licenses/LICENSE,sha256=BPTJfvegcaek6E2PQ2rViLbxbfB1AbjIauxVQWo5Od4,1062
12
+ guardcoreapi-0.1.0.dist-info/METADATA,sha256=JGV4PVDmJYhxQ65AbzCa-OFJqBgDj0TXqnuWSw0Wv5U,273
13
+ guardcoreapi-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ guardcoreapi-0.1.0.dist-info/top_level.txt,sha256=ArZR_iOVG8XvUCTMHioVgKI8CkJOX_yH8t7898OXBF8,13
15
+ guardcoreapi-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Erfan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ guardcoreapi