Skip to content

Commit 0d9d07c

Browse files
author
Datata1
committed
feat(domain): add domains resource
1 parent 28d56b5 commit 0d9d07c

File tree

9 files changed

+216
-21
lines changed

9 files changed

+216
-21
lines changed

examples/domains/list_domains.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import asyncio
2+
import logging
3+
from codesphere import CodesphereSDK
4+
5+
logging.basicConfig(level=logging.INFO)
6+
7+
8+
async def main():
9+
async with CodesphereSDK() as sdk:
10+
domains = await sdk.domains.list(team_id=99999999)
11+
for domain in domains:
12+
print(domain.model_dump_json(indent=2))
13+
14+
15+
if __name__ == "__main__":
16+
asyncio.run(main())

examples/workspaces/execute_command.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22
import logging
33
from codesphere import CodesphereSDK
44

5-
# --- Logging-Konfiguration ---
65
logging.basicConfig(level=logging.INFO)
7-
# (Optionale Logger stummschalten)
8-
logging.getLogger("codesphere.http_client").setLevel(logging.WARNING)
9-
logging.getLogger("httpx").setLevel(logging.WARNING)
10-
11-
log = logging.getLogger(__name__)
126

137

148
async def main():

src/codesphere/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
)
3333
from .resources.workspace.envVars import EnvVar
3434
from .resources.metadata import Datacenter, Characteristic, WsPlan, Image
35+
from .resources.domain import (
36+
Domain,
37+
CustomDomainConfig,
38+
DomainVerificationStatus,
39+
DomainBase,
40+
DomainsResource,
41+
)
3542

3643
logging.getLogger("codesphere").addHandler(logging.NullHandler())
3744

@@ -51,4 +58,9 @@
5158
"Characteristic",
5259
"WsPlan",
5360
"Image",
61+
"Domain",
62+
"CustomDomainConfig",
63+
"DomainVerificationStatus",
64+
"DomainBase",
65+
"DomainsResource",
5466
]

src/codesphere/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .resources.metadata import MetadataResource
99
from .resources.team import TeamsResource
1010
from .resources.workspace import WorkspacesResource
11+
from .resources.domain import DomainsResource
1112

1213

