feat: initial commit for ipv64 DNS TUI client
- Implement modular Textual TUI (main, app, widgets, config, api_client) - Integrate IPv64.net REST API client using httpx - Support record listing, creation, in-place edit, and deletion - Add flexible token resolution (.env, env export, interactive prompt) - Add bilingual README (DE/EN) and project configuration
This commit is contained in:
1 parent
fc1f055b11
commit
d15c927f55
11 files changed
+603
-1
No files matched your search
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""IPv64 DNS TUI Client
|
||||
Author: Pascal Bouquet <pascal@ptbos.de>
|
||||
License: GNU General Public License v3.0 (GPL-3.0)
|
||||
Year: 2026
|
||||
"""
|
||||
|
||||
import httpx
|
||||
|
||||
BASE_URL = "https://ipv64.net/api.php"
|
||||
|
||||
|
||||
class IPv64Client:
|
||||
def __init__(self, api_key: str):
|
||||
self.headers = {"Authorization": f"Bearer {api_key.strip()}"}
|
||||
|
||||
async def get_account_info(self) -> dict:
|
||||
"""[GET] get_account_info: Ruft Kontoinformationen und Limits ab."""
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(
|
||||
f"{BASE_URL}?get_account_info",
|
||||
headers=self.headers,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def get_domains(self) -> dict:
|
||||
"""[GET] get_domains: Liefert alle Domains und Records."""
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(
|
||||
f"{BASE_URL}?get_domains",
|
||||
headers=self.headers,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def add_domain(self, domain_name: str) -> dict:
|
||||
"""[POST] add_domain: Legt eine neue Domain an."""
|
||||
data = {"add_domain": domain_name}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(
|
||||
BASE_URL,
|
||||
headers=self.headers,
|
||||
data=data,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def delete_domain(self, domain_name: str) -> dict:
|
||||
"""[DELETE] del_domain: Löscht Domain mit allen Einträgen."""
|
||||
data = {"del_domain": domain_name}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.request(
|
||||
"DELETE",
|
||||
BASE_URL,
|
||||
headers=self.headers,
|
||||
data=data,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def add_record(
|
||||
self,
|
||||
domain: str,
|
||||
subdomain: str,
|
||||
typ: str,
|
||||
content: str,
|
||||
prio: str = "",
|
||||
) -> dict:
|
||||
"""[POST] add_record: DNS-Record anlegen."""
|
||||
data = {
|
||||
"add_record": domain,
|
||||
"praefix": subdomain,
|
||||
"type": typ.upper(),
|
||||
"content": content,
|
||||
}
|
||||
if prio and prio.strip() and prio.strip().lower() != "none":
|
||||
data["prio"] = prio.strip()
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(
|
||||
BASE_URL,
|
||||
headers=self.headers,
|
||||
data=data,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
async def delete_record_by_id(self, record_id: int | str) -> dict:
|
||||
"""[DELETE] del_record per ID."""
|
||||
data = {"del_record": str(record_id)}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.request(
|
||||
"DELETE",
|
||||
BASE_URL,
|
||||
headers=self.headers,
|
||||
data=data,
|
||||
timeout=10.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
Reference in new issue
Block a user