cacholong-cloud-cli 0.3.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.
- cacholong_cli/AsyncTyper.py +17 -0
- cacholong_cli/__init__.py +0 -0
- cacholong_cli/cli.py +110 -0
- cacholong_cli/commands/accounts.py +105 -0
- cacholong_cli/commands/addresses.py +280 -0
- cacholong_cli/commands/companies.py +100 -0
- cacholong_cli/commands/dns_records.py +275 -0
- cacholong_cli/commands/dns_templates.py +141 -0
- cacholong_cli/commands/dns_zones.py +277 -0
- cacholong_cli/commands/products.py +121 -0
- cacholong_cli/commands/purchases.py +127 -0
- cacholong_cli/common.py +179 -0
- cacholong_cli/connection.py +18 -0
- cacholong_cloud_cli-0.3.0.dist-info/METADATA +115 -0
- cacholong_cloud_cli-0.3.0.dist-info/RECORD +39 -0
- cacholong_cloud_cli-0.3.0.dist-info/WHEEL +4 -0
- cacholong_cloud_cli-0.3.0.dist-info/entry_points.txt +3 -0
- cacholong_sdk/__init__.py +18 -0
- cacholong_sdk/account.py +14 -0
- cacholong_sdk/address.py +14 -0
- cacholong_sdk/api_schema.py +124 -0
- cacholong_sdk/common.py +119 -0
- cacholong_sdk/company.py +14 -0
- cacholong_sdk/connection.py +22 -0
- cacholong_sdk/dns_record.py +14 -0
- cacholong_sdk/dns_template.py +14 -0
- cacholong_sdk/dns_zone.py +14 -0
- cacholong_sdk/exception.py +7 -0
- cacholong_sdk/product.py +14 -0
- cacholong_sdk/purchase.py +14 -0
- jsonapi_client/__init__.py +42 -0
- jsonapi_client/common.py +186 -0
- jsonapi_client/document.py +161 -0
- jsonapi_client/exceptions.py +62 -0
- jsonapi_client/filter.py +155 -0
- jsonapi_client/objects.py +187 -0
- jsonapi_client/relationships.py +447 -0
- jsonapi_client/resourceobject.py +656 -0
- jsonapi_client/session.py +755 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from asyncio import run
|
|
2
|
+
from functools import wraps
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AsyncTyper(typer.Typer):
|
|
8
|
+
def async_command(self, *args, **kwargs):
|
|
9
|
+
def decorator(async_func):
|
|
10
|
+
@wraps(async_func)
|
|
11
|
+
def sync_func(*_args, **_kwargs):
|
|
12
|
+
return run(async_func(*_args, **_kwargs))
|
|
13
|
+
|
|
14
|
+
self.command(*args, **kwargs)(sync_func)
|
|
15
|
+
return async_func
|
|
16
|
+
|
|
17
|
+
return decorator
|
|
File without changes
|
cacholong_cli/cli.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import importlib.metadata
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import typer
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from cacholong_cli.commands import (
|
|
8
|
+
accounts,
|
|
9
|
+
addresses,
|
|
10
|
+
companies,
|
|
11
|
+
dns_records,
|
|
12
|
+
dns_templates,
|
|
13
|
+
dns_zones,
|
|
14
|
+
products,
|
|
15
|
+
purchases,
|
|
16
|
+
)
|
|
17
|
+
from cacholong_cli.common import OutputFormat
|
|
18
|
+
from xdg import BaseDirectory
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Version of our CLI
|
|
22
|
+
__version__ = importlib.metadata.version("cacholong-cloud-cli")
|
|
23
|
+
|
|
24
|
+
# Check if required config.ini file exists
|
|
25
|
+
configpath = BaseDirectory.save_config_path("cacholong-cli")
|
|
26
|
+
if not os.path.exists(os.path.join(configpath, "config.ini")):
|
|
27
|
+
print("Get a token through our panel at https://cp.cacholong.eu/")
|
|
28
|
+
token = input("API Token: ")
|
|
29
|
+
if len(token) == 0:
|
|
30
|
+
print("Invalid token")
|
|
31
|
+
sys.exit(1)
|
|
32
|
+
with open(os.path.join(configpath, "config.ini"), "w") as f:
|
|
33
|
+
f.write("[DEFAULT]\n")
|
|
34
|
+
f.write("api_url = 'https://api.cacholong.eu/api/v1/'\n")
|
|
35
|
+
f.write("api_key = '" + token + "'\n")
|
|
36
|
+
|
|
37
|
+
# Generate the available commands
|
|
38
|
+
app = typer.Typer()
|
|
39
|
+
app.add_typer(accounts.app, name="accounts", help="Manage accounts")
|
|
40
|
+
app.add_typer(
|
|
41
|
+
addresses.app, name="addresses", help="Manage addresses for users and companies"
|
|
42
|
+
)
|
|
43
|
+
app.add_typer(companies.app, name="companies", help="Manage companies")
|
|
44
|
+
app.add_typer(dns_records.app, name="dns-records", help="Manage DNS records")
|
|
45
|
+
app.add_typer(dns_templates.app, name="dns-templates", help="Manage DNS templates")
|
|
46
|
+
app.add_typer(dns_zones.app, name="dns-zones", help="Manage DNS zones")
|
|
47
|
+
app.add_typer(products.app, name="products", help="Manage products")
|
|
48
|
+
app.add_typer(purchases.app, name="purchases", help="Manage purchases")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Handle version
|
|
52
|
+
def _version_callback(value: bool) -> None:
|
|
53
|
+
if value:
|
|
54
|
+
typer.echo(f"cacholong cli version: {__version__}")
|
|
55
|
+
raise typer.Exit()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _verbose_callback(ctx: typer.Context, value: bool) -> None:
|
|
59
|
+
ctx.obj["verbose"] = False
|
|
60
|
+
if value:
|
|
61
|
+
ctx.obj["verbose"] = True
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _output_callback(ctx: typer.Context, value: OutputFormat) -> None:
|
|
65
|
+
ctx.obj["output"] = value
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _create_issue_callback(ctx: typer.Context, value: bool) -> None:
|
|
69
|
+
ctx.obj["create_issue"] = value
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _sync_callback(ctx: typer.Context, value: bool) -> None:
|
|
73
|
+
ctx.obj["sync"] = value
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _sort_callback(ctx: typer.Context, value: str) -> None:
|
|
77
|
+
ctx.obj["sort"] = value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@app.callback(context_settings={"obj": {}})
|
|
81
|
+
def main(
|
|
82
|
+
ctx: typer.Context,
|
|
83
|
+
version: Optional[bool] = typer.Option(
|
|
84
|
+
None,
|
|
85
|
+
"--version",
|
|
86
|
+
help="Show the application's version and exit.",
|
|
87
|
+
callback=_version_callback,
|
|
88
|
+
is_eager=True,
|
|
89
|
+
),
|
|
90
|
+
verbose: Optional[bool] = typer.Option(
|
|
91
|
+
None, "--verbose", help="Verbose output", callback=_verbose_callback
|
|
92
|
+
),
|
|
93
|
+
sort: Optional[str] = typer.Option(
|
|
94
|
+
"-created_at", "--sort", help="Field to sort on", callback=_sort_callback
|
|
95
|
+
),
|
|
96
|
+
create_issue: bool = typer.Option(
|
|
97
|
+
False,
|
|
98
|
+
"--create-issue",
|
|
99
|
+
help="Create an issue in gitlab",
|
|
100
|
+
callback=_create_issue_callback,
|
|
101
|
+
),
|
|
102
|
+
sync: bool = typer.Option(
|
|
103
|
+
False, "--sync", help="Process action directly", callback=_sync_callback
|
|
104
|
+
),
|
|
105
|
+
output: OutputFormat = typer.Option(
|
|
106
|
+
"table", "--output", help="Output format", callback=_output_callback
|
|
107
|
+
),
|
|
108
|
+
) -> None:
|
|
109
|
+
|
|
110
|
+
return
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import Account, AccountModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def list(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
name: Annotated[
|
|
26
|
+
Optional[str],
|
|
27
|
+
typer.Option(
|
|
28
|
+
help="Must be unique. Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote, numbers 0 to 9, space or the following symbols: @ & + - ( ) ? ! * # /"
|
|
29
|
+
),
|
|
30
|
+
] = None,
|
|
31
|
+
display_name: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
32
|
+
description: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
33
|
+
created_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
34
|
+
updated_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
35
|
+
account_type: Annotated[
|
|
36
|
+
Optional[str], typer.Option(help="Only available for certain users.")
|
|
37
|
+
] = None,
|
|
38
|
+
account_account_id: Annotated[
|
|
39
|
+
Optional[str],
|
|
40
|
+
typer.Option(
|
|
41
|
+
help="Only available for certain users. When used, account_account_relation is mandatory."
|
|
42
|
+
),
|
|
43
|
+
] = None,
|
|
44
|
+
account_account_relation: Annotated[
|
|
45
|
+
Optional[str],
|
|
46
|
+
typer.Option(
|
|
47
|
+
help="Only available for certain users. When used, account_account_id is mandatory."
|
|
48
|
+
),
|
|
49
|
+
] = None,
|
|
50
|
+
company: Annotated[Optional[UUID], typer.Option(help="")] = None,
|
|
51
|
+
):
|
|
52
|
+
# Build modifier
|
|
53
|
+
modifier = []
|
|
54
|
+
if name is not None:
|
|
55
|
+
modifier.append(Filter(name=name))
|
|
56
|
+
if display_name is not None:
|
|
57
|
+
modifier.append(Filter(query_str="filter[display_name]=" + str(display_name)))
|
|
58
|
+
if description is not None:
|
|
59
|
+
modifier.append(Filter(description=description))
|
|
60
|
+
if created_at is not None:
|
|
61
|
+
modifier.append(Filter(query_str="filter[created_at]=" + str(created_at)))
|
|
62
|
+
if updated_at is not None:
|
|
63
|
+
modifier.append(Filter(query_str="filter[updated_at]=" + str(updated_at)))
|
|
64
|
+
if account_type is not None:
|
|
65
|
+
modifier.append(Filter(query_str="filter[account_type]=" + str(account_type)))
|
|
66
|
+
if account_account_id is not None:
|
|
67
|
+
modifier.append(
|
|
68
|
+
Filter(query_str="filter[account_account_id]=" + str(account_account_id))
|
|
69
|
+
)
|
|
70
|
+
if account_account_relation is not None:
|
|
71
|
+
modifier.append(
|
|
72
|
+
Filter(
|
|
73
|
+
query_str="filter[account_account_relation]="
|
|
74
|
+
+ str(account_account_relation)
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
if company is not None:
|
|
78
|
+
modifier.append(Filter(company=str(company)))
|
|
79
|
+
|
|
80
|
+
# Table definition
|
|
81
|
+
tabledef = [
|
|
82
|
+
{"header": Column("Id", no_wrap=True), "column": "id"},
|
|
83
|
+
{"header": "Name", "column": "name"},
|
|
84
|
+
{"header": "Display name", "column": "display_name"},
|
|
85
|
+
{"header": "Created", "column": "created_at"},
|
|
86
|
+
{"header": "Updated", "column": "updated_at"},
|
|
87
|
+
]
|
|
88
|
+
async with Connection() as conn:
|
|
89
|
+
await list_resources(ctx, Account(conn), tabledef, modifier)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@app.async_command()
|
|
93
|
+
async def show(
|
|
94
|
+
ctx: typer.Context,
|
|
95
|
+
account_id: Annotated[UUID, typer.Argument()],
|
|
96
|
+
):
|
|
97
|
+
# Show resource
|
|
98
|
+
try:
|
|
99
|
+
async with Connection() as conn:
|
|
100
|
+
ctrl = Account(conn)
|
|
101
|
+
model = await ctrl.fetch(account_id)
|
|
102
|
+
|
|
103
|
+
show_resource(ctx, model)
|
|
104
|
+
except DocumentError as e:
|
|
105
|
+
await print_document_error(e)
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import Address, AddressModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def list(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
street: Annotated[
|
|
26
|
+
Optional[str],
|
|
27
|
+
typer.Option(
|
|
28
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
29
|
+
),
|
|
30
|
+
] = None,
|
|
31
|
+
number: Annotated[
|
|
32
|
+
Optional[str], typer.Option(help="Can contain any number from any language.")
|
|
33
|
+
] = None,
|
|
34
|
+
suffix: Annotated[
|
|
35
|
+
Optional[str],
|
|
36
|
+
typer.Option(
|
|
37
|
+
help="Can contain any letter or number from any language or space."
|
|
38
|
+
),
|
|
39
|
+
] = None,
|
|
40
|
+
zipcode: Annotated[
|
|
41
|
+
Optional[str],
|
|
42
|
+
typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US."),
|
|
43
|
+
] = None,
|
|
44
|
+
city: Annotated[
|
|
45
|
+
Optional[str],
|
|
46
|
+
typer.Option(help="Can contain any letter from any language or space."),
|
|
47
|
+
] = None,
|
|
48
|
+
state: Annotated[
|
|
49
|
+
Optional[str],
|
|
50
|
+
typer.Option(
|
|
51
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
52
|
+
),
|
|
53
|
+
] = None,
|
|
54
|
+
country: Annotated[
|
|
55
|
+
Optional[str], typer.Option(help="Must contain two uppercase letters (A-Z).")
|
|
56
|
+
] = None,
|
|
57
|
+
user: Annotated[
|
|
58
|
+
Optional[UUID],
|
|
59
|
+
typer.Option(
|
|
60
|
+
help="Existing user. Required unless company is given. Readonly on update."
|
|
61
|
+
),
|
|
62
|
+
] = None,
|
|
63
|
+
company: Annotated[
|
|
64
|
+
Optional[UUID],
|
|
65
|
+
typer.Option(
|
|
66
|
+
help="Existing company. Required unless user is given. Readonly on update."
|
|
67
|
+
),
|
|
68
|
+
] = None,
|
|
69
|
+
):
|
|
70
|
+
# Build modifier
|
|
71
|
+
modifier = []
|
|
72
|
+
if street is not None:
|
|
73
|
+
modifier.append(Filter(street=street))
|
|
74
|
+
if number is not None:
|
|
75
|
+
modifier.append(Filter(number=number))
|
|
76
|
+
if suffix is not None:
|
|
77
|
+
modifier.append(Filter(suffix=suffix))
|
|
78
|
+
if zipcode is not None:
|
|
79
|
+
modifier.append(Filter(zipcode=zipcode))
|
|
80
|
+
if city is not None:
|
|
81
|
+
modifier.append(Filter(city=city))
|
|
82
|
+
if state is not None:
|
|
83
|
+
modifier.append(Filter(state=state))
|
|
84
|
+
if country is not None:
|
|
85
|
+
modifier.append(Filter(country=country))
|
|
86
|
+
if user is not None:
|
|
87
|
+
modifier.append(Filter(user=str(user)))
|
|
88
|
+
if company is not None:
|
|
89
|
+
modifier.append(Filter(company=str(company)))
|
|
90
|
+
modifier.append(Inclusion("company"))
|
|
91
|
+
modifier.append(Inclusion("user"))
|
|
92
|
+
|
|
93
|
+
# Table definition
|
|
94
|
+
tabledef = [
|
|
95
|
+
{"header": Column("Id", no_wrap=True), "column": "id"},
|
|
96
|
+
{"header": "Company", "column": "company", "nested_column": "name"},
|
|
97
|
+
{"header": "User", "column": "user", "nested_column": "name"},
|
|
98
|
+
{"header": "Street", "column": "street"},
|
|
99
|
+
{"header": "Number", "column": "number"},
|
|
100
|
+
{"header": "City", "column": "city"},
|
|
101
|
+
{"header": "Created", "column": "created_at"},
|
|
102
|
+
{"header": "Updated", "column": "updated_at"},
|
|
103
|
+
]
|
|
104
|
+
async with Connection() as conn:
|
|
105
|
+
await list_resources(ctx, Address(conn), tabledef, modifier)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.async_command()
|
|
109
|
+
async def show(
|
|
110
|
+
ctx: typer.Context,
|
|
111
|
+
address_id: Annotated[UUID, typer.Argument()],
|
|
112
|
+
):
|
|
113
|
+
# Show resource
|
|
114
|
+
try:
|
|
115
|
+
async with Connection() as conn:
|
|
116
|
+
ctrl = Address(conn)
|
|
117
|
+
model = await ctrl.fetch(address_id)
|
|
118
|
+
|
|
119
|
+
show_resource(ctx, model)
|
|
120
|
+
except DocumentError as e:
|
|
121
|
+
await print_document_error(e)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@app.async_command()
|
|
125
|
+
async def create(
|
|
126
|
+
ctx: typer.Context,
|
|
127
|
+
street: Annotated[
|
|
128
|
+
str,
|
|
129
|
+
typer.Option(
|
|
130
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
131
|
+
),
|
|
132
|
+
],
|
|
133
|
+
number: Annotated[
|
|
134
|
+
str, typer.Option(help="Can contain any number from any language.")
|
|
135
|
+
],
|
|
136
|
+
zipcode: Annotated[
|
|
137
|
+
str, typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US.")
|
|
138
|
+
],
|
|
139
|
+
city: Annotated[
|
|
140
|
+
str, typer.Option(help="Can contain any letter from any language or space.")
|
|
141
|
+
],
|
|
142
|
+
country: Annotated[
|
|
143
|
+
str, typer.Option(help="Must contain two uppercase letters (A-Z).")
|
|
144
|
+
],
|
|
145
|
+
suffix: Annotated[
|
|
146
|
+
Optional[str],
|
|
147
|
+
typer.Option(
|
|
148
|
+
help="Can contain any letter or number from any language or space."
|
|
149
|
+
),
|
|
150
|
+
] = None,
|
|
151
|
+
state: Annotated[
|
|
152
|
+
Optional[str],
|
|
153
|
+
typer.Option(
|
|
154
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
155
|
+
),
|
|
156
|
+
] = None,
|
|
157
|
+
user: Annotated[
|
|
158
|
+
Optional[UUID],
|
|
159
|
+
typer.Option(
|
|
160
|
+
help="Existing user. Required unless company is given. Readonly on update."
|
|
161
|
+
),
|
|
162
|
+
] = None,
|
|
163
|
+
company: Annotated[
|
|
164
|
+
Optional[UUID],
|
|
165
|
+
typer.Option(
|
|
166
|
+
help="Existing company. Required unless user is given. Readonly on update."
|
|
167
|
+
),
|
|
168
|
+
] = None,
|
|
169
|
+
):
|
|
170
|
+
try:
|
|
171
|
+
async with Connection() as conn:
|
|
172
|
+
ctrl = Address(conn)
|
|
173
|
+
model = ctrl.create()
|
|
174
|
+
model["street"] = street
|
|
175
|
+
model["number"] = number
|
|
176
|
+
if suffix is not None:
|
|
177
|
+
model["suffix"] = suffix
|
|
178
|
+
model["zipcode"] = zipcode
|
|
179
|
+
model["city"] = city
|
|
180
|
+
if state is not None:
|
|
181
|
+
model["state"] = state
|
|
182
|
+
model["country"] = country
|
|
183
|
+
if user is not None:
|
|
184
|
+
model["user"] = ResourceTuple(user, "users")
|
|
185
|
+
if company is not None:
|
|
186
|
+
model["company"] = ResourceTuple(company, "companies")
|
|
187
|
+
await ctrl.store(model, ctx.obj["create_issue"])
|
|
188
|
+
|
|
189
|
+
show_resource(ctx, model)
|
|
190
|
+
except DocumentError as e:
|
|
191
|
+
await print_document_error(e)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@app.async_command()
|
|
195
|
+
async def update(
|
|
196
|
+
ctx: typer.Context,
|
|
197
|
+
address_id: Annotated[UUID, typer.Argument()],
|
|
198
|
+
street: Annotated[
|
|
199
|
+
Optional[str],
|
|
200
|
+
typer.Option(
|
|
201
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
202
|
+
),
|
|
203
|
+
] = None,
|
|
204
|
+
number: Annotated[
|
|
205
|
+
Optional[str], typer.Option(help="Can contain any number from any language.")
|
|
206
|
+
] = None,
|
|
207
|
+
suffix: Annotated[
|
|
208
|
+
Optional[str],
|
|
209
|
+
typer.Option(
|
|
210
|
+
help="Can contain any letter or number from any language or space."
|
|
211
|
+
),
|
|
212
|
+
] = None,
|
|
213
|
+
zipcode: Annotated[
|
|
214
|
+
Optional[str],
|
|
215
|
+
typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US."),
|
|
216
|
+
] = None,
|
|
217
|
+
city: Annotated[
|
|
218
|
+
Optional[str],
|
|
219
|
+
typer.Option(help="Can contain any letter from any language or space."),
|
|
220
|
+
] = None,
|
|
221
|
+
state: Annotated[
|
|
222
|
+
Optional[str],
|
|
223
|
+
typer.Option(
|
|
224
|
+
help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
|
|
225
|
+
),
|
|
226
|
+
] = None,
|
|
227
|
+
country: Annotated[
|
|
228
|
+
Optional[str], typer.Option(help="Must contain two uppercase letters (A-Z).")
|
|
229
|
+
] = None,
|
|
230
|
+
user: Annotated[
|
|
231
|
+
Optional[UUID],
|
|
232
|
+
typer.Option(
|
|
233
|
+
help="Existing user. Required unless company is given. Readonly on update."
|
|
234
|
+
),
|
|
235
|
+
] = None,
|
|
236
|
+
company: Annotated[
|
|
237
|
+
Optional[UUID],
|
|
238
|
+
typer.Option(
|
|
239
|
+
help="Existing company. Required unless user is given. Readonly on update."
|
|
240
|
+
),
|
|
241
|
+
] = None,
|
|
242
|
+
):
|
|
243
|
+
try:
|
|
244
|
+
async with Connection() as conn:
|
|
245
|
+
ctrl = Address(conn)
|
|
246
|
+
model = await ctrl.fetch(address_id)
|
|
247
|
+
if street is not None:
|
|
248
|
+
model["street"] = street
|
|
249
|
+
if number is not None:
|
|
250
|
+
model["number"] = number
|
|
251
|
+
if suffix is not None:
|
|
252
|
+
model["suffix"] = suffix
|
|
253
|
+
if zipcode is not None:
|
|
254
|
+
model["zipcode"] = zipcode
|
|
255
|
+
if city is not None:
|
|
256
|
+
model["city"] = city
|
|
257
|
+
if state is not None:
|
|
258
|
+
model["state"] = state
|
|
259
|
+
if country is not None:
|
|
260
|
+
model["country"] = country
|
|
261
|
+
if user is not None:
|
|
262
|
+
model["user"].set(user, "users")
|
|
263
|
+
if company is not None:
|
|
264
|
+
model["company"].set(company, "companies")
|
|
265
|
+
except DocumentError as e:
|
|
266
|
+
await print_document_error(e)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@app.async_command()
|
|
270
|
+
async def delete(
|
|
271
|
+
ctx: typer.Context,
|
|
272
|
+
address_id: Annotated[List[UUID], typer.Argument()],
|
|
273
|
+
):
|
|
274
|
+
try:
|
|
275
|
+
async with Connection() as conn, asyncio.TaskGroup() as tg:
|
|
276
|
+
ctrl = Address(conn)
|
|
277
|
+
for resource_id in address_id:
|
|
278
|
+
tg.create_task(ctrl.destroy(resource_id))
|
|
279
|
+
except DocumentError as e:
|
|
280
|
+
await print_document_error(e)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import Company, CompanyModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def show(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
company_id: Annotated[UUID, typer.Argument()],
|
|
26
|
+
):
|
|
27
|
+
# Show resource
|
|
28
|
+
try:
|
|
29
|
+
async with Connection() as conn:
|
|
30
|
+
ctrl = Company(conn)
|
|
31
|
+
model = await ctrl.fetch(company_id)
|
|
32
|
+
|
|
33
|
+
show_resource(ctx, model)
|
|
34
|
+
except DocumentError as e:
|
|
35
|
+
await print_document_error(e)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@app.async_command()
|
|
39
|
+
async def update(
|
|
40
|
+
ctx: typer.Context,
|
|
41
|
+
company_id: Annotated[UUID, typer.Argument()],
|
|
42
|
+
name: Annotated[
|
|
43
|
+
Optional[str],
|
|
44
|
+
typer.Option(
|
|
45
|
+
help="Must be unique. Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, numbers 0 to 9, space, point or the folowing symbols: @ & + - ( ) ? ! * # /"
|
|
46
|
+
),
|
|
47
|
+
] = None,
|
|
48
|
+
kvknr: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
49
|
+
phone: Annotated[
|
|
50
|
+
Optional[str],
|
|
51
|
+
typer.Option(help="Can contain valid phonenumber from NL,BE,DE,GB or US."),
|
|
52
|
+
] = None,
|
|
53
|
+
email: Annotated[
|
|
54
|
+
Optional[str],
|
|
55
|
+
typer.Option(
|
|
56
|
+
help="Email will be validated and DNS records checked to make sure server accepts emails."
|
|
57
|
+
),
|
|
58
|
+
] = None,
|
|
59
|
+
email_invoice: Annotated[
|
|
60
|
+
Optional[str],
|
|
61
|
+
typer.Option(
|
|
62
|
+
help="Email for invoicing, defaults to email if not given. Email will be validated and DNS records checked to make sure server accepts emails."
|
|
63
|
+
),
|
|
64
|
+
] = None,
|
|
65
|
+
vat_number: Annotated[
|
|
66
|
+
Optional[str],
|
|
67
|
+
typer.Option(
|
|
68
|
+
help="VAT number, must be valid. If not given, it will be set to null. If given, it will be validated."
|
|
69
|
+
),
|
|
70
|
+
] = None,
|
|
71
|
+
account: Annotated[
|
|
72
|
+
Optional[UUID],
|
|
73
|
+
typer.Option(help="Existing account. Must be unique. Readonly on update."),
|
|
74
|
+
] = None,
|
|
75
|
+
addresses: Annotated[
|
|
76
|
+
Optional[List[UUID]], typer.Option(help="Existing addresses. Readonly.")
|
|
77
|
+
] = None,
|
|
78
|
+
):
|
|
79
|
+
try:
|
|
80
|
+
async with Connection() as conn:
|
|
81
|
+
ctrl = Company(conn)
|
|
82
|
+
model = await ctrl.fetch(company_id)
|
|
83
|
+
if name is not None:
|
|
84
|
+
model["name"] = name
|
|
85
|
+
if kvknr is not None:
|
|
86
|
+
model["kvknr"] = kvknr
|
|
87
|
+
if phone is not None:
|
|
88
|
+
model["phone"] = phone
|
|
89
|
+
if email is not None:
|
|
90
|
+
model["email"] = email
|
|
91
|
+
if email_invoice is not None:
|
|
92
|
+
model["email_invoice"] = email_invoice
|
|
93
|
+
if vat_number is not None:
|
|
94
|
+
model["vat_number"] = vat_number
|
|
95
|
+
if account is not None:
|
|
96
|
+
model["account"].set(account, "accounts")
|
|
97
|
+
if addresses is not None:
|
|
98
|
+
model["addresses"].set(addresses, "addresses")
|
|
99
|
+
except DocumentError as e:
|
|
100
|
+
await print_document_error(e)
|