1314
class CodesphereSDK:
@@ -33,6 +34,7 @@ class CodesphereSDK:
3334
teams (TeamsResource): Access to Team API operations.
3435
workspaces (WorkspacesResource): Access to Workspace API operations.
3536
metadata (MetadataResource): Access to Metadata API operations.
37+
domains (DomainResource): Access to Domain API operations.
3638
"""
3739

3840
teams: TeamsResource
@@ -44,11 +46,14 @@ class CodesphereSDK:
4446
metadata: MetadataResource
4547
"""Access to the Metadata API. (e.g., `sdk.metadata.list_plans()`)"""
4648

49+
domains: DomainsResource
50+
4751
def __init__(self):
4852
self._http_client = APIHttpClient()
4953
self.teams = TeamsResource(self._http_client)
5054
self.workspaces = WorkspacesResource(self._http_client)
5155
self.metadata = MetadataResource(self._http_client)
56+
self.domains = DomainsResource(self._http_client)
5257

5358
async def open(self):
5459
"""Manually opens the underlying HTTP client session.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from .models import Domain, CustomDomainConfig, DomainVerificationStatus, DomainBase
2+
from .resources import DomainsResource
3+
4+
__all__ = [
5+
"Domain",
6+
"CustomDomainConfig",
7+
"DomainVerificationStatus",
8+
"DomainBase",
9+
"DomainsResource",
10+
]
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
Pydantic models for the Domain resource.
3+
"""
4+
5+
from __future__ import annotations
6+
import logging
7+
from typing import Optional
8+
from pydantic import BaseModel, ConfigDict, Field
9+
from pydantic.alias_generators import to_camel
10+
11+
from ...utils import update_model_fields
12+
from ...core import _APIOperationExecutor, APIOperation, AsyncCallable
13+
14+
log = logging.getLogger(__name__)
15+
16+
camel_config = ConfigDict(
17+
alias_generator=to_camel,
18+
populate_by_name=True,
19+
)
20+
21+
22+
class DomainBase(BaseModel):
23+
model_config = camel_config
24+
25+
name: str
26+
team_id: int
27+
data_center_id: int
28+
workspaces: dict[str, list[int]]
29+
certificate_request_status: CertificateRequestStatus
30+
dns_entries: DNSEntries
31+
domain_verification_status: DomainVerificationStatus
32+
custom_config_revision: Optional[int] = None
33+
custom_config: Optional[CustomDomainConfig] = None
34+
35+
36+
class CertificateRequestStatus(BaseModel):
37+
model_config = camel_config
38+
issued: bool
39+
reason: Optional[str] = None
40+
41+
42+
class DNSEntries(BaseModel):
43+
model_config = camel_config
44+
a: str
45+
cname: str
46+
txt: str
47+
48+
49+
class DomainVerificationStatus(BaseModel):
50+
model_config = camel_config
51+
verified: bool
52+
reason: Optional[str] = None
53+
54+
55+
class CustomDomainConfig(BaseModel):
56+
max_body_size_mb: int
57+
max_connection_timeout: int
58+
use_regex: bool
59+
restricted: bool
60+
61+
62+
class Domain(DomainBase, _APIOperationExecutor):
63+
update_domain_op: AsyncCallable[None] = Field(
64+
default=APIOperation(
65+
method="PATCH",
66+
endpoint_template="/domains/team/{team_id}/domain/{name}",
67+
response_model=DomainBase,
68+
),
69+
exclude=True,
70+
)
71+
72+
update_workspace_connections_op: AsyncCallable[None] = Field(
73+
default=APIOperation(
74+
method="PUT",
75+
endpoint_template="/domains/team/{team_id}/domain/{name}/workspace-connections",
76+
response_model=DomainBase,
77+
),
78+
exclude=True,
79+
)
80+
81+
verify_domain_op: AsyncCallable[None] = Field(
82+
default=APIOperation(
83+
method="POST",
84+
endpoint_template="/domains/team/{team_id}/domain/{name}/verify",
85+
response_model=DomainVerificationStatus,
86+
),
87+
exclude=True,
88+
)
89+
90+
delete_domain_op: AsyncCallable[None] = Field(
91+
default=APIOperation(
92+
method="DELETE",
93+
endpoint_template="/domains/team/{team_id}/domain/{name}",
94+
response_model=DomainBase,
95+
),
96+
exclude=True,
97+
)
98+
99+
async def update_domain(self, data: CustomDomainConfig) -> DomainBase:
100+
await self.update_domain_op(data=data)
101+
update_model_fields(target=self.custom_config, source=data)
102+
103+
async def update_workspace_connections(
104+
self, data: dict[str, list[int]]
105+
) -> DomainBase:
106+
response = await self.update_workspace_connections_op(data=data)
107+
update_model_fields(target=self, source=response)
108+
109+
async def verify_status(self) -> DomainVerificationStatus:
110+
response = await self.verify_domain_op()
111+
update_model_fields(target=self.domain_verification_status, source=response)
112+
return response
113+
114+
async def delete(self) -> None:
115+
await self.delete_domain_op()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from typing import List, Protocol
2+
3+
from .models import Domain
4+
5+
from ...core import APIOperation, ResourceBase
6+
7+
8+
class ListDomainsCallable(Protocol):
9+
async def __call__(self, *, team_id: int) -> List[Domain]: ...
10+
11+
12+
class GetDomainCallable(Protocol):
13+
async def __call__(self, *, team_id: int, domain_name: str) -> Domain: ...
14+
15+
16+
class CreateDomainCallable(Protocol):
17+
async def __call__(self, *, team_id: int, domain_name: str) -> Domain: ...
18+
19+
20+
class DomainsResource(ResourceBase):
21+
list: ListDomainsCallable
22+
list = APIOperation(
23+
method="GET",
24+
endpoint_template="/domains/team/{team_id}",
25+
response_model=List[Domain],
26+
)
27+
28+
get: GetDomainCallable
29+
get = APIOperation(
30+
method="GET",
31+
endpoint_template="/domains/team/{team_id}/domain/{domain_name}",
32+
response_model=Domain,
33+
)
34+
35+
create: CreateDomainCallable
36+
create = APIOperation(
37+
method="POST",
38+
endpoint_template="/domains/team/{team_id}/domain/{domain_name}",
39+
response_model=Domain,
40+
)

src/codesphere/resources/workspace/models.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from pydantic import BaseModel, Field
55
from typing import Dict, Optional, List
66

7+
from ...utils import update_model_fields
78
from ...core import _APIOperationExecutor, APIOperation, AsyncCallable
89
from .envVars import EnvVar, WorkspaceEnvVarManager
910

@@ -117,10 +118,7 @@ async def update(self, data: WorkspaceUpdate) -> None:
117118
data (WorkspaceUpdate): The payload with fields to update.
118119
"""
119120
await self.update_op(data=data)
120-
update_data = data.model_dump(exclude_unset=True)
121-
log.debug(f"Updating local workspace state (id={self.id}) with: {update_data}")
122-
for key, value in update_data.items():
123-
setattr(self, key, value)
121+
update_model_fields(target=self, source=data)
124122

125123
async def delete(self) -> None:
126124
"""Deletes this workspace."""
@@ -133,17 +131,6 @@ async def get_status(self) -> WorkspaceStatus:
133131
async def execute_command(
134132
self, command: str, env: Optional[Dict[str, str]] = None
135133
) -> CommandOutput:
136-
"""
137-
Führt einen Befehl in diesem Workspace aus.
138-
139-
Args:
140-
command (str): Der Bash-Befehl (z.B. "ls -la").
141-
env (Dict[str, str], optional): Env Vars, die nur
142-
für diesen Befehl gesetzt werden.
143-
144-
Returns:
145-
CommandOutput: Ein Objekt mit stdout und stderr.
146-
"""
147134
command_data = CommandInput(command=command, env=env)
148135
return await self.execute_command_op(data=command_data)
149136

src/codesphere/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import logging
2+
from pydantic import BaseModel
3+
from typing import Any, Dict
4+
5+
log = logging.getLogger(__name__)
6+
7+
8+
def update_model_fields(target: BaseModel, source: BaseModel) -> Dict[str, Any]:
9+
update_data = source.model_dump(exclude_unset=True)
10+
11+
log.debug(f"Updating {target.__class__.__name__} with data: {update_data}")
12+
13+
for key, value in update_data.items():
14+
setattr(target, key, value)
15+
16+
return update_data

0 commit comments

Comments
 (0)