packetdial: add onboard-domain wrapper (GUI Add-a-Domain -> 3-call API flow)

onboard-domain runs POST /domains -> addresses/validate (gen E911 pidflo) -> addresses/create
from one JSON body (domain fields + optional `emergency` block), gated --confirm. Reverse-
engineered from the OITVOIP wizard screenshots; live-created the real client domain
vwp.91912.service (Valley Wide Plastering) + E911 address, and proved the wrapper with a
throwaway create->delete (no leftovers, vwp intact). Documented GUI->API mapping + the two
manual gaps (voicemail user-defaults, email-send-from-address pending the packetdial.com mailbox)
+ the domain-type "no"-on-create quirk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 09:34:48 -07:00
parent 4157fc6f1d
commit d1d1302d55
3 changed files with 89 additions and 0 deletions

View File

@@ -167,6 +167,10 @@ def main(argv=None) -> int:
sp = sub.add_parser("create-moh"); sp.add_argument("domain"); sp.add_argument("--body", required=True); sp.add_argument("--confirm", action="store_true")
sp = sub.add_parser("delete-moh"); sp.add_argument("domain"); sp.add_argument("index"); sp.add_argument("--confirm", action="store_true")
# onboard a new client domain (wizard -> 3-call flow): domain + optional E911 address
sp = sub.add_parser("onboard-domain", help="create a domain (+ optional E911 address) from one JSON body")
sp.add_argument("--body"); sp.add_argument("--body-file"); sp.add_argument("--confirm", action="store_true")
# --- raw escape hatch ---
sp = sub.add_parser("raw", help="raw request against any v2 path")
sp.add_argument("method", choices=["GET", "POST", "PUT", "PATCH", "DELETE"])
@@ -379,6 +383,20 @@ def main(argv=None) -> int:
_require_confirm(args, "DELETE MOH", f"{args.domain}/{args.index}")
_emit(client.delete_moh(args.domain, args.index))
elif args.cmd == "onboard-domain":
if args.body_file:
with open(args.body_file, encoding="utf-8") as fh:
body = json.load(fh)
else:
body = _parse_body(args.body)
if not isinstance(body, dict) or not body.get("domain"):
print("[ERROR] onboard-domain needs a JSON body with 'domain'", file=sys.stderr); sys.exit(2)
has_em = "emergency" in body
_require_confirm(args, "ONBOARD domain",
f"{body['domain']} (reseller {body.get('reseller','?')})"
+ (" + E911 address" if has_em else " (no E911 block)"))
_emit(client.onboard_domain(body))
elif args.cmd == "raw":
body = _parse_body(args.body)
if args.method != "GET":