packetdial: finish resource wrapping (reads + gated writes across the platform)
Added read wrappers: addresses (E911), smsnumbers, blocked-numbers, moh, dialrules, recording, transcriptions. Added gated write wrappers: DID update/delete, per-user device CRUD, E911 address CRUD, contact CRUD, site create/update, auto-attendant create, SMS number CRUD, block/unblock numbers, MoH TTS create/delete. Verification: contact create→delete lifecycle verified on arizonacomputerguru (id field is `unique-id`); reads for addresses/blocked-numbers/moh verified. Remaining writes are plumbed per the OpenAPI spec [P] but not lifecycle-verified (test domain lacks the feature or needs a special body) — SKILL.md marks each [V]/[P] and documents the gotchas (E911 pidflo via addresses/validate; SMS not provisioned on test domain; number-filters add 202'd but didn't persist; MoH file upload is multipart -> raw). Capability map + api.md history updated. All writes --confirm-gated; anything unwrapped still reachable via `raw`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -452,3 +452,116 @@ class NetSapiensClient:
|
||||
def delete_timeframe(self, domain: str, tf_id: str, body: Optional[dict] = None) -> Any:
|
||||
d, t = urllib.parse.quote(domain), urllib.parse.quote(tf_id)
|
||||
return self.request("DELETE", f"domains/{d}/timeframes/{t}", json_body=body)
|
||||
|
||||
# --- DID (phonenumber) update/delete (completes create-did + read) ---
|
||||
def update_phonenumber(self, domain: str, number: str, body: dict) -> Any:
|
||||
d, n = urllib.parse.quote(domain), urllib.parse.quote(number)
|
||||
return self.request("PUT", f"domains/{d}/phonenumbers/{n}", json_body=body)
|
||||
|
||||
def delete_phonenumber(self, domain: str, number: str) -> Any:
|
||||
d, n = urllib.parse.quote(domain), urllib.parse.quote(number)
|
||||
return self.request("DELETE", f"domains/{d}/phonenumbers/{n}")
|
||||
|
||||
# --- per-user SIP devices (write; read via devices()) ---
|
||||
def create_device(self, domain: str, user: str, body: dict) -> Any:
|
||||
d, u = urllib.parse.quote(domain), urllib.parse.quote(user)
|
||||
return self.request("POST", f"domains/{d}/users/{u}/devices", json_body=body)
|
||||
|
||||
def update_device(self, domain: str, user: str, device: str, body: dict) -> Any:
|
||||
d, u, v = (urllib.parse.quote(domain), urllib.parse.quote(user),
|
||||
urllib.parse.quote(device))
|
||||
return self.request("PUT", f"domains/{d}/users/{u}/devices/{v}", json_body=body)
|
||||
|
||||
def delete_device(self, domain: str, user: str, device: str) -> Any:
|
||||
d, u, v = (urllib.parse.quote(domain), urllib.parse.quote(user),
|
||||
urllib.parse.quote(device))
|
||||
return self.request("DELETE", f"domains/{d}/users/{u}/devices/{v}")
|
||||
|
||||
# --- E911 addresses (read + write) ---
|
||||
def addresses(self, domain: str) -> Any:
|
||||
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/addresses")
|
||||
|
||||
def create_address(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/addresses", json_body=body)
|
||||
|
||||
def update_address(self, domain: str, address_id: str, body: dict) -> Any:
|
||||
d, a = urllib.parse.quote(domain), urllib.parse.quote(address_id)
|
||||
return self.request("PUT", f"domains/{d}/addresses/{a}", json_body=body)
|
||||
|
||||
def delete_address(self, domain: str, address_id: str) -> Any:
|
||||
d, a = urllib.parse.quote(domain), urllib.parse.quote(address_id)
|
||||
return self.request("DELETE", f"domains/{d}/addresses/{a}")
|
||||
|
||||
# --- domain contacts (write; read via contacts()) ---
|
||||
def create_contact(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/contacts", json_body=body)
|
||||
|
||||
def update_contact(self, domain: str, contact_id: str, body: dict) -> Any:
|
||||
d, c = urllib.parse.quote(domain), urllib.parse.quote(contact_id)
|
||||
return self.request("PUT", f"domains/{d}/contacts/{c}", json_body=body)
|
||||
|
||||
def delete_contact(self, domain: str, contact_id: str) -> Any:
|
||||
d, c = urllib.parse.quote(domain), urllib.parse.quote(contact_id)
|
||||
return self.request("DELETE", f"domains/{d}/contacts/{c}")
|
||||
|
||||
# --- sites (write; read via sites()) ---
|
||||
def create_site(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/sites", json_body=body)
|
||||
|
||||
def update_site(self, domain: str, site: str, body: dict) -> Any:
|
||||
d, s = urllib.parse.quote(domain), urllib.parse.quote(site)
|
||||
return self.request("PUT", f"domains/{d}/sites/{s}", json_body=body)
|
||||
|
||||
# --- auto-attendants (create; read via autoattendants()) ---
|
||||
def create_autoattendant(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/autoattendants", json_body=body)
|
||||
|
||||
# --- SMS numbers (read + write) ---
|
||||
def smsnumbers(self, domain: str) -> Any:
|
||||
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/smsnumbers")
|
||||
|
||||
def create_smsnumber(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/smsnumbers", json_body=body)
|
||||
|
||||
def update_smsnumber(self, domain: str, smsnumber: str, body: dict) -> Any:
|
||||
d, s = urllib.parse.quote(domain), urllib.parse.quote(smsnumber)
|
||||
return self.request("PUT", f"domains/{d}/smsnumbers/{s}", json_body=body)
|
||||
|
||||
def delete_smsnumber(self, domain: str, smsnumber: str) -> Any:
|
||||
d, s = urllib.parse.quote(domain), urllib.parse.quote(smsnumber)
|
||||
return self.request("DELETE", f"domains/{d}/smsnumbers/{s}")
|
||||
|
||||
# --- blocked-number filters (read + add/remove) ---
|
||||
def blocked_numbers(self, domain: str) -> Any:
|
||||
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/number-filters")
|
||||
|
||||
def block_numbers(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/number-filters", json_body=body)
|
||||
|
||||
def unblock_numbers(self, domain: str, body: dict) -> Any:
|
||||
return self.request("DELETE", f"domains/{urllib.parse.quote(domain)}/number-filters", json_body=body)
|
||||
|
||||
# --- music on hold (read + TTS create/delete; uploads are multipart -> raw) ---
|
||||
def moh(self, domain: str) -> Any:
|
||||
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/moh")
|
||||
|
||||
def create_moh(self, domain: str, body: dict) -> Any:
|
||||
return self.request("POST", f"domains/{urllib.parse.quote(domain)}/moh", json_body=body)
|
||||
|
||||
def delete_moh(self, domain: str, index: str) -> Any:
|
||||
d, i = urllib.parse.quote(domain), urllib.parse.quote(index)
|
||||
return self.request("DELETE", f"domains/{d}/moh/{i}")
|
||||
|
||||
# --- dial rules / call data (read) ---
|
||||
def dialrules(self, domain: str, dialplan: str) -> Any:
|
||||
d, p = urllib.parse.quote(domain), urllib.parse.quote(dialplan)
|
||||
return self.request("GET", f"domains/{d}/dialplans/{p}/dialrules")
|
||||
|
||||
def recording(self, domain: str, callid: str) -> Any:
|
||||
d, c = urllib.parse.quote(domain), urllib.parse.quote(callid)
|
||||
return self.request("GET", f"domains/{d}/recordings/{c}")
|
||||
|
||||
def transcriptions(self, domain: str, **filters) -> Any:
|
||||
return self.request(
|
||||
"GET", f"domains/{urllib.parse.quote(domain)}/transcriptions", params=filters or None
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user