Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions linode_api4/groups/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
AccountBetaProgram,
AccountSettings,
BetaProgram,
ChildAccount,
Event,
Invoice,
Login,
Expand All @@ -18,6 +19,7 @@
ServiceTransfer,
User,
)
from linode_api4.objects.profile import PersonalAccessToken


class AccountGroup(Group):
Expand Down Expand Up @@ -496,3 +498,14 @@ def availabilities(self, *filters):
:rtype: PaginatedList of AccountAvailability
"""
return self.client._get_and_filter(AccountAvailability, *filters)

def child_accounts(self, *filters):
"""
Returns a list of all child accounts under the this parent account.

API doc: TBD

:returns: a list of all child accounts.
:rtype: PaginatedList of ChildAccount
"""
return self.client._get_and_filter(ChildAccount, *filters)
35 changes: 35 additions & 0 deletions linode_api4/objects/account.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from datetime import datetime

import requests
Expand All @@ -16,6 +18,7 @@
)
from linode_api4.objects.longview import LongviewClient, LongviewSubscription
from linode_api4.objects.nodebalancer import NodeBalancer
from linode_api4.objects.profile import PersonalAccessToken
from linode_api4.objects.support import SupportTicket


Expand Down Expand Up @@ -53,6 +56,37 @@ class Account(Base):
}


class ChildAccount(Account):
"""
A child account under a parent account.

API Documentation: TBD
"""

api_endpoint = "/account/child-accounts/{euuid}"
id_attribute = "euuid"

def create_token(self, **kwargs):
"""
Create a ephemeral token for accessing the child account.

API Documentation: TBD
"""
resp = self._client.post(
"{}/token".format(self.api_endpoint),
model=self,
data=kwargs,
)

if "errors" in resp:
raise UnexpectedResponseError(
"Unexpected response when creating a token for the child account!",
json=resp,
)

return PersonalAccessToken(self._client, resp["id"], resp)


class ServiceTransfer(Base):
"""
A transfer request for transferring a service between Linode accounts.
Expand Down Expand Up @@ -476,6 +510,7 @@ class User(Base):
properties = {
"email": Property(),
"username": Property(identifier=True, mutable=True),
"user_type": Property(),
"restricted": Property(mutable=True),
"ssh_keys": Property(),
"tfa_enabled": Property(),
Expand Down
36 changes: 36 additions & 0 deletions test/fixtures/account_child-accounts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"data": [
{
"active_since": "2018-01-01T00:01:01",
"address_1": "123 Main Street",
"address_2": "Suite A",
"balance": 200,
"balance_uninvoiced": 145,
"billing_source": "external",
"capabilities": [
"Linodes",
"NodeBalancers",
"Block Storage",
"Object Storage"
],
"city": "Philadelphia",
"company": "Linode LLC",
"country": "US",
"credit_card": {
"expiry": "11/2022",
"last_four": 1111
},
"email": "john.smith@linode.com",
"euuid": "E1AF5EEC-526F-487D-B317EBEB34C87D71",
"first_name": "John",
"last_name": "Smith",
"phone": "215-555-1212",
"state": "PA",
"tax_id": "ATU99999999",
"zip": "19102-1234"
}
],
"page": 1,
"pages": 1,
"results": 1
}
29 changes: 29 additions & 0 deletions test/fixtures/account_child-accounts_123456.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"active_since": "2018-01-01T00:01:01",
"address_1": "123 Main Street",
"address_2": "Suite A",
"balance": 200,
"balance_uninvoiced": 145,
"billing_source": "external",
"capabilities": [
"Linodes",
"NodeBalancers",
"Block Storage",
"Object Storage"
],
"city": "Philadelphia",
"company": "Linode LLC",
"country": "US",
"credit_card": {
"expiry": "11/2022",
"last_four": 1111
},
"email": "john.smith@linode.com",
"euuid": "E1AF5EEC-526F-487D-B317EBEB34C87D71",
"first_name": "John",
"last_name": "Smith",
"phone": "215-555-1212",
"state": "PA",
"tax_id": "ATU99999999",
"zip": "19102-1234"
}
8 changes: 8 additions & 0 deletions test/fixtures/account_child-accounts_123456_token.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"created": "2024-01-01T00:01:01",
"expiry": "2024-01-01T13:46:32",
"id": 123,
"label": "cool_customer_proxy",
"scopes": "*",
"token": "abcdefghijklmnop"
}
10 changes: 10 additions & 0 deletions test/integration/models/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
OAuthClient,
User,
)
from linode_api4.objects.account import ChildAccount


@pytest.mark.smoke
Expand Down Expand Up @@ -101,3 +102,12 @@ def test_get_user(test_linode_client):
assert username == user.username
assert "email" in user._raw_json
assert "email" in user._raw_json


def test_list_child_accounts(test_linode_client):
client = test_linode_client
child_accounts = client.account.child_accounts()
if len(child_accounts) > 0:
child_account = ChildAccount(client, child_accounts[0].euuid)
child_account._api_get()
child_account.create_token()
19 changes: 19 additions & 0 deletions test/unit/objects/account_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Volume,
get_obj_grants,
)
from linode_api4.objects.account import ChildAccount


class InvoiceTest(ClientBaseCase):
Expand Down Expand Up @@ -278,3 +279,21 @@ def test_account_availability_api_get(self):
self.assertEqual(availability.unavailable, [])

self.assertEqual(m.call_url, account_availability_url)


class ChildAccountTest(ClientBaseCase):
"""
Test methods of the ChildAccount
"""

def test_child_account_api_list(self):
Comment thread
zliang-akamai marked this conversation as resolved.
result = self.client.account.child_accounts()
self.assertEqual(len(result), 1)
self.assertEqual(result[0].euuid, "E1AF5EEC-526F-487D-B317EBEB34C87D71")

def test_child_account_create_token(self):
child_account = self.client.load(ChildAccount, 123456)
with self.mock_post("/account/child-accounts/123456/token") as m:
token = child_account.create_token()
self.assertEqual(token.token, "abcdefghijklmnop")
self.assertEqual(m.call_data, {})