Skip to content

new: Add support for Parent/Child account switching #411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 3, 2024
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": "[email protected]",
"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": "[email protected]",
"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"
}
18 changes: 17 additions & 1 deletion test/integration/models/account/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@

import pytest

from linode_api4.objects import Account, AccountSettings, Event, Login, User
from linode_api4.objects import (
Account,
AccountSettings,
ChildAccount,
Event,
Login,
User,
)


@pytest.mark.smoke
Expand Down Expand Up @@ -85,3 +92,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 @@ -290,3 +291,21 @@ def test_account_availability_api_get(self):
self.assertEqual(availability.available, ["Linodes", "Kubernetes"])

self.assertEqual(m.call_url, account_availability_url)


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

def test_child_account_api_list(self):
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, {})