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.
@@ -785,3 +820,210 @@ def delete_snapshot(
785820 return DeleteStorageBoxSnapshotResponse (
786821 action = BoundAction (self ._parent .actions , response ["action" ]),
787822 )
823+
824+ # Subaccounts
825+ ###########################################################################
826+
827+ def get_subaccount_by_id (
828+ self ,
829+ storage_box : StorageBox | BoundStorageBox ,
830+ id : int ,
831+ ) -> BoundStorageBoxSubaccount :
832+ """
833+ Returns a single Subaccount from a Storage Box.
834+
835+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-get-a-subaccount
836+
837+ :param storage_box: Storage Box to get the Subaccount from.
838+ :param id: ID of the Subaccount.
839+ """
840+ response = self ._client .request (
841+ method = "GET" ,
842+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts/{ id } " ,
843+ )
844+ return BoundStorageBoxSubaccount (self , response ["subaccount" ])
845+
846+ def get_subaccount_by_username (
847+ self ,
848+ storage_box : StorageBox | BoundStorageBox ,
849+ username : str ,
850+ ) -> BoundStorageBoxSubaccount :
851+ """
852+ Returns a single Subaccount from a Storage Box.
853+
854+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
855+
856+ :param storage_box: Storage Box to get the Subaccount from.
857+ :param name: User name of the Subaccount.
858+ """
859+ return self ._get_first_by (
860+ self .get_subaccount_list , storage_box , username = username
861+ )
862+
863+ def get_subaccount_list (
864+ self ,
865+ storage_box : StorageBox | BoundStorageBox ,
866+ * ,
867+ username : str | None = None ,
868+ label_selector : str | None = None ,
869+ sort : list [str ] | None = None ,
870+ ) -> StorageBoxSubaccountsPageResult :
871+ """
872+ Returns all Subaccounts for a Storage Box.
873+
874+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
875+
876+ :param storage_box: Storage Box to get the Subaccount from.
877+ :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
878+ :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
879+ :param sort: Sort resources by field and direction.
880+ """
881+ params : dict [str , Any ] = {}
882+ if username is not None :
883+ params ["username" ] = username
884+ if label_selector is not None :
885+ params ["label_selector" ] = label_selector
886+ if sort is not None :
887+ params ["sort" ] = sort
888+
889+ response = self ._client .request (
890+ method = "GET" ,
891+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts" ,
892+ params = params ,
893+ )
894+ return StorageBoxSubaccountsPageResult (
895+ subaccounts = [
896+ BoundStorageBoxSubaccount (self , item )
897+ for item in response ["subaccounts" ]
898+ ],
899+ meta = Meta .parse_meta (response ),
900+ )
901+
902+ def get_subaccount_all (
903+ self ,
904+ storage_box : StorageBox | BoundStorageBox ,
905+ * ,
906+ username : str | None = None ,
907+ label_selector : str | None = None ,
908+ sort : list [str ] | None = None ,
909+ ) -> list [BoundStorageBoxSubaccount ]:
910+ """
911+ Returns all Subaccounts for a Storage Box.
912+
913+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
914+
915+ :param storage_box: Storage Box to get the Subaccount from.
916+ :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
917+ :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
918+ :param sort: Sort resources by field and direction.
919+ """
920+ # The endpoint does not have pagination, forward to the list method.
921+ result , _ = self .get_subaccount_list (
922+ storage_box ,
923+ username = username ,
924+ label_selector = label_selector ,
925+ sort = sort ,
926+ )
927+ return result
928+
929+ def create_subaccount (
930+ self ,
931+ storage_box : StorageBox | BoundStorageBox ,
932+ * ,
933+ home_directory : str ,
934+ password : str ,
935+ access_settings : StorageBoxSubaccountAccessSettings | None = None ,
936+ description : str | None = None ,
937+ labels : dict [str , str ] | None = None ,
938+ ) -> CreateStorageBoxSubaccountResponse :
939+ """
940+ Creates a Subaccount for the Storage Box.
941+
942+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount
943+
944+ :param storage_box: Storage Box to create a Subaccount for.
945+ :param home_directory: Home directory of the Subaccount.
946+ :param password: Password of the Subaccount.
947+ :param access_settings: Access Settings of the Subaccount.
948+ :param description: Description of the Subaccount.
949+ :param labels: User-defined labels (key/value pairs) for the Resource.
950+ """
951+ data : dict [str , Any ] = {
952+ "home_directory" : home_directory ,
953+ "password" : password ,
954+ }
955+ if access_settings is not None :
956+ data ["access_settings" ] = access_settings .to_payload ()
957+ if description is not None :
958+ data ["description" ] = description
959+ if labels is not None :
960+ data ["labels" ] = labels
961+
962+ response = self ._client .request (
963+ method = "POST" ,
964+ url = f"{ self ._base_url } /{ storage_box .id } /subaccounts" ,
965+ json = data ,
966+ )
967+ return CreateStorageBoxSubaccountResponse (
968+ subaccount = BoundStorageBoxSubaccount (
969+ self ,
970+ response ["subaccount" ],
971+ # API only returns a partial object.
972+ complete = False ,
973+ ),
974+ action = BoundAction (self ._parent .actions , response ["action" ]),
975+ )
976+
977+ def update_subaccount (
978+ self ,
979+ subaccount : StorageBoxSubaccount | BoundStorageBoxSubaccount ,
980+ * ,
981+ description : str | None = None ,
982+ labels : dict [str , str ] | None = None ,
983+ ) -> BoundStorageBoxSubaccount :
984+ """
985+ Updates a Storage Box Subaccount.
986+
987+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount
988+
989+ :param subaccount: Storage Box Subaccount to update.
990+ :param description: Description of the Subaccount.
991+ :param labels: User-defined labels (key/value pairs) for the Resource.
992+ """
993+ if subaccount .storage_box is None :
994+ raise ValueError ("subaccount storage_box property is none" )
995+
996+ data : dict [str , Any ] = {}
997+ if description is not None :
998+ data ["description" ] = description
999+ if labels is not None :
1000+ data ["labels" ] = labels
1001+
1002+ response = self ._client .request (
1003+ method = "PUT" ,
1004+ url = f"{ self ._base_url } /{ subaccount .storage_box .id } /subaccounts/{ subaccount .id } " ,
1005+ json = data ,
1006+ )
1007+ return BoundStorageBoxSubaccount (self , response ["subaccount" ])
1008+
1009+ def delete_subaccount (
1010+ self ,
1011+ subaccount : StorageBoxSubaccount | BoundStorageBoxSubaccount ,
1012+ ) -> DeleteStorageBoxSubaccountResponse :
1013+ """
1014+ Deletes a Storage Box Subaccount.
1015+
1016+ See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-delete-a-subaccount
1017+
1018+ :param subaccount: Storage Box Subaccount to delete.
1019+ """
1020+ if subaccount .storage_box is None :
1021+ raise ValueError ("subaccount storage_box property is none" )
1022+
1023+ response = self ._client .request (
1024+ method = "DELETE" ,
1025+ url = f"{ self ._base_url } /{ subaccount .storage_box .id } /subaccounts/{ subaccount .id } " ,
1026+ )
1027+ return DeleteStorageBoxSubaccountResponse (
1028+ action = BoundAction (self ._parent .actions , response ["action" ]),
1029+ )
0 commit comments