99from .domain import (
1010 CreateStorageBoxResponse ,
1111 CreateStorageBoxSnapshotResponse ,
12+ CreateStorageBoxSubaccountResponse ,
1213 DeleteStorageBoxResponse ,
1314 DeleteStorageBoxSnapshotResponse ,
15+ DeleteStorageBoxSubaccountResponse ,
1416 StorageBox ,
1517 StorageBoxAccessSettings ,
1618 StorageBoxFoldersResponse ,
1719 StorageBoxSnapshot ,
1820 StorageBoxSnapshotPlan ,
1921 StorageBoxSnapshotStats ,
2022 StorageBoxStats ,
23+ StorageBoxSubaccount ,
24+ StorageBoxSubaccountAccessSettings ,
2125)
2226
2327if TYPE_CHECKING :
@@ -134,6 +138,32 @@ def __init__(
134138 # TODO: implement bound methods
135139
136140
141+ class BoundStorageBoxSubaccount (BoundModelBase , StorageBoxSubaccount ):
142+ _client : StorageBoxesClient
143+
144+ model = StorageBoxSubaccount
145+
146+ def __init__ (
147+ self ,
148+ client : StorageBoxesClient ,
149+ data : dict [str , Any ],
150+ complete : bool = True ,
151+ ):
152+ raw = data .get ("storage_box" )
153+ if raw is not None :
154+ data ["storage_box" ] = BoundStorageBox (
155+ client , data = {"id" : raw }, complete = False
156+ )
157+
158+ raw = data .get ("access_settings" )
159+ if raw is not None :
160+ data ["access_settings" ] = StorageBoxAccessSettings .from_dict (raw )
161+
162+ super ().__init__ (client , data , complete )
163+
164+ # TODO: implement bound methods
165+
166+
137167class StorageBoxesPageResult (NamedTuple ):
138168 storage_boxes : list [BoundStorageBox ]
139169 meta : Meta
@@ -144,6 +174,11 @@ class StorageBoxSnapshotsPageResult(NamedTuple):
144174 meta : Meta
145175
146176
177+ class StorageBoxSubaccountsPageResult (NamedTuple ):
178+ subaccounts : list [BoundStorageBoxSubaccount ]
179+ meta : Meta
180+
181+
147182class StorageBoxesClient (ResourceClientBase ):
148183 """
149184 A client for the Storage Boxes API.
@@ -790,3 +825,212 @@ def delete_snapshot(
790825 return DeleteStorageBoxSnapshotResponse (
791826 action = BoundAction (self ._parent .actions , response ["action" ]),
792827 )
828+
829+ # Subaccounts
830+ ###########################################################################
831+
832+ def get_subaccount_by_id (
833+ self ,
834+ storage_box : StorageBox | BoundStorageBox ,
835+ id : int ,
836+ ) -> BoundStorageBoxSubaccount :
837+ """
838+ Returns a single Subaccount from a Storage Box.
839+
840+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-get-a-subaccount
841+
842+ :param storage_box: Storage Box to get the Subaccount from.
843+ :param id: ID of the Subaccount.
844+ """
845+ response = self ._client .request (
846+ method = "GET" ,
847+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts/{ id } " ,
848+ )
849+ return BoundStorageBoxSubaccount (self , response ["subaccount" ])
850+
851+ def get_subaccount_by_username (
852+ self ,
853+ storage_box : StorageBox | BoundStorageBox ,
854+ username : str ,
855+ ) -> BoundStorageBoxSubaccount :
856+ """
857+ Returns a single Subaccount from a Storage Box.
858+
859+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
860+
861+ :param storage_box: Storage Box to get the Subaccount from.
862+ :param name: User name of the Subaccount.
863+ """
864+ return self ._get_first_by (
865+ self .get_subaccount_list ,
866+ storage_box ,
867+ username = username ,
868+ )
869+
870+ def get_subaccount_list (
871+ self ,
872+ storage_box : StorageBox | BoundStorageBox ,
873+ * ,
874+ username : str | None = None ,
875+ label_selector : str | None = None ,
876+ sort : list [str ] | None = None ,
877+ ) -> StorageBoxSubaccountsPageResult :
878+ """
879+ Returns all Subaccounts for a Storage Box.
880+
881+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
882+
883+ :param storage_box: Storage Box to get the Subaccount from.
884+ :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
885+ :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
886+ :param sort: Sort resources by field and direction.
887+ """
888+ params : dict [str , Any ] = {}
889+ if username is not None :
890+ params ["username" ] = username
891+ if label_selector is not None :
892+ params ["label_selector" ] = label_selector
893+ if sort is not None :
894+ params ["sort" ] = sort
895+
896+ response = self ._client .request (
897+ method = "GET" ,
898+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts" ,
899+ params = params ,
900+ )
901+ return StorageBoxSubaccountsPageResult (
902+ subaccounts = [
903+ BoundStorageBoxSubaccount (self , item )
904+ for item in response ["subaccounts" ]
905+ ],
906+ meta = Meta .parse_meta (response ),
907+ )
908+
909+ def get_subaccount_all (
910+ self ,
911+ storage_box : StorageBox | BoundStorageBox ,
912+ * ,
913+ username : str | None = None ,
914+ label_selector : str | None = None ,
915+ sort : list [str ] | None = None ,
916+ ) -> list [BoundStorageBoxSubaccount ]:
917+ """
918+ Returns all Subaccounts for a Storage Box.
919+
920+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
921+
922+ :param storage_box: Storage Box to get the Subaccount from.
923+ :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
924+ :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
925+ :param sort: Sort resources by field and direction.
926+ """
927+ # The endpoint does not have pagination, forward to the list method.
928+ result , _ = self .get_subaccount_list (
929+ storage_box ,
930+ username = username ,
931+ label_selector = label_selector ,
932+ sort = sort ,
933+ )
934+ return result
935+
936+ def create_subaccount (
937+ self ,
938+ storage_box : StorageBox | BoundStorageBox ,
939+ * ,
940+ home_directory : str ,
941+ password : str ,
942+ access_settings : StorageBoxSubaccountAccessSettings | None = None ,
943+ description : str | None = None ,
944+ labels : dict [str , str ] | None = None ,
945+ ) -> CreateStorageBoxSubaccountResponse :
946+ """
947+ Creates a Subaccount for the Storage Box.
948+
949+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount
950+
951+ :param storage_box: Storage Box to create a Subaccount for.
952+ :param home_directory: Home directory of the Subaccount.
953+ :param password: Password of the Subaccount.
954+ :param access_settings: Access Settings of the Subaccount.
955+ :param description: Description of the Subaccount.
956+ :param labels: User-defined labels (key/value pairs) for the Resource.
957+ """
958+ data : dict [str , Any ] = {
959+ "home_directory" : home_directory ,
960+ "password" : password ,
961+ }
962+ if access_settings is not None :
963+ data ["access_settings" ] = access_settings .to_payload ()
964+ if description is not None :
965+ data ["description" ] = description
966+ if labels is not None :
967+ data ["labels" ] = labels
968+
969+ response = self ._client .request (
970+ method = "POST" ,
971+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts" ,
972+ json = data ,
973+ )
974+ return CreateStorageBoxSubaccountResponse (
975+ subaccount = BoundStorageBoxSubaccount (
976+ self ,
977+ response ["subaccount" ],
978+ # API only returns a partial object.
979+ complete = False ,
980+ ),
981+ action = BoundAction (self ._parent .actions , response ["action" ]),
982+ )
983+
984+ def update_subaccount (
985+ self ,
986+ subaccount : StorageBoxSubaccount | BoundStorageBoxSubaccount ,
987+ * ,
988+ description : str | None = None ,
989+ labels : dict [str , str ] | None = None ,
990+ ) -> BoundStorageBoxSubaccount :
991+ """
992+ Updates a Storage Box Subaccount.
993+
994+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount
995+
996+ :param subaccount: Storage Box Subaccount to update.
997+ :param description: Description of the Subaccount.
998+ :param labels: User-defined labels (key/value pairs) for the Resource.
999+ """
1000+ if subaccount .storage_box is None :
1001+ raise ValueError ("subaccount storage_box property is none" )
1002+
1003+ data : dict [str , Any ] = {}
1004+ if description is not None :
1005+ data ["description" ] = description
1006+ if labels is not None :
1007+ data ["labels" ] = labels
1008+
1009+ response = self ._client .request (
1010+ method = "PUT" ,
1011+ url = f"{ self ._base_url } /{ subaccount .storage_box .id } /subaccounts/{ subaccount .id } " ,
1012+ json = data ,
1013+ )
1014+ return BoundStorageBoxSubaccount (self , response ["subaccount" ])
1015+
1016+ def delete_subaccount (
1017+ self ,
1018+ subaccount : StorageBoxSubaccount | BoundStorageBoxSubaccount ,
1019+ ) -> DeleteStorageBoxSubaccountResponse :
1020+ """
1021+ Deletes a Storage Box Subaccount.
1022+
1023+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-delete-a-subaccount
1024+
1025+ :param subaccount: Storage Box Subaccount to delete.
1026+ """
1027+ if subaccount .storage_box is None :
1028+ raise ValueError ("subaccount storage_box property is none" )
1029+
1030+ response = self ._client .request (
1031+ method = "DELETE" ,
1032+ url = f"{ self ._base_url } /{ subaccount .storage_box .id } /subaccounts/{ subaccount .id } " ,
1033+ )
1034+ return DeleteStorageBoxSubaccountResponse (
1035+ action = BoundAction (self ._parent .actions , response ["action" ]),
1036+ )
0 commit comments