proxyhat 0.2.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.
@@ -0,0 +1,107 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ import httpx
6
+
7
+ from proxyhat.types.payments import Cryptocurrency, Payment, PaymentCreateResponse, PaymentDetails
8
+
9
+ if TYPE_CHECKING:
10
+ from proxyhat.async_client import AsyncProxyHat
11
+ from proxyhat.client import ProxyHat
12
+
13
+
14
+ class PaymentsResource:
15
+ def __init__(self, client: ProxyHat) -> None:
16
+ self._client = client
17
+
18
+ def list(self) -> list[Payment]:
19
+ data = self._client.request("GET", "/payments")
20
+ if isinstance(data, list):
21
+ return [Payment.from_dict(item) for item in data]
22
+ return []
23
+
24
+ def create(
25
+ self,
26
+ *,
27
+ type: str,
28
+ plan_id: str,
29
+ gate: str = "crypto",
30
+ cryptocurrency_code: str,
31
+ coupon_code: str | None = None,
32
+ ) -> PaymentCreateResponse:
33
+ body: dict[str, Any] = {
34
+ "type": type,
35
+ "plan_id": plan_id,
36
+ "gate": gate,
37
+ "cryptocurrency_code": cryptocurrency_code,
38
+ }
39
+ if coupon_code is not None:
40
+ body["coupon_code"] = coupon_code
41
+ data = self._client.request("POST", "/payments", json=body)
42
+ return PaymentCreateResponse.from_dict(data)
43
+
44
+ def get(self, id: str) -> PaymentDetails:
45
+ data = self._client.request("GET", f"/payments/{id}")
46
+ return PaymentDetails.from_dict(data)
47
+
48
+ def check(self, id: str) -> PaymentDetails:
49
+ data = self._client.request("GET", f"/payments/{id}/check")
50
+ return PaymentDetails.from_dict(data)
51
+
52
+ def invoice(self, id: str, *, format: str = "pdf") -> httpx.Response:
53
+ return self._client.request_raw("GET", f"/payments/{id}/invoice", params={"format": format})
54
+
55
+ def cryptocurrencies(self) -> list[Cryptocurrency]:
56
+ data = self._client.request("GET", "/payments/cryptocurrencies")
57
+ if isinstance(data, list):
58
+ return [Cryptocurrency.from_dict(item) for item in data]
59
+ return []
60
+
61
+
62
+ class AsyncPaymentsResource:
63
+ def __init__(self, client: AsyncProxyHat) -> None:
64
+ self._client = client
65
+
66
+ async def list(self) -> list[Payment]:
67
+ data = await self._client.request("GET", "/payments")
68
+ if isinstance(data, list):
69
+ return [Payment.from_dict(item) for item in data]
70
+ return []
71
+
72
+ async def create(
73
+ self,
74
+ *,
75
+ type: str,
76
+ plan_id: str,
77
+ gate: str = "crypto",
78
+ cryptocurrency_code: str,
79
+ coupon_code: str | None = None,
80
+ ) -> PaymentCreateResponse:
81
+ body: dict[str, Any] = {
82
+ "type": type,
83
+ "plan_id": plan_id,
84
+ "gate": gate,
85
+ "cryptocurrency_code": cryptocurrency_code,
86
+ }
87
+ if coupon_code is not None:
88
+ body["coupon_code"] = coupon_code
89
+ data = await self._client.request("POST", "/payments", json=body)
90
+ return PaymentCreateResponse.from_dict(data)
91
+
92
+ async def get(self, id: str) -> PaymentDetails:
93
+ data = await self._client.request("GET", f"/payments/{id}")
94
+ return PaymentDetails.from_dict(data)
95
+
96
+ async def check(self, id: str) -> PaymentDetails:
97
+ data = await self._client.request("GET", f"/payments/{id}/check")
98
+ return PaymentDetails.from_dict(data)
99
+
100
+ async def invoice(self, id: str, *, format: str = "pdf") -> httpx.Response:
101
+ return await self._client.request_raw("GET", f"/payments/{id}/invoice", params={"format": format})
102
+
103
+ async def cryptocurrencies(self) -> list[Cryptocurrency]:
104
+ data = await self._client.request("GET", "/payments/cryptocurrencies")
105
+ if isinstance(data, list):
106
+ return [Cryptocurrency.from_dict(item) for item in data]
107
+ return []
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.plans import RegularPlan, SubscriptionPlan
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ class PlansResource:
13
+ def __init__(self, client: ProxyHat) -> None:
14
+ self._client = client
15
+
16
+ def list_regular(self) -> list[RegularPlan]:
17
+ data = self._client.request("GET", "/regular-options")
18
+ if isinstance(data, list):
19
+ return [RegularPlan.from_dict(item) for item in data]
20
+ return []
21
+
22
+ def list_subscriptions(self) -> list[SubscriptionPlan]:
23
+ data = self._client.request("GET", "/subscription-plans")
24
+ if isinstance(data, list):
25
+ return [SubscriptionPlan.from_dict(item) for item in data]
26
+ return []
27
+
28
+ def get_regular(self, name: str) -> RegularPlan:
29
+ data = self._client.request("GET", f"/plans/regular/{name}")
30
+ return RegularPlan.from_dict(data)
31
+
32
+ def get_subscription(self, name: str) -> SubscriptionPlan:
33
+ data = self._client.request("GET", f"/plans/subscription/{name}")
34
+ return SubscriptionPlan.from_dict(data)
35
+
36
+ def pricing_regular(self) -> list[Any]:
37
+ data = self._client.request("GET", "/pricing/regular")
38
+ if isinstance(data, list):
39
+ return data
40
+ return []
41
+
42
+ def pricing_subscriptions(self) -> list[Any]:
43
+ data = self._client.request("GET", "/pricing/subscriptions")
44
+ if isinstance(data, list):
45
+ return data
46
+ return []
47
+
48
+
49
+ class AsyncPlansResource:
50
+ def __init__(self, client: AsyncProxyHat) -> None:
51
+ self._client = client
52
+
53
+ async def list_regular(self) -> list[RegularPlan]:
54
+ data = await self._client.request("GET", "/regular-options")
55
+ if isinstance(data, list):
56
+ return [RegularPlan.from_dict(item) for item in data]
57
+ return []
58
+
59
+ async def list_subscriptions(self) -> list[SubscriptionPlan]:
60
+ data = await self._client.request("GET", "/subscription-plans")
61
+ if isinstance(data, list):
62
+ return [SubscriptionPlan.from_dict(item) for item in data]
63
+ return []
64
+
65
+ async def get_regular(self, name: str) -> RegularPlan:
66
+ data = await self._client.request("GET", f"/plans/regular/{name}")
67
+ return RegularPlan.from_dict(data)
68
+
69
+ async def get_subscription(self, name: str) -> SubscriptionPlan:
70
+ data = await self._client.request("GET", f"/plans/subscription/{name}")
71
+ return SubscriptionPlan.from_dict(data)
72
+
73
+ async def pricing_regular(self) -> list[Any]:
74
+ data = await self._client.request("GET", "/pricing/regular")
75
+ if isinstance(data, list):
76
+ return data
77
+ return []
78
+
79
+ async def pricing_subscriptions(self) -> list[Any]:
80
+ data = await self._client.request("GET", "/pricing/subscriptions")
81
+ if isinstance(data, list):
82
+ return data
83
+ return []
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.profile import APIKey, Preferences
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ class ProfileResource:
13
+ def __init__(self, client: ProxyHat) -> None:
14
+ self._client = client
15
+
16
+ def get_preferences(self) -> Preferences:
17
+ data = self._client.request("GET", "/profile/preferences")
18
+ return Preferences.from_dict(data)
19
+
20
+ def update_preferences(self, **preferences: Any) -> Preferences:
21
+ data = self._client.request("PUT", "/profile/preferences", json=preferences)
22
+ return Preferences.from_dict(data)
23
+
24
+ def list_api_keys(self) -> list[APIKey]:
25
+ data = self._client.request("GET", "/profile/api-keys")
26
+ if isinstance(data, list):
27
+ return [APIKey.from_dict(item) for item in data]
28
+ return []
29
+
30
+ def create_api_key(self, *, name: str | None = None) -> APIKey:
31
+ body: dict[str, Any] = {}
32
+ if name is not None:
33
+ body["name"] = name
34
+ data = self._client.request("POST", "/profile/api-keys", json=body)
35
+ return APIKey.from_dict(data)
36
+
37
+ def delete_api_key(self, id: str) -> None:
38
+ self._client.request("DELETE", f"/profile/api-keys/{id}")
39
+
40
+ def regenerate_api_key(self, id: str) -> APIKey:
41
+ data = self._client.request("POST", f"/profile/api-keys/{id}/regenerate")
42
+ return APIKey.from_dict(data)
43
+
44
+
45
+ class AsyncProfileResource:
46
+ def __init__(self, client: AsyncProxyHat) -> None:
47
+ self._client = client
48
+
49
+ async def get_preferences(self) -> Preferences:
50
+ data = await self._client.request("GET", "/profile/preferences")
51
+ return Preferences.from_dict(data)
52
+
53
+ async def update_preferences(self, **preferences: Any) -> Preferences:
54
+ data = await self._client.request("PUT", "/profile/preferences", json=preferences)
55
+ return Preferences.from_dict(data)
56
+
57
+ async def list_api_keys(self) -> list[APIKey]:
58
+ data = await self._client.request("GET", "/profile/api-keys")
59
+ if isinstance(data, list):
60
+ return [APIKey.from_dict(item) for item in data]
61
+ return []
62
+
63
+ async def create_api_key(self, *, name: str | None = None) -> APIKey:
64
+ body: dict[str, Any] = {}
65
+ if name is not None:
66
+ body["name"] = name
67
+ data = await self._client.request("POST", "/profile/api-keys", json=body)
68
+ return APIKey.from_dict(data)
69
+
70
+ async def delete_api_key(self, id: str) -> None:
71
+ await self._client.request("DELETE", f"/profile/api-keys/{id}")
72
+
73
+ async def regenerate_api_key(self, id: str) -> APIKey:
74
+ data = await self._client.request("POST", f"/profile/api-keys/{id}/regenerate")
75
+ return APIKey.from_dict(data)
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.proxy_descriptor import ProxyDescriptor
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ def _body(
13
+ sub_user_uuid: str,
14
+ protocol: str,
15
+ location: dict[str, Any] | None,
16
+ session: dict[str, Any] | None,
17
+ filter: str | None,
18
+ ) -> dict[str, Any]:
19
+ body: dict[str, Any] = {"sub_user_uuid": sub_user_uuid, "protocol": protocol}
20
+ if location is not None:
21
+ body["location"] = location
22
+ if session is not None:
23
+ body["session"] = session
24
+ if filter is not None:
25
+ body["filter"] = filter
26
+ return body
27
+
28
+
29
+ class ProxyDescriptorsResource:
30
+ def __init__(self, client: ProxyHat) -> None:
31
+ self._client = client
32
+
33
+ def create(
34
+ self,
35
+ *,
36
+ sub_user_uuid: str,
37
+ protocol: str = "http",
38
+ location: dict[str, Any] | None = None,
39
+ session: dict[str, Any] | None = None,
40
+ filter: str | None = None,
41
+ ) -> ProxyDescriptor:
42
+ data = self._client.request(
43
+ "POST", "/proxy-descriptors", json=_body(sub_user_uuid, protocol, location, session, filter)
44
+ )
45
+ return ProxyDescriptor.from_dict(data)
46
+
47
+
48
+ class AsyncProxyDescriptorsResource:
49
+ def __init__(self, client: AsyncProxyHat) -> None:
50
+ self._client = client
51
+
52
+ async def create(
53
+ self,
54
+ *,
55
+ sub_user_uuid: str,
56
+ protocol: str = "http",
57
+ location: dict[str, Any] | None = None,
58
+ session: dict[str, Any] | None = None,
59
+ filter: str | None = None,
60
+ ) -> ProxyDescriptor:
61
+ data = await self._client.request(
62
+ "POST", "/proxy-descriptors", json=_body(sub_user_uuid, protocol, location, session, filter)
63
+ )
64
+ return ProxyDescriptor.from_dict(data)
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.proxy_presets import ProxyPreset
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ class ProxyPresetsResource:
13
+ def __init__(self, client: ProxyHat) -> None:
14
+ self._client = client
15
+
16
+ def list(self) -> list[ProxyPreset]:
17
+ data = self._client.request("GET", "/proxy-presets")
18
+ if isinstance(data, list):
19
+ return [ProxyPreset.from_dict(item) for item in data]
20
+ return []
21
+
22
+ def create(self, *, name: str, data: dict[str, Any]) -> ProxyPreset:
23
+ result = self._client.request("POST", "/proxy-presets", json={"name": name, "data": data})
24
+ return ProxyPreset.from_dict(result)
25
+
26
+ def get(self, id: str) -> ProxyPreset:
27
+ data = self._client.request("GET", f"/proxy-presets/{id}")
28
+ return ProxyPreset.from_dict(data)
29
+
30
+ def update(self, id: str, *, name: str | None = None, data: dict[str, Any] | None = None) -> ProxyPreset:
31
+ body: dict[str, Any] = {}
32
+ if name is not None:
33
+ body["name"] = name
34
+ if data is not None:
35
+ body["data"] = data
36
+ result = self._client.request("PUT", f"/proxy-presets/{id}", json=body)
37
+ return ProxyPreset.from_dict(result)
38
+
39
+ def delete(self, id: str) -> None:
40
+ self._client.request("DELETE", f"/proxy-presets/{id}")
41
+
42
+
43
+ class AsyncProxyPresetsResource:
44
+ def __init__(self, client: AsyncProxyHat) -> None:
45
+ self._client = client
46
+
47
+ async def list(self) -> list[ProxyPreset]:
48
+ data = await self._client.request("GET", "/proxy-presets")
49
+ if isinstance(data, list):
50
+ return [ProxyPreset.from_dict(item) for item in data]
51
+ return []
52
+
53
+ async def create(self, *, name: str, data: dict[str, Any]) -> ProxyPreset:
54
+ result = await self._client.request("POST", "/proxy-presets", json={"name": name, "data": data})
55
+ return ProxyPreset.from_dict(result)
56
+
57
+ async def get(self, id: str) -> ProxyPreset:
58
+ data = await self._client.request("GET", f"/proxy-presets/{id}")
59
+ return ProxyPreset.from_dict(data)
60
+
61
+ async def update(self, id: str, *, name: str | None = None, data: dict[str, Any] | None = None) -> ProxyPreset:
62
+ body: dict[str, Any] = {}
63
+ if name is not None:
64
+ body["name"] = name
65
+ if data is not None:
66
+ body["data"] = data
67
+ result = await self._client.request("PUT", f"/proxy-presets/{id}", json=body)
68
+ return ProxyPreset.from_dict(result)
69
+
70
+ async def delete(self, id: str) -> None:
71
+ await self._client.request("DELETE", f"/proxy-presets/{id}")
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.sub_user_groups import SubUserGroup
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ class SubUserGroupsResource:
13
+ def __init__(self, client: ProxyHat) -> None:
14
+ self._client = client
15
+
16
+ def list(self) -> list[SubUserGroup]:
17
+ data = self._client.request("GET", "/sub-user-groups")
18
+ if isinstance(data, list):
19
+ return [SubUserGroup.from_dict(item) for item in data]
20
+ return []
21
+
22
+ def create(self, *, name: str, description: str | None = None) -> SubUserGroup:
23
+ body: dict[str, Any] = {"name": name}
24
+ if description is not None:
25
+ body["description"] = description
26
+ data = self._client.request("POST", "/sub-user-groups", json=body)
27
+ return SubUserGroup.from_dict(data)
28
+
29
+ def get(self, id: str) -> SubUserGroup:
30
+ data = self._client.request("GET", f"/sub-user-groups/{id}")
31
+ return SubUserGroup.from_dict(data)
32
+
33
+ def update(self, id: str, *, name: str | None = None, description: str | None = None) -> SubUserGroup:
34
+ body: dict[str, Any] = {}
35
+ if name is not None:
36
+ body["name"] = name
37
+ if description is not None:
38
+ body["description"] = description
39
+ data = self._client.request("PUT", f"/sub-user-groups/{id}", json=body)
40
+ return SubUserGroup.from_dict(data)
41
+
42
+ def delete(self, id: str) -> None:
43
+ self._client.request("DELETE", f"/sub-user-groups/{id}")
44
+
45
+
46
+ class AsyncSubUserGroupsResource:
47
+ def __init__(self, client: AsyncProxyHat) -> None:
48
+ self._client = client
49
+
50
+ async def list(self) -> list[SubUserGroup]:
51
+ data = await self._client.request("GET", "/sub-user-groups")
52
+ if isinstance(data, list):
53
+ return [SubUserGroup.from_dict(item) for item in data]
54
+ return []
55
+
56
+ async def create(self, *, name: str, description: str | None = None) -> SubUserGroup:
57
+ body: dict[str, Any] = {"name": name}
58
+ if description is not None:
59
+ body["description"] = description
60
+ data = await self._client.request("POST", "/sub-user-groups", json=body)
61
+ return SubUserGroup.from_dict(data)
62
+
63
+ async def get(self, id: str) -> SubUserGroup:
64
+ data = await self._client.request("GET", f"/sub-user-groups/{id}")
65
+ return SubUserGroup.from_dict(data)
66
+
67
+ async def update(self, id: str, *, name: str | None = None, description: str | None = None) -> SubUserGroup:
68
+ body: dict[str, Any] = {}
69
+ if name is not None:
70
+ body["name"] = name
71
+ if description is not None:
72
+ body["description"] = description
73
+ data = await self._client.request("PUT", f"/sub-user-groups/{id}", json=body)
74
+ return SubUserGroup.from_dict(data)
75
+
76
+ async def delete(self, id: str) -> None:
77
+ await self._client.request("DELETE", f"/sub-user-groups/{id}")
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from proxyhat.types.sub_user import BulkDeleteResponse, ResetUsageResponse, SubUser
6
+
7
+ if TYPE_CHECKING:
8
+ from proxyhat.async_client import AsyncProxyHat
9
+ from proxyhat.client import ProxyHat
10
+
11
+
12
+ class SubUsersResource:
13
+ def __init__(self, client: ProxyHat) -> None:
14
+ self._client = client
15
+
16
+ def list(self) -> list[SubUser]:
17
+ data = self._client.request("GET", "/sub-users")
18
+ if isinstance(data, list):
19
+ return [SubUser.from_dict(item) for item in data]
20
+ return []
21
+
22
+ def create(
23
+ self,
24
+ *,
25
+ proxy_password: str,
26
+ is_traffic_limited: bool = False,
27
+ traffic_limit: str | None = None,
28
+ name: str | None = None,
29
+ notes: str | None = None,
30
+ sub_user_group_id: str | None = None,
31
+ ) -> SubUser:
32
+ body: dict[str, Any] = {
33
+ "proxy_password": proxy_password,
34
+ "is_traffic_limited": is_traffic_limited,
35
+ }
36
+ if traffic_limit is not None:
37
+ body["traffic_limit"] = traffic_limit
38
+ if name is not None:
39
+ body["name"] = name
40
+ if notes is not None:
41
+ body["notes"] = notes
42
+ if sub_user_group_id is not None:
43
+ body["sub_user_group_id"] = sub_user_group_id
44
+
45
+ data = self._client.request("POST", "/sub-users", json=body)
46
+ return SubUser.from_dict(data)
47
+
48
+ def get(self, id: str) -> SubUser:
49
+ data = self._client.request("GET", f"/sub-users/{id}")
50
+ return SubUser.from_dict(data)
51
+
52
+ def update(
53
+ self,
54
+ id: str,
55
+ *,
56
+ proxy_password: str | None = None,
57
+ is_traffic_limited: bool | None = None,
58
+ traffic_limit: str | None = None,
59
+ name: str | None = None,
60
+ notes: str | None = None,
61
+ ) -> SubUser:
62
+ body: dict[str, Any] = {}
63
+ if proxy_password is not None:
64
+ body["proxy_password"] = proxy_password
65
+ if is_traffic_limited is not None:
66
+ body["is_traffic_limited"] = is_traffic_limited
67
+ if traffic_limit is not None:
68
+ body["traffic_limit"] = traffic_limit
69
+ if name is not None:
70
+ body["name"] = name
71
+ if notes is not None:
72
+ body["notes"] = notes
73
+
74
+ data = self._client.request("PUT", f"/sub-users/{id}", json=body)
75
+ return SubUser.from_dict(data)
76
+
77
+ def delete(self, id: str) -> None:
78
+ self._client.request("DELETE", f"/sub-users/{id}")
79
+
80
+ def reset_usage(self, ids: list[str]) -> ResetUsageResponse:
81
+ data = self._client.request("POST", "/sub-users/reset/usage", json={"ids": ids})
82
+ return ResetUsageResponse.from_dict(data)
83
+
84
+ def bulk_delete(self, ids: list[str]) -> BulkDeleteResponse:
85
+ data = self._client.request("POST", "/sub-users/bulk-delete", json={"ids": ids})
86
+ return BulkDeleteResponse.from_dict(data)
87
+
88
+ def bulk_move_to_group(self, ids: list[str], group_id: str | None = None) -> Any:
89
+ return self._client.request("POST", "/sub-users/bulk-move-to-group", json={"ids": ids, "group_id": group_id})
90
+
91
+
92
+ class AsyncSubUsersResource:
93
+ def __init__(self, client: AsyncProxyHat) -> None:
94
+ self._client = client
95
+
96
+ async def list(self) -> list[SubUser]:
97
+ data = await self._client.request("GET", "/sub-users")
98
+ if isinstance(data, list):
99
+ return [SubUser.from_dict(item) for item in data]
100
+ return []
101
+
102
+ async def create(
103
+ self,
104
+ *,
105
+ proxy_password: str,
106
+ is_traffic_limited: bool = False,
107
+ traffic_limit: str | None = None,
108
+ name: str | None = None,
109
+ notes: str | None = None,
110
+ sub_user_group_id: str | None = None,
111
+ ) -> SubUser:
112
+ body: dict[str, Any] = {
113
+ "proxy_password": proxy_password,
114
+ "is_traffic_limited": is_traffic_limited,
115
+ }
116
+ if traffic_limit is not None:
117
+ body["traffic_limit"] = traffic_limit
118
+ if name is not None:
119
+ body["name"] = name
120
+ if notes is not None:
121
+ body["notes"] = notes
122
+ if sub_user_group_id is not None:
123
+ body["sub_user_group_id"] = sub_user_group_id
124
+
125
+ data = await self._client.request("POST", "/sub-users", json=body)
126
+ return SubUser.from_dict(data)
127
+
128
+ async def get(self, id: str) -> SubUser:
129
+ data = await self._client.request("GET", f"/sub-users/{id}")
130
+ return SubUser.from_dict(data)
131
+
132
+ async def update(
133
+ self,
134
+ id: str,
135
+ *,
136
+ proxy_password: str | None = None,
137
+ is_traffic_limited: bool | None = None,
138
+ traffic_limit: str | None = None,
139
+ name: str | None = None,
140
+ notes: str | None = None,
141
+ ) -> SubUser:
142
+ body: dict[str, Any] = {}
143
+ if proxy_password is not None:
144
+ body["proxy_password"] = proxy_password
145
+ if is_traffic_limited is not None:
146
+ body["is_traffic_limited"] = is_traffic_limited
147
+ if traffic_limit is not None:
148
+ body["traffic_limit"] = traffic_limit
149
+ if name is not None:
150
+ body["name"] = name
151
+ if notes is not None:
152
+ body["notes"] = notes
153
+
154
+ data = await self._client.request("PUT", f"/sub-users/{id}", json=body)
155
+ return SubUser.from_dict(data)
156
+
157
+ async def delete(self, id: str) -> None:
158
+ await self._client.request("DELETE", f"/sub-users/{id}")
159
+
160
+ async def reset_usage(self, ids: list[str]) -> ResetUsageResponse:
161
+ data = await self._client.request("POST", "/sub-users/reset/usage", json={"ids": ids})
162
+ return ResetUsageResponse.from_dict(data)
163
+
164
+ async def bulk_delete(self, ids: list[str]) -> BulkDeleteResponse:
165
+ data = await self._client.request("POST", "/sub-users/bulk-delete", json={"ids": ids})
166
+ return BulkDeleteResponse.from_dict(data)
167
+
168
+ async def bulk_move_to_group(self, ids: list[str], group_id: str | None = None) -> Any:
169
+ return await self._client.request(
170
+ "POST", "/sub-users/bulk-move-to-group", json={"ids": ids, "group_id": group_id}
171
+ )