wxcli 1.2.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.
Files changed (413) hide show
  1. wxcli/__init__.py +4 -0
  2. wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
  3. wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
  4. wxcli/_playbook/.claude/rules/cleanup.md +29 -0
  5. wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
  6. wxcli/_playbook/.claude/rules/org-health.md +14 -0
  7. wxcli/_playbook/.claude/settings.json +8 -0
  8. wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
  9. wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
  10. wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
  11. wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
  12. wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
  13. wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
  14. wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
  15. wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
  16. wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
  17. wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
  18. wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
  19. wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
  20. wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
  21. wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
  22. wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
  23. wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
  24. wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
  25. wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
  26. wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
  27. wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
  28. wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
  29. wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
  30. wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
  31. wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
  32. wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
  33. wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
  34. wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
  35. wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
  36. wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
  37. wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
  38. wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
  39. wxcli/_playbook/CLAUDE.md +373 -0
  40. wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
  41. wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
  42. wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
  43. wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
  44. wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
  45. wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
  46. wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
  47. wxcli/_playbook/docs/reference/admin-partner.md +357 -0
  48. wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
  49. wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
  50. wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
  51. wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
  52. wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
  53. wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
  54. wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
  55. wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
  56. wxcli/_playbook/docs/reference/authentication.md +965 -0
  57. wxcli/_playbook/docs/reference/call-control.md +1205 -0
  58. wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
  59. wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
  60. wxcli/_playbook/docs/reference/call-routing.md +2304 -0
  61. wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
  62. wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
  63. wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
  64. wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
  65. wxcli/_playbook/docs/reference/devices-core.md +1869 -0
  66. wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
  67. wxcli/_playbook/docs/reference/devices-platform.md +467 -0
  68. wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
  69. wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
  70. wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
  71. wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
  72. wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
  73. wxcli/_playbook/docs/reference/meetings-content.md +473 -0
  74. wxcli/_playbook/docs/reference/meetings-core.md +903 -0
  75. wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
  76. wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
  77. wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
  78. wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
  79. wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
  80. wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
  81. wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
  82. wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
  83. wxcli/_playbook/docs/reference/provisioning.md +1366 -0
  84. wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
  85. wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
  86. wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
  87. wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
  88. wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
  89. wxcli/_version.py +24 -0
  90. wxcli/auth.py +137 -0
  91. wxcli/commands/__init__.py +0 -0
  92. wxcli/commands/_registry.py +181 -0
  93. wxcli/commands/activation_email.py +103 -0
  94. wxcli/commands/admin_recordings.py +585 -0
  95. wxcli/commands/analytics.py +105 -0
  96. wxcli/commands/announcement_playlists.py +219 -0
  97. wxcli/commands/announcements.py +519 -0
  98. wxcli/commands/archive_users.py +36 -0
  99. wxcli/commands/attachment_actions.py +60 -0
  100. wxcli/commands/audit_events.py +83 -0
  101. wxcli/commands/authorizations.py +113 -0
  102. wxcli/commands/auto_attendant.py +642 -0
  103. wxcli/commands/broadworks_billing_reports.py +126 -0
  104. wxcli/commands/broadworks_enterprises.py +160 -0
  105. wxcli/commands/broadworks_subscribers.py +319 -0
  106. wxcli/commands/broadworks_workspaces.py +108 -0
  107. wxcli/commands/call_controls.py +1304 -0
  108. wxcli/commands/call_park.py +494 -0
  109. wxcli/commands/call_pickup.py +229 -0
  110. wxcli/commands/call_queue.py +1878 -0
  111. wxcli/commands/call_recording.py +707 -0
  112. wxcli/commands/call_routing.py +1610 -0
  113. wxcli/commands/call_settings_for_me_phase_5.py +212 -0
  114. wxcli/commands/caller_reputation.py +169 -0
  115. wxcli/commands/calling_service.py +305 -0
  116. wxcli/commands/cc_address_book.py +770 -0
  117. wxcli/commands/cc_agent_greetings.py +242 -0
  118. wxcli/commands/cc_agent_summaries.py +39 -0
  119. wxcli/commands/cc_agent_wellbeing.py +216 -0
  120. wxcli/commands/cc_agents.py +425 -0
  121. wxcli/commands/cc_ai_assistant.py +55 -0
  122. wxcli/commands/cc_ai_feature.py +294 -0
  123. wxcli/commands/cc_audio_files.py +149 -0
  124. wxcli/commands/cc_auto_csat.py +311 -0
  125. wxcli/commands/cc_aux_code.py +458 -0
  126. wxcli/commands/cc_business_hour.py +353 -0
  127. wxcli/commands/cc_call_monitoring.py +228 -0
  128. wxcli/commands/cc_callbacks.py +194 -0
  129. wxcli/commands/cc_campaign.py +212 -0
  130. wxcli/commands/cc_captures.py +39 -0
  131. wxcli/commands/cc_contact_list.py +169 -0
  132. wxcli/commands/cc_contact_number.py +295 -0
  133. wxcli/commands/cc_data_sources.py +235 -0
  134. wxcli/commands/cc_desktop_layout.py +380 -0
  135. wxcli/commands/cc_desktop_profile.py +322 -0
  136. wxcli/commands/cc_dial_number.py +511 -0
  137. wxcli/commands/cc_dial_plan.py +347 -0
  138. wxcli/commands/cc_dnc.py +101 -0
  139. wxcli/commands/cc_entry_point.py +545 -0
  140. wxcli/commands/cc_ewt.py +51 -0
  141. wxcli/commands/cc_flow.py +477 -0
  142. wxcli/commands/cc_global_vars.py +430 -0
  143. wxcli/commands/cc_holiday_list.py +335 -0
  144. wxcli/commands/cc_journey.py +1261 -0
  145. wxcli/commands/cc_legacy_flows.py +49 -0
  146. wxcli/commands/cc_multimedia_profile.py +436 -0
  147. wxcli/commands/cc_notification.py +51 -0
  148. wxcli/commands/cc_outdial_ani.py +604 -0
  149. wxcli/commands/cc_overrides.py +341 -0
  150. wxcli/commands/cc_queue.py +1083 -0
  151. wxcli/commands/cc_queue_stats.py +55 -0
  152. wxcli/commands/cc_realtime.py +51 -0
  153. wxcli/commands/cc_resource_collection.py +312 -0
  154. wxcli/commands/cc_search.py +46 -0
  155. wxcli/commands/cc_site.py +400 -0
  156. wxcli/commands/cc_skill.py +350 -0
  157. wxcli/commands/cc_skill_profile.py +289 -0
  158. wxcli/commands/cc_subscriptions.py +426 -0
  159. wxcli/commands/cc_summaries.py +130 -0
  160. wxcli/commands/cc_tasks.py +844 -0
  161. wxcli/commands/cc_team.py +325 -0
  162. wxcli/commands/cc_user_profiles.py +349 -0
  163. wxcli/commands/cc_users.py +701 -0
  164. wxcli/commands/cc_work_types.py +363 -0
  165. wxcli/commands/cdr.py +89 -0
  166. wxcli/commands/classifications.py +38 -0
  167. wxcli/commands/cleanup.py +1427 -0
  168. wxcli/commands/client_settings.py +72 -0
  169. wxcli/commands/conference.py +328 -0
  170. wxcli/commands/configure.py +72 -0
  171. wxcli/commands/converged_recordings.py +347 -0
  172. wxcli/commands/converged_recordings_export.py +310 -0
  173. wxcli/commands/cq_playlists.py +42 -0
  174. wxcli/commands/cucm.py +2794 -0
  175. wxcli/commands/cucm_config.py +129 -0
  176. wxcli/commands/customer_assist.py +373 -0
  177. wxcli/commands/data_sources.py +227 -0
  178. wxcli/commands/dect_devices.py +787 -0
  179. wxcli/commands/device_configurations.py +77 -0
  180. wxcli/commands/device_dynamic_settings.py +320 -0
  181. wxcli/commands/device_settings.py +1489 -0
  182. wxcli/commands/devices.py +280 -0
  183. wxcli/commands/domains.py +142 -0
  184. wxcli/commands/ecm.py +178 -0
  185. wxcli/commands/emergency_services.py +827 -0
  186. wxcli/commands/events.py +83 -0
  187. wxcli/commands/external_voicemail.py +52 -0
  188. wxcli/commands/groups.py +206 -0
  189. wxcli/commands/guest_management.py +76 -0
  190. wxcli/commands/hds.py +340 -0
  191. wxcli/commands/hot_desk.py +67 -0
  192. wxcli/commands/hot_desking_members.py +118 -0
  193. wxcli/commands/hot_desking_portal.py +124 -0
  194. wxcli/commands/hunt_group.py +577 -0
  195. wxcli/commands/hybrid_clusters.py +71 -0
  196. wxcli/commands/hybrid_connectors.py +67 -0
  197. wxcli/commands/identity_org.py +159 -0
  198. wxcli/commands/init_playbook.py +155 -0
  199. wxcli/commands/licenses.py +106 -0
  200. wxcli/commands/live_monitoring.py +40 -0
  201. wxcli/commands/location_call_handling.py +577 -0
  202. wxcli/commands/location_schedules.py +341 -0
  203. wxcli/commands/location_settings.py +1297 -0
  204. wxcli/commands/location_voicemail.py +494 -0
  205. wxcli/commands/locations.py +336 -0
  206. wxcli/commands/meeting_captions.py +110 -0
  207. wxcli/commands/meeting_chats.py +63 -0
  208. wxcli/commands/meeting_invitees.py +234 -0
  209. wxcli/commands/meeting_messages.py +28 -0
  210. wxcli/commands/meeting_participants.py +278 -0
  211. wxcli/commands/meeting_polls.py +111 -0
  212. wxcli/commands/meeting_preferences.py +515 -0
  213. wxcli/commands/meeting_qa.py +78 -0
  214. wxcli/commands/meeting_qualities.py +43 -0
  215. wxcli/commands/meeting_reports.py +101 -0
  216. wxcli/commands/meeting_session_types.py +105 -0
  217. wxcli/commands/meeting_site.py +57 -0
  218. wxcli/commands/meeting_slido.py +44 -0
  219. wxcli/commands/meeting_summaries.py +92 -0
  220. wxcli/commands/meeting_tracking_codes.py +233 -0
  221. wxcli/commands/meeting_transcripts.py +230 -0
  222. wxcli/commands/meetings.py +1997 -0
  223. wxcli/commands/memberships.py +164 -0
  224. wxcli/commands/messages.py +213 -0
  225. wxcli/commands/mode_management.py +244 -0
  226. wxcli/commands/my_call_settings.py +3577 -0
  227. wxcli/commands/numbers.py +405 -0
  228. wxcli/commands/operating_modes.py +410 -0
  229. wxcli/commands/org_contacts.py +284 -0
  230. wxcli/commands/org_health_cli.py +55 -0
  231. wxcli/commands/org_settings.py +71 -0
  232. wxcli/commands/organizations.py +83 -0
  233. wxcli/commands/paging_group.py +257 -0
  234. wxcli/commands/partner_admins.py +141 -0
  235. wxcli/commands/partner_reports.py +188 -0
  236. wxcli/commands/partner_tags.py +216 -0
  237. wxcli/commands/people.py +279 -0
  238. wxcli/commands/person_call_settings.py +71 -0
  239. wxcli/commands/pstn.py +280 -0
  240. wxcli/commands/recording_report.py +154 -0
  241. wxcli/commands/report_templates.py +38 -0
  242. wxcli/commands/reports.py +144 -0
  243. wxcli/commands/resource_group_memberships.py +160 -0
  244. wxcli/commands/resource_groups.py +67 -0
  245. wxcli/commands/roles.py +63 -0
  246. wxcli/commands/room_tabs.py +160 -0
  247. wxcli/commands/rooms.py +225 -0
  248. wxcli/commands/scim_bulk.py +46 -0
  249. wxcli/commands/scim_groups.py +246 -0
  250. wxcli/commands/scim_schemas.py +82 -0
  251. wxcli/commands/scim_users.py +283 -0
  252. wxcli/commands/security_audit.py +54 -0
  253. wxcli/commands/service_apps.py +51 -0
  254. wxcli/commands/single_number_reach.py +209 -0
  255. wxcli/commands/team_memberships.py +155 -0
  256. wxcli/commands/teams.py +153 -0
  257. wxcli/commands/ucm_profile.py +42 -0
  258. wxcli/commands/update.py +219 -0
  259. wxcli/commands/user_settings.py +5116 -0
  260. wxcli/commands/video_mesh.py +1090 -0
  261. wxcli/commands/virtual_extensions.py +502 -0
  262. wxcli/commands/virtual_line_settings.py +2072 -0
  263. wxcli/commands/webhooks.py +176 -0
  264. wxcli/commands/wholesale_billing_reports.py +147 -0
  265. wxcli/commands/wholesale_provisioning.py +523 -0
  266. wxcli/commands/workspace_locations.py +339 -0
  267. wxcli/commands/workspace_metrics.py +103 -0
  268. wxcli/commands/workspace_personalization.py +70 -0
  269. wxcli/commands/workspace_settings.py +3347 -0
  270. wxcli/commands/workspaces.py +279 -0
  271. wxcli/commands/xapi.py +114 -0
  272. wxcli/config.py +139 -0
  273. wxcli/errors.py +77 -0
  274. wxcli/main.py +210 -0
  275. wxcli/migration/CLAUDE.md +106 -0
  276. wxcli/migration/__init__.py +1 -0
  277. wxcli/migration/advisory/CLAUDE.md +196 -0
  278. wxcli/migration/advisory/__init__.py +46 -0
  279. wxcli/migration/advisory/advisor.py +107 -0
  280. wxcli/migration/advisory/advisory_patterns.py +2552 -0
  281. wxcli/migration/advisory/recommendation_rules.py +835 -0
  282. wxcli/migration/cucm/CLAUDE.md +74 -0
  283. wxcli/migration/cucm/__init__.py +5 -0
  284. wxcli/migration/cucm/connection.py +265 -0
  285. wxcli/migration/cucm/discovery.py +225 -0
  286. wxcli/migration/cucm/extractors/__init__.py +1 -0
  287. wxcli/migration/cucm/extractors/announcements.py +92 -0
  288. wxcli/migration/cucm/extractors/base.py +90 -0
  289. wxcli/migration/cucm/extractors/device_profiles.py +98 -0
  290. wxcli/migration/cucm/extractors/devices.py +193 -0
  291. wxcli/migration/cucm/extractors/e911.py +103 -0
  292. wxcli/migration/cucm/extractors/features.py +309 -0
  293. wxcli/migration/cucm/extractors/helpers.py +73 -0
  294. wxcli/migration/cucm/extractors/informational.py +295 -0
  295. wxcli/migration/cucm/extractors/locations.py +221 -0
  296. wxcli/migration/cucm/extractors/moh.py +100 -0
  297. wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
  298. wxcli/migration/cucm/extractors/routing.py +493 -0
  299. wxcli/migration/cucm/extractors/shared_lines.py +146 -0
  300. wxcli/migration/cucm/extractors/templates.py +229 -0
  301. wxcli/migration/cucm/extractors/tier4.py +173 -0
  302. wxcli/migration/cucm/extractors/users.py +240 -0
  303. wxcli/migration/cucm/extractors/voicemail.py +243 -0
  304. wxcli/migration/cucm/extractors/workspaces.py +88 -0
  305. wxcli/migration/cucm/unity_connection.py +304 -0
  306. wxcli/migration/execute/CLAUDE.md +372 -0
  307. wxcli/migration/execute/__init__.py +303 -0
  308. wxcli/migration/execute/batch.py +277 -0
  309. wxcli/migration/execute/dependency.py +483 -0
  310. wxcli/migration/execute/engine.py +964 -0
  311. wxcli/migration/execute/handlers.py +2232 -0
  312. wxcli/migration/execute/planner.py +1939 -0
  313. wxcli/migration/execute/runtime.py +571 -0
  314. wxcli/migration/export/CLAUDE.md +49 -0
  315. wxcli/migration/export/__init__.py +8 -0
  316. wxcli/migration/export/csv_export.py +126 -0
  317. wxcli/migration/export/deployment_plan.py +479 -0
  318. wxcli/migration/export/json_export.py +60 -0
  319. wxcli/migration/models.py +941 -0
  320. wxcli/migration/phone_models.py +50 -0
  321. wxcli/migration/preflight/CLAUDE.md +52 -0
  322. wxcli/migration/preflight/__init__.py +89 -0
  323. wxcli/migration/preflight/checks.py +911 -0
  324. wxcli/migration/preflight/runner.py +293 -0
  325. wxcli/migration/rate_limiter.py +144 -0
  326. wxcli/migration/report/CLAUDE.md +245 -0
  327. wxcli/migration/report/__init__.py +7 -0
  328. wxcli/migration/report/appendix.py +2437 -0
  329. wxcli/migration/report/assembler.py +183 -0
  330. wxcli/migration/report/charts.py +263 -0
  331. wxcli/migration/report/executive.py +776 -0
  332. wxcli/migration/report/explainer.py +704 -0
  333. wxcli/migration/report/helpers.py +74 -0
  334. wxcli/migration/report/ingest.py +152 -0
  335. wxcli/migration/report/notice_templates.py +192 -0
  336. wxcli/migration/report/score.py +375 -0
  337. wxcli/migration/report/styles.py +1052 -0
  338. wxcli/migration/report/user_diff.py +1052 -0
  339. wxcli/migration/report/user_notice.py +425 -0
  340. wxcli/migration/state.py +139 -0
  341. wxcli/migration/store.py +860 -0
  342. wxcli/migration/transform/CLAUDE.md +107 -0
  343. wxcli/migration/transform/__init__.py +12 -0
  344. wxcli/migration/transform/analysis_pipeline.py +453 -0
  345. wxcli/migration/transform/analyzers/__init__.py +142 -0
  346. wxcli/migration/transform/analyzers/css_permission.py +189 -0
  347. wxcli/migration/transform/analyzers/css_routing.py +335 -0
  348. wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
  349. wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
  350. wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
  351. wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
  352. wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
  353. wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
  354. wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
  355. wxcli/migration/transform/analyzers/missing_data.py +300 -0
  356. wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
  357. wxcli/migration/transform/analyzers/shared_line.py +170 -0
  358. wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
  359. wxcli/migration/transform/analyzers/workspace_license.py +212 -0
  360. wxcli/migration/transform/cross_reference.py +1136 -0
  361. wxcli/migration/transform/cucm_pattern.py +246 -0
  362. wxcli/migration/transform/decisions.py +301 -0
  363. wxcli/migration/transform/e164.py +145 -0
  364. wxcli/migration/transform/engine.py +256 -0
  365. wxcli/migration/transform/mappers/CLAUDE.md +123 -0
  366. wxcli/migration/transform/mappers/__init__.py +76 -0
  367. wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
  368. wxcli/migration/transform/mappers/base.py +190 -0
  369. wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
  370. wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
  371. wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
  372. wxcli/migration/transform/mappers/css_mapper.py +868 -0
  373. wxcli/migration/transform/mappers/dect_mapper.py +367 -0
  374. wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
  375. wxcli/migration/transform/mappers/device_mapper.py +227 -0
  376. wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
  377. wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
  378. wxcli/migration/transform/mappers/e911_mapper.py +129 -0
  379. wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
  380. wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
  381. wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
  382. wxcli/migration/transform/mappers/line_mapper.py +310 -0
  383. wxcli/migration/transform/mappers/location_mapper.py +235 -0
  384. wxcli/migration/transform/mappers/moh_mapper.py +114 -0
  385. wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
  386. wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
  387. wxcli/migration/transform/mappers/routing_mapper.py +821 -0
  388. wxcli/migration/transform/mappers/snr_mapper.py +201 -0
  389. wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
  390. wxcli/migration/transform/mappers/user_mapper.py +264 -0
  391. wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
  392. wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
  393. wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
  394. wxcli/migration/transform/normalizers.py +2008 -0
  395. wxcli/migration/transform/pattern_converter.py +106 -0
  396. wxcli/migration/transform/pipeline.py +271 -0
  397. wxcli/migration/transform/rules.py +255 -0
  398. wxcli/org_health/CLAUDE.md +63 -0
  399. wxcli/org_health/__init__.py +7 -0
  400. wxcli/org_health/analyze.py +93 -0
  401. wxcli/org_health/checks.py +458 -0
  402. wxcli/org_health/collector.py +62 -0
  403. wxcli/org_health/models.py +78 -0
  404. wxcli/org_health/report.py +300 -0
  405. wxcli/output.py +101 -0
  406. wxcli-1.2.0.dist-info/METADATA +505 -0
  407. wxcli-1.2.0.dist-info/RECORD +413 -0
  408. wxcli-1.2.0.dist-info/WHEEL +5 -0
  409. wxcli-1.2.0.dist-info/entry_points.txt +2 -0
  410. wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
  411. wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
  412. wxcli-1.2.0.dist-info/scm_version.json +8 -0
  413. wxcli-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1304 @@
1
+ import json
2
+ import typer
3
+ from wxcli.auth import get_api
4
+ from wxcli.errors import WebexError, handle_rest_error
5
+ from wxcli.output import print_table, print_json
6
+ from wxcli.config import get_org_id
7
+
8
+
9
+ app = typer.Typer(help="Manage Webex Calling call-controls.")
10
+
11
+
12
+ @app.command("create")
13
+ def create(
14
+ destination: str = typer.Option(None, "--destination", help="(required) The destination to be dialed. The destination can be digits"),
15
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the call. The"),
16
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the call. Mu"),
17
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
18
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
19
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
20
+ debug: bool = typer.Option(False, "--debug"),
21
+ ):
22
+ """Dial."""
23
+ api = get_api(debug=debug)
24
+ url = f"https://webexapis.com/v1/telephony/calls/dial"
25
+ if json_body:
26
+ body = json.loads(json_body)
27
+ else:
28
+ body = {}
29
+ if destination is not None:
30
+ body["destination"] = destination
31
+ if endpoint_id is not None:
32
+ body["endpointId"] = endpoint_id
33
+ if single_number_reach_phone_number is not None:
34
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
35
+ if line_owner_id is not None:
36
+ body["lineOwnerId"] = line_owner_id
37
+ _missing = [f for f in ['destination'] if f not in body or body[f] is None]
38
+ if _missing:
39
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
40
+ raise typer.Exit(1)
41
+ try:
42
+ result = api.session.rest_post(url, json=body)
43
+ except WebexError as e:
44
+ handle_rest_error(e)
45
+ if output == "json":
46
+ print_json(result)
47
+ elif isinstance(result, dict) and "callId" in result:
48
+ typer.echo(f"Created: {result['callId']}")
49
+ elif isinstance(result, dict) and "id" in result:
50
+ typer.echo(f"Created: {result['id']}")
51
+ elif not result or result == {}:
52
+ typer.echo("Created.")
53
+ else:
54
+ print_json(result)
55
+
56
+
57
+
58
+ @app.command("create-answer-calls")
59
+ def create_answer_calls(
60
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to be answered."),
61
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to answer the call on. T"),
62
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
63
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
64
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
65
+ debug: bool = typer.Option(False, "--debug"),
66
+ ):
67
+ """Answer."""
68
+ api = get_api(debug=debug)
69
+ url = f"https://webexapis.com/v1/telephony/calls/answer"
70
+ if json_body:
71
+ body = json.loads(json_body)
72
+ else:
73
+ body = {}
74
+ if call_id is not None:
75
+ body["callId"] = call_id
76
+ if endpoint_id is not None:
77
+ body["endpointId"] = endpoint_id
78
+ if line_owner_id is not None:
79
+ body["lineOwnerId"] = line_owner_id
80
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
81
+ if _missing:
82
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
83
+ raise typer.Exit(1)
84
+ try:
85
+ result = api.session.rest_post(url, json=body)
86
+ except WebexError as e:
87
+ handle_rest_error(e)
88
+ if output == "json":
89
+ print_json(result)
90
+ elif isinstance(result, dict) and "id" in result:
91
+ typer.echo(f"Created: {result['id']}")
92
+ elif not result or result == {}:
93
+ typer.echo("Created.")
94
+ else:
95
+ print_json(result)
96
+
97
+
98
+
99
+ @app.command("create-reject")
100
+ def create_reject(
101
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to be rejected."),
102
+ action: str = typer.Option(None, "--action", help="The rejection action to apply to the call. The busy action i"),
103
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
104
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
105
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
106
+ debug: bool = typer.Option(False, "--debug"),
107
+ ):
108
+ """Reject."""
109
+ api = get_api(debug=debug)
110
+ url = f"https://webexapis.com/v1/telephony/calls/reject"
111
+ if json_body:
112
+ body = json.loads(json_body)
113
+ else:
114
+ body = {}
115
+ if call_id is not None:
116
+ body["callId"] = call_id
117
+ if action is not None:
118
+ body["action"] = action
119
+ if line_owner_id is not None:
120
+ body["lineOwnerId"] = line_owner_id
121
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
122
+ if _missing:
123
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
124
+ raise typer.Exit(1)
125
+ try:
126
+ result = api.session.rest_post(url, json=body)
127
+ except WebexError as e:
128
+ handle_rest_error(e)
129
+ if output == "json":
130
+ print_json(result)
131
+ elif isinstance(result, dict) and "id" in result:
132
+ typer.echo(f"Created: {result['id']}")
133
+ elif not result or result == {}:
134
+ typer.echo("Created.")
135
+ else:
136
+ print_json(result)
137
+
138
+
139
+
140
+ @app.command("create-hangup-calls")
141
+ def create_hangup_calls(
142
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to hangup."),
143
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
144
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
145
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
146
+ debug: bool = typer.Option(False, "--debug"),
147
+ ):
148
+ """Hangup."""
149
+ api = get_api(debug=debug)
150
+ url = f"https://webexapis.com/v1/telephony/calls/hangup"
151
+ if json_body:
152
+ body = json.loads(json_body)
153
+ else:
154
+ body = {}
155
+ if call_id is not None:
156
+ body["callId"] = call_id
157
+ if line_owner_id is not None:
158
+ body["lineOwnerId"] = line_owner_id
159
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
160
+ if _missing:
161
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
162
+ raise typer.Exit(1)
163
+ try:
164
+ result = api.session.rest_post(url, json=body)
165
+ except WebexError as e:
166
+ handle_rest_error(e)
167
+ if output == "json":
168
+ print_json(result)
169
+ elif isinstance(result, dict) and "id" in result:
170
+ typer.echo(f"Created: {result['id']}")
171
+ elif not result or result == {}:
172
+ typer.echo("Created.")
173
+ else:
174
+ print_json(result)
175
+
176
+
177
+
178
+ @app.command("create-hold")
179
+ def create_hold(
180
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to hold."),
181
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
182
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
183
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
184
+ debug: bool = typer.Option(False, "--debug"),
185
+ ):
186
+ """Hold."""
187
+ api = get_api(debug=debug)
188
+ url = f"https://webexapis.com/v1/telephony/calls/hold"
189
+ if json_body:
190
+ body = json.loads(json_body)
191
+ else:
192
+ body = {}
193
+ if call_id is not None:
194
+ body["callId"] = call_id
195
+ if line_owner_id is not None:
196
+ body["lineOwnerId"] = line_owner_id
197
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
198
+ if _missing:
199
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
200
+ raise typer.Exit(1)
201
+ try:
202
+ result = api.session.rest_post(url, json=body)
203
+ except WebexError as e:
204
+ handle_rest_error(e)
205
+ if output == "json":
206
+ print_json(result)
207
+ elif isinstance(result, dict) and "id" in result:
208
+ typer.echo(f"Created: {result['id']}")
209
+ elif not result or result == {}:
210
+ typer.echo("Created.")
211
+ else:
212
+ print_json(result)
213
+
214
+
215
+
216
+ @app.command("create-resume")
217
+ def create_resume(
218
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to resume."),
219
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
220
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
221
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
222
+ debug: bool = typer.Option(False, "--debug"),
223
+ ):
224
+ """Resume."""
225
+ api = get_api(debug=debug)
226
+ url = f"https://webexapis.com/v1/telephony/calls/resume"
227
+ if json_body:
228
+ body = json.loads(json_body)
229
+ else:
230
+ body = {}
231
+ if call_id is not None:
232
+ body["callId"] = call_id
233
+ if line_owner_id is not None:
234
+ body["lineOwnerId"] = line_owner_id
235
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
236
+ if _missing:
237
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
238
+ raise typer.Exit(1)
239
+ try:
240
+ result = api.session.rest_post(url, json=body)
241
+ except WebexError as e:
242
+ handle_rest_error(e)
243
+ if output == "json":
244
+ print_json(result)
245
+ elif isinstance(result, dict) and "id" in result:
246
+ typer.echo(f"Created: {result['id']}")
247
+ elif not result or result == {}:
248
+ typer.echo("Created.")
249
+ else:
250
+ print_json(result)
251
+
252
+
253
+
254
+ @app.command("create-mute")
255
+ def create_mute(
256
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to mute."),
257
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
258
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
259
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
260
+ debug: bool = typer.Option(False, "--debug"),
261
+ ):
262
+ """Mute."""
263
+ api = get_api(debug=debug)
264
+ url = f"https://webexapis.com/v1/telephony/calls/mute"
265
+ if json_body:
266
+ body = json.loads(json_body)
267
+ else:
268
+ body = {}
269
+ if call_id is not None:
270
+ body["callId"] = call_id
271
+ if line_owner_id is not None:
272
+ body["lineOwnerId"] = line_owner_id
273
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
274
+ if _missing:
275
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
276
+ raise typer.Exit(1)
277
+ try:
278
+ result = api.session.rest_post(url, json=body)
279
+ except WebexError as e:
280
+ handle_rest_error(e)
281
+ if output == "json":
282
+ print_json(result)
283
+ elif isinstance(result, dict) and "id" in result:
284
+ typer.echo(f"Created: {result['id']}")
285
+ elif not result or result == {}:
286
+ typer.echo("Created.")
287
+ else:
288
+ print_json(result)
289
+
290
+
291
+
292
+ @app.command("create-unmute")
293
+ def create_unmute(
294
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to unmute."),
295
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
296
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
297
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
298
+ debug: bool = typer.Option(False, "--debug"),
299
+ ):
300
+ """Unmute."""
301
+ api = get_api(debug=debug)
302
+ url = f"https://webexapis.com/v1/telephony/calls/unmute"
303
+ if json_body:
304
+ body = json.loads(json_body)
305
+ else:
306
+ body = {}
307
+ if call_id is not None:
308
+ body["callId"] = call_id
309
+ if line_owner_id is not None:
310
+ body["lineOwnerId"] = line_owner_id
311
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
312
+ if _missing:
313
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
314
+ raise typer.Exit(1)
315
+ try:
316
+ result = api.session.rest_post(url, json=body)
317
+ except WebexError as e:
318
+ handle_rest_error(e)
319
+ if output == "json":
320
+ print_json(result)
321
+ elif isinstance(result, dict) and "id" in result:
322
+ typer.echo(f"Created: {result['id']}")
323
+ elif not result or result == {}:
324
+ typer.echo("Created.")
325
+ else:
326
+ print_json(result)
327
+
328
+
329
+
330
+ @app.command("create-divert")
331
+ def create_divert(
332
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to divert."),
333
+ destination: str = typer.Option(None, "--destination", help="The destination to divert the call to. If toVoicemail is fal"),
334
+ to_voicemail: bool = typer.Option(None, "--to-voicemail/--no-to-voicemail", help="If set to true, the call is diverted to voicemail. If no des"),
335
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
336
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
337
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
338
+ debug: bool = typer.Option(False, "--debug"),
339
+ ):
340
+ """Divert."""
341
+ api = get_api(debug=debug)
342
+ url = f"https://webexapis.com/v1/telephony/calls/divert"
343
+ if json_body:
344
+ body = json.loads(json_body)
345
+ else:
346
+ body = {}
347
+ if call_id is not None:
348
+ body["callId"] = call_id
349
+ if destination is not None:
350
+ body["destination"] = destination
351
+ if to_voicemail is not None:
352
+ body["toVoicemail"] = to_voicemail
353
+ if line_owner_id is not None:
354
+ body["lineOwnerId"] = line_owner_id
355
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
356
+ if _missing:
357
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
358
+ raise typer.Exit(1)
359
+ try:
360
+ result = api.session.rest_post(url, json=body)
361
+ except WebexError as e:
362
+ handle_rest_error(e)
363
+ if output == "json":
364
+ print_json(result)
365
+ elif isinstance(result, dict) and "id" in result:
366
+ typer.echo(f"Created: {result['id']}")
367
+ elif not result or result == {}:
368
+ typer.echo("Created.")
369
+ else:
370
+ print_json(result)
371
+
372
+
373
+
374
+ @app.command("create-transfer")
375
+ def create_transfer(
376
+ call_id1: str = typer.Option(None, "--call-id1", help="The call identifier of the first call to transfer. This para"),
377
+ call_id2: str = typer.Option(None, "--call-id2", help="The call identifier of the second call to transfer. This par"),
378
+ destination: str = typer.Option(None, "--destination", help="The destination to be transferred to. The destination can be"),
379
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
380
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
381
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
382
+ debug: bool = typer.Option(False, "--debug"),
383
+ ):
384
+ """Transfer."""
385
+ api = get_api(debug=debug)
386
+ url = f"https://webexapis.com/v1/telephony/calls/transfer"
387
+ if json_body:
388
+ body = json.loads(json_body)
389
+ else:
390
+ body = {}
391
+ if call_id1 is not None:
392
+ body["callId1"] = call_id1
393
+ if call_id2 is not None:
394
+ body["callId2"] = call_id2
395
+ if destination is not None:
396
+ body["destination"] = destination
397
+ if line_owner_id is not None:
398
+ body["lineOwnerId"] = line_owner_id
399
+ try:
400
+ result = api.session.rest_post(url, json=body)
401
+ except WebexError as e:
402
+ handle_rest_error(e)
403
+ if output == "json":
404
+ print_json(result)
405
+ elif isinstance(result, dict) and "callId" in result:
406
+ typer.echo(f"Created: {result['callId']}")
407
+ elif isinstance(result, dict) and "id" in result:
408
+ typer.echo(f"Created: {result['id']}")
409
+ elif not result or result == {}:
410
+ typer.echo("Created.")
411
+ else:
412
+ print_json(result)
413
+
414
+
415
+
416
+ @app.command("create-park")
417
+ def create_park(
418
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to park."),
419
+ destination: str = typer.Option(None, "--destination", help="Identifes where the call is to be parked. If not provided, t"),
420
+ is_group_park: bool = typer.Option(None, "--is-group-park/--no-is-group-park", help="If set to`true`, the call is parked against an automatically"),
421
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
422
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
423
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
424
+ debug: bool = typer.Option(False, "--debug"),
425
+ ):
426
+ """Park."""
427
+ api = get_api(debug=debug)
428
+ url = f"https://webexapis.com/v1/telephony/calls/park"
429
+ if json_body:
430
+ body = json.loads(json_body)
431
+ else:
432
+ body = {}
433
+ if call_id is not None:
434
+ body["callId"] = call_id
435
+ if destination is not None:
436
+ body["destination"] = destination
437
+ if is_group_park is not None:
438
+ body["isGroupPark"] = is_group_park
439
+ if line_owner_id is not None:
440
+ body["lineOwnerId"] = line_owner_id
441
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
442
+ if _missing:
443
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
444
+ raise typer.Exit(1)
445
+ try:
446
+ result = api.session.rest_post(url, json=body)
447
+ except WebexError as e:
448
+ handle_rest_error(e)
449
+ if output == "json":
450
+ print_json(result)
451
+ elif isinstance(result, dict) and "id" in result:
452
+ typer.echo(f"Created: {result['id']}")
453
+ elif not result or result == {}:
454
+ typer.echo("Created.")
455
+ else:
456
+ print_json(result)
457
+
458
+
459
+
460
+ @app.command("create-retrieve")
461
+ def create_retrieve(
462
+ destination: str = typer.Option(None, "--destination", help="Identifies where the call is parked. The number field from t"),
463
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the retrieval"),
464
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the retrieva"),
465
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
466
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
467
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
468
+ debug: bool = typer.Option(False, "--debug"),
469
+ ):
470
+ """Retrieve."""
471
+ api = get_api(debug=debug)
472
+ url = f"https://webexapis.com/v1/telephony/calls/retrieve"
473
+ if json_body:
474
+ body = json.loads(json_body)
475
+ else:
476
+ body = {}
477
+ if destination is not None:
478
+ body["destination"] = destination
479
+ if endpoint_id is not None:
480
+ body["endpointId"] = endpoint_id
481
+ if single_number_reach_phone_number is not None:
482
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
483
+ if line_owner_id is not None:
484
+ body["lineOwnerId"] = line_owner_id
485
+ try:
486
+ result = api.session.rest_post(url, json=body)
487
+ except WebexError as e:
488
+ handle_rest_error(e)
489
+ if output == "json":
490
+ print_json(result)
491
+ elif isinstance(result, dict) and "callId" in result:
492
+ typer.echo(f"Created: {result['callId']}")
493
+ elif isinstance(result, dict) and "id" in result:
494
+ typer.echo(f"Created: {result['id']}")
495
+ elif not result or result == {}:
496
+ typer.echo("Created.")
497
+ else:
498
+ print_json(result)
499
+
500
+
501
+
502
+ @app.command("create-start-recording")
503
+ def create_start_recording(
504
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to start recording."),
505
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
506
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
507
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
508
+ debug: bool = typer.Option(False, "--debug"),
509
+ ):
510
+ """Start Recording."""
511
+ api = get_api(debug=debug)
512
+ url = f"https://webexapis.com/v1/telephony/calls/startRecording"
513
+ if json_body:
514
+ body = json.loads(json_body)
515
+ else:
516
+ body = {}
517
+ if call_id is not None:
518
+ body["callId"] = call_id
519
+ if line_owner_id is not None:
520
+ body["lineOwnerId"] = line_owner_id
521
+ try:
522
+ result = api.session.rest_post(url, json=body)
523
+ except WebexError as e:
524
+ handle_rest_error(e)
525
+ if output == "json":
526
+ print_json(result)
527
+ elif isinstance(result, dict) and "id" in result:
528
+ typer.echo(f"Created: {result['id']}")
529
+ elif not result or result == {}:
530
+ typer.echo("Created.")
531
+ else:
532
+ print_json(result)
533
+
534
+
535
+
536
+ @app.command("create-stop-recording")
537
+ def create_stop_recording(
538
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to stop recording."),
539
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
540
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
541
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
542
+ debug: bool = typer.Option(False, "--debug"),
543
+ ):
544
+ """Stop Recording."""
545
+ api = get_api(debug=debug)
546
+ url = f"https://webexapis.com/v1/telephony/calls/stopRecording"
547
+ if json_body:
548
+ body = json.loads(json_body)
549
+ else:
550
+ body = {}
551
+ if call_id is not None:
552
+ body["callId"] = call_id
553
+ if line_owner_id is not None:
554
+ body["lineOwnerId"] = line_owner_id
555
+ try:
556
+ result = api.session.rest_post(url, json=body)
557
+ except WebexError as e:
558
+ handle_rest_error(e)
559
+ if output == "json":
560
+ print_json(result)
561
+ elif isinstance(result, dict) and "id" in result:
562
+ typer.echo(f"Created: {result['id']}")
563
+ elif not result or result == {}:
564
+ typer.echo("Created.")
565
+ else:
566
+ print_json(result)
567
+
568
+
569
+
570
+ @app.command("create-pause-recording")
571
+ def create_pause_recording(
572
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to pause recording."),
573
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
574
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
575
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
576
+ debug: bool = typer.Option(False, "--debug"),
577
+ ):
578
+ """Pause Recording."""
579
+ api = get_api(debug=debug)
580
+ url = f"https://webexapis.com/v1/telephony/calls/pauseRecording"
581
+ if json_body:
582
+ body = json.loads(json_body)
583
+ else:
584
+ body = {}
585
+ if call_id is not None:
586
+ body["callId"] = call_id
587
+ if line_owner_id is not None:
588
+ body["lineOwnerId"] = line_owner_id
589
+ try:
590
+ result = api.session.rest_post(url, json=body)
591
+ except WebexError as e:
592
+ handle_rest_error(e)
593
+ if output == "json":
594
+ print_json(result)
595
+ elif isinstance(result, dict) and "id" in result:
596
+ typer.echo(f"Created: {result['id']}")
597
+ elif not result or result == {}:
598
+ typer.echo("Created.")
599
+ else:
600
+ print_json(result)
601
+
602
+
603
+
604
+ @app.command("create-resume-recording")
605
+ def create_resume_recording(
606
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to resume recording."),
607
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
608
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
609
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
610
+ debug: bool = typer.Option(False, "--debug"),
611
+ ):
612
+ """Resume Recording."""
613
+ api = get_api(debug=debug)
614
+ url = f"https://webexapis.com/v1/telephony/calls/resumeRecording"
615
+ if json_body:
616
+ body = json.loads(json_body)
617
+ else:
618
+ body = {}
619
+ if call_id is not None:
620
+ body["callId"] = call_id
621
+ if line_owner_id is not None:
622
+ body["lineOwnerId"] = line_owner_id
623
+ try:
624
+ result = api.session.rest_post(url, json=body)
625
+ except WebexError as e:
626
+ handle_rest_error(e)
627
+ if output == "json":
628
+ print_json(result)
629
+ elif isinstance(result, dict) and "id" in result:
630
+ typer.echo(f"Created: {result['id']}")
631
+ elif not result or result == {}:
632
+ typer.echo("Created.")
633
+ else:
634
+ print_json(result)
635
+
636
+
637
+
638
+ @app.command("create-transmit-dtmf")
639
+ def create_transmit_dtmf(
640
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to transmit DTMF digits for."),
641
+ dtmf: str = typer.Option(None, "--dtmf", help="The DTMF digits to transmit. Each digit must be part of the"),
642
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
643
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
644
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
645
+ debug: bool = typer.Option(False, "--debug"),
646
+ ):
647
+ """Transmit DTMF."""
648
+ api = get_api(debug=debug)
649
+ url = f"https://webexapis.com/v1/telephony/calls/transmitDtmf"
650
+ if json_body:
651
+ body = json.loads(json_body)
652
+ else:
653
+ body = {}
654
+ if call_id is not None:
655
+ body["callId"] = call_id
656
+ if dtmf is not None:
657
+ body["dtmf"] = dtmf
658
+ if line_owner_id is not None:
659
+ body["lineOwnerId"] = line_owner_id
660
+ try:
661
+ result = api.session.rest_post(url, json=body)
662
+ except WebexError as e:
663
+ handle_rest_error(e)
664
+ if output == "json":
665
+ print_json(result)
666
+ elif isinstance(result, dict) and "id" in result:
667
+ typer.echo(f"Created: {result['id']}")
668
+ elif not result or result == {}:
669
+ typer.echo("Created.")
670
+ else:
671
+ print_json(result)
672
+
673
+
674
+
675
+ @app.command("create-push")
676
+ def create_push(
677
+ call_id: str = typer.Option(None, "--call-id", help="The call identifier of the call to push."),
678
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
679
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
680
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
681
+ debug: bool = typer.Option(False, "--debug"),
682
+ ):
683
+ """Push."""
684
+ api = get_api(debug=debug)
685
+ url = f"https://webexapis.com/v1/telephony/calls/push"
686
+ if json_body:
687
+ body = json.loads(json_body)
688
+ else:
689
+ body = {}
690
+ if call_id is not None:
691
+ body["callId"] = call_id
692
+ if line_owner_id is not None:
693
+ body["lineOwnerId"] = line_owner_id
694
+ try:
695
+ result = api.session.rest_post(url, json=body)
696
+ except WebexError as e:
697
+ handle_rest_error(e)
698
+ if output == "json":
699
+ print_json(result)
700
+ elif isinstance(result, dict) and "id" in result:
701
+ typer.echo(f"Created: {result['id']}")
702
+ elif not result or result == {}:
703
+ typer.echo("Created.")
704
+ else:
705
+ print_json(result)
706
+
707
+
708
+
709
+ @app.command("create-pickup")
710
+ def create_pickup(
711
+ target: str = typer.Option(None, "--target", help="Identifies the user to pickup an incoming call from. If not"),
712
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the pickup. T"),
713
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the pickup."),
714
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
715
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
716
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
717
+ debug: bool = typer.Option(False, "--debug"),
718
+ ):
719
+ """Pickup."""
720
+ api = get_api(debug=debug)
721
+ url = f"https://webexapis.com/v1/telephony/calls/pickup"
722
+ if json_body:
723
+ body = json.loads(json_body)
724
+ else:
725
+ body = {}
726
+ if target is not None:
727
+ body["target"] = target
728
+ if endpoint_id is not None:
729
+ body["endpointId"] = endpoint_id
730
+ if single_number_reach_phone_number is not None:
731
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
732
+ if line_owner_id is not None:
733
+ body["lineOwnerId"] = line_owner_id
734
+ try:
735
+ result = api.session.rest_post(url, json=body)
736
+ except WebexError as e:
737
+ handle_rest_error(e)
738
+ if output == "json":
739
+ print_json(result)
740
+ elif isinstance(result, dict) and "callId" in result:
741
+ typer.echo(f"Created: {result['callId']}")
742
+ elif isinstance(result, dict) and "id" in result:
743
+ typer.echo(f"Created: {result['id']}")
744
+ elif not result or result == {}:
745
+ typer.echo("Created.")
746
+ else:
747
+ print_json(result)
748
+
749
+
750
+
751
+ @app.command("create-barge-in")
752
+ def create_barge_in(
753
+ target: str = typer.Option(None, "--target", help="(required) Identifies the user to barge-in on. The target can be digits"),
754
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the barge-in."),
755
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the barge-in"),
756
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
757
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
758
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
759
+ debug: bool = typer.Option(False, "--debug"),
760
+ ):
761
+ """Barge In."""
762
+ api = get_api(debug=debug)
763
+ url = f"https://webexapis.com/v1/telephony/calls/bargeIn"
764
+ if json_body:
765
+ body = json.loads(json_body)
766
+ else:
767
+ body = {}
768
+ if target is not None:
769
+ body["target"] = target
770
+ if endpoint_id is not None:
771
+ body["endpointId"] = endpoint_id
772
+ if single_number_reach_phone_number is not None:
773
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
774
+ if line_owner_id is not None:
775
+ body["lineOwnerId"] = line_owner_id
776
+ _missing = [f for f in ['target'] if f not in body or body[f] is None]
777
+ if _missing:
778
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
779
+ raise typer.Exit(1)
780
+ try:
781
+ result = api.session.rest_post(url, json=body)
782
+ except WebexError as e:
783
+ handle_rest_error(e)
784
+ if output == "json":
785
+ print_json(result)
786
+ elif isinstance(result, dict) and "callId" in result:
787
+ typer.echo(f"Created: {result['callId']}")
788
+ elif isinstance(result, dict) and "id" in result:
789
+ typer.echo(f"Created: {result['id']}")
790
+ elif not result or result == {}:
791
+ typer.echo("Created.")
792
+ else:
793
+ print_json(result)
794
+
795
+
796
+
797
+ @app.command("list")
798
+ def cmd_list(
799
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
800
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
801
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
802
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
803
+ debug: bool = typer.Option(False, "--debug"),
804
+ ):
805
+ """List Calls."""
806
+ api = get_api(debug=debug)
807
+ url = f"https://webexapis.com/v1/telephony/calls"
808
+ params = {}
809
+ if line_owner_id is not None:
810
+ params["lineOwnerId"] = line_owner_id
811
+ if limit > 0:
812
+ params["max"] = limit
813
+ if offset > 0:
814
+ params["start"] = offset
815
+ result = None
816
+ try:
817
+ result = api.session.rest_get(url, params=params)
818
+ except WebexError as e:
819
+ handle_rest_error(e)
820
+ result = result or []
821
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
822
+ if output == "json":
823
+ print_json(items)
824
+ else:
825
+ print_table(items, columns=[('Call ID', 'id'), ('Personality', 'personality'), ('State', 'state'), ('Remote Party', 'remoteParty.name')], limit=limit)
826
+
827
+
828
+
829
+ @app.command("show")
830
+ def show(
831
+ call_id: str = typer.Argument(help="callId"),
832
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
833
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
834
+ debug: bool = typer.Option(False, "--debug"),
835
+ ):
836
+ """Get Call Details."""
837
+ api = get_api(debug=debug)
838
+ url = f"https://webexapis.com/v1/telephony/calls/{call_id}"
839
+ params = {}
840
+ if line_owner_id is not None:
841
+ params["lineOwnerId"] = line_owner_id
842
+ try:
843
+ result = api.session.rest_get(url, params=params)
844
+ except WebexError as e:
845
+ handle_rest_error(e)
846
+ if output == "json":
847
+ print_json(result)
848
+ else:
849
+ if isinstance(result, dict):
850
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
851
+ elif isinstance(result, list):
852
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
853
+ else:
854
+ print_json(result)
855
+
856
+
857
+
858
+ @app.command("list-history")
859
+ def list_history(
860
+ type_param: str = typer.Option(None, "--type", help="Choices: placed, missed, received"),
861
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
862
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
863
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
864
+ debug: bool = typer.Option(False, "--debug"),
865
+ ):
866
+ """List Call History."""
867
+ api = get_api(debug=debug)
868
+ url = f"https://webexapis.com/v1/telephony/calls/history"
869
+ params = {}
870
+ if type_param is not None:
871
+ params["type"] = type_param
872
+ if limit > 0:
873
+ params["max"] = limit
874
+ if offset > 0:
875
+ params["start"] = offset
876
+ result = None
877
+ try:
878
+ result = api.session.rest_get(url, params=params)
879
+ except WebexError as e:
880
+ handle_rest_error(e)
881
+ result = result or []
882
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
883
+ if output == "json":
884
+ print_json(items)
885
+ else:
886
+ print_table(items, columns=[('Type', 'type'), ('Name', 'name'), ('Number', 'number'), ('Time', 'time')], limit=limit)
887
+
888
+
889
+
890
+ @app.command("create-pull")
891
+ def create_pull(
892
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the retrieval"),
893
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
894
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
895
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
896
+ debug: bool = typer.Option(False, "--debug"),
897
+ ):
898
+ """Pull."""
899
+ api = get_api(debug=debug)
900
+ url = f"https://webexapis.com/v1/telephony/calls/pull"
901
+ if json_body:
902
+ body = json.loads(json_body)
903
+ else:
904
+ body = {}
905
+ if endpoint_id is not None:
906
+ body["endpointId"] = endpoint_id
907
+ if line_owner_id is not None:
908
+ body["lineOwnerId"] = line_owner_id
909
+ try:
910
+ result = api.session.rest_post(url, json=body)
911
+ except WebexError as e:
912
+ handle_rest_error(e)
913
+ if output == "json":
914
+ print_json(result)
915
+ elif isinstance(result, dict) and "callId" in result:
916
+ typer.echo(f"Created: {result['callId']}")
917
+ elif isinstance(result, dict) and "id" in result:
918
+ typer.echo(f"Created: {result['id']}")
919
+ elif not result or result == {}:
920
+ typer.echo("Created.")
921
+ else:
922
+ print_json(result)
923
+
924
+
925
+
926
+ @app.command("create-dial-members")
927
+ def create_dial_members(
928
+ member_id: str = typer.Argument(help="memberId"),
929
+ destination: str = typer.Option(None, "--destination", help="(required) The destination to be dialed. The destination can be digits"),
930
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the call. The"),
931
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the call. Mu"),
932
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
933
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
934
+ debug: bool = typer.Option(False, "--debug"),
935
+ ):
936
+ """Dial by Member ID."""
937
+ api = get_api(debug=debug)
938
+ url = f"https://webexapis.com/v1/telephony/calls/members/{member_id}/dial"
939
+ params = {}
940
+ org_id = get_org_id()
941
+ if org_id is not None:
942
+ params["orgId"] = org_id
943
+ if json_body:
944
+ body = json.loads(json_body)
945
+ else:
946
+ body = {}
947
+ if destination is not None:
948
+ body["destination"] = destination
949
+ if endpoint_id is not None:
950
+ body["endpointId"] = endpoint_id
951
+ if single_number_reach_phone_number is not None:
952
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
953
+ _missing = [f for f in ['destination'] if f not in body or body[f] is None]
954
+ if _missing:
955
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
956
+ raise typer.Exit(1)
957
+ try:
958
+ result = api.session.rest_post(url, json=body, params=params)
959
+ except WebexError as e:
960
+ handle_rest_error(e)
961
+ if output == "json":
962
+ print_json(result)
963
+ elif isinstance(result, dict) and "callId" in result:
964
+ typer.echo(f"Created: {result['callId']}")
965
+ elif isinstance(result, dict) and "id" in result:
966
+ typer.echo(f"Created: {result['id']}")
967
+ elif not result or result == {}:
968
+ typer.echo("Created.")
969
+ else:
970
+ print_json(result)
971
+
972
+
973
+
974
+ @app.command("create-answer-members")
975
+ def create_answer_members(
976
+ member_id: str = typer.Argument(help="memberId"),
977
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to be answered."),
978
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to answer the call on. T"),
979
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
980
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
981
+ debug: bool = typer.Option(False, "--debug"),
982
+ ):
983
+ """Answer by Member ID."""
984
+ api = get_api(debug=debug)
985
+ url = f"https://webexapis.com/v1/telephony/calls/members/{member_id}/answer"
986
+ params = {}
987
+ org_id = get_org_id()
988
+ if org_id is not None:
989
+ params["orgId"] = org_id
990
+ if json_body:
991
+ body = json.loads(json_body)
992
+ else:
993
+ body = {}
994
+ if call_id is not None:
995
+ body["callId"] = call_id
996
+ if endpoint_id is not None:
997
+ body["endpointId"] = endpoint_id
998
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
999
+ if _missing:
1000
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1001
+ raise typer.Exit(1)
1002
+ try:
1003
+ result = api.session.rest_post(url, json=body, params=params)
1004
+ except WebexError as e:
1005
+ handle_rest_error(e)
1006
+ if output == "json":
1007
+ print_json(result)
1008
+ elif isinstance(result, dict) and "id" in result:
1009
+ typer.echo(f"Created: {result['id']}")
1010
+ elif not result or result == {}:
1011
+ typer.echo("Created.")
1012
+ else:
1013
+ print_json(result)
1014
+
1015
+
1016
+
1017
+ @app.command("create-hangup-members")
1018
+ def create_hangup_members(
1019
+ member_id: str = typer.Argument(help="memberId"),
1020
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to hangup."),
1021
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1022
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1023
+ debug: bool = typer.Option(False, "--debug"),
1024
+ ):
1025
+ """Hangup by Member ID."""
1026
+ api = get_api(debug=debug)
1027
+ url = f"https://webexapis.com/v1/telephony/calls/members/{member_id}/hangup"
1028
+ params = {}
1029
+ org_id = get_org_id()
1030
+ if org_id is not None:
1031
+ params["orgId"] = org_id
1032
+ if json_body:
1033
+ body = json.loads(json_body)
1034
+ else:
1035
+ body = {}
1036
+ if call_id is not None:
1037
+ body["callId"] = call_id
1038
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
1039
+ if _missing:
1040
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1041
+ raise typer.Exit(1)
1042
+ try:
1043
+ result = api.session.rest_post(url, json=body, params=params)
1044
+ except WebexError as e:
1045
+ handle_rest_error(e)
1046
+ if output == "json":
1047
+ print_json(result)
1048
+ elif isinstance(result, dict) and "id" in result:
1049
+ typer.echo(f"Created: {result['id']}")
1050
+ elif not result or result == {}:
1051
+ typer.echo("Created.")
1052
+ else:
1053
+ print_json(result)
1054
+
1055
+
1056
+
1057
+ @app.command("list-calls-members")
1058
+ def list_calls_members(
1059
+ member_id: str = typer.Argument(help="memberId"),
1060
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1061
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1062
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1063
+ debug: bool = typer.Option(False, "--debug"),
1064
+ ):
1065
+ """List Calls by Member ID."""
1066
+ api = get_api(debug=debug)
1067
+ url = f"https://webexapis.com/v1/telephony/calls/members/{member_id}/calls"
1068
+ params = {}
1069
+ if limit > 0:
1070
+ params["max"] = limit
1071
+ if offset > 0:
1072
+ params["start"] = offset
1073
+ org_id = get_org_id()
1074
+ if org_id is not None:
1075
+ params["orgId"] = org_id
1076
+ result = None
1077
+ try:
1078
+ result = api.session.rest_get(url, params=params)
1079
+ except WebexError as e:
1080
+ handle_rest_error(e)
1081
+ result = result or []
1082
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1083
+ if output == "json":
1084
+ print_json(items)
1085
+ else:
1086
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1087
+
1088
+
1089
+
1090
+ @app.command("show-calls-members")
1091
+ def show_calls_members(
1092
+ member_id: str = typer.Argument(help="memberId"),
1093
+ call_id: str = typer.Argument(help="callId"),
1094
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1095
+ debug: bool = typer.Option(False, "--debug"),
1096
+ ):
1097
+ """Get Call Details by Member ID."""
1098
+ api = get_api(debug=debug)
1099
+ url = f"https://webexapis.com/v1/telephony/calls/members/{member_id}/calls/{call_id}"
1100
+ params = {}
1101
+ org_id = get_org_id()
1102
+ if org_id is not None:
1103
+ params["orgId"] = org_id
1104
+ try:
1105
+ result = api.session.rest_get(url, params=params)
1106
+ except WebexError as e:
1107
+ handle_rest_error(e)
1108
+ if output == "json":
1109
+ print_json(result)
1110
+ else:
1111
+ if isinstance(result, dict):
1112
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1113
+ elif isinstance(result, list):
1114
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1115
+ else:
1116
+ print_json(result)
1117
+
1118
+
1119
+
1120
+ @app.command("create-dial-me")
1121
+ def create_dial_me(
1122
+ destination: str = typer.Option(None, "--destination", help="(required) The destination to be dialed. The destination can be digits"),
1123
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to use for the call. The"),
1124
+ single_number_reach_phone_number: str = typer.Option(None, "--single-number-reach-phone-number", help="The Single Number Reach phone number to use for the call. Mu"),
1125
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
1126
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1127
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1128
+ debug: bool = typer.Option(False, "--debug"),
1129
+ ):
1130
+ """Dial."""
1131
+ api = get_api(debug=debug)
1132
+ url = f"https://webexapis.com/v1/telephony/calls/members/me/dial"
1133
+ if json_body:
1134
+ body = json.loads(json_body)
1135
+ else:
1136
+ body = {}
1137
+ if destination is not None:
1138
+ body["destination"] = destination
1139
+ if endpoint_id is not None:
1140
+ body["endpointId"] = endpoint_id
1141
+ if single_number_reach_phone_number is not None:
1142
+ body["singleNumberReachPhoneNumber"] = single_number_reach_phone_number
1143
+ if line_owner_id is not None:
1144
+ body["lineOwnerId"] = line_owner_id
1145
+ _missing = [f for f in ['destination'] if f not in body or body[f] is None]
1146
+ if _missing:
1147
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1148
+ raise typer.Exit(1)
1149
+ try:
1150
+ result = api.session.rest_post(url, json=body)
1151
+ except WebexError as e:
1152
+ handle_rest_error(e)
1153
+ if output == "json":
1154
+ print_json(result)
1155
+ elif isinstance(result, dict) and "callId" in result:
1156
+ typer.echo(f"Created: {result['callId']}")
1157
+ elif isinstance(result, dict) and "id" in result:
1158
+ typer.echo(f"Created: {result['id']}")
1159
+ elif not result or result == {}:
1160
+ typer.echo("Created.")
1161
+ else:
1162
+ print_json(result)
1163
+
1164
+
1165
+
1166
+ @app.command("create-answer-me")
1167
+ def create_answer_me(
1168
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to be answered."),
1169
+ endpoint_id: str = typer.Option(None, "--endpoint-id", help="The ID of the device or application to answer the call on. T"),
1170
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
1171
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1172
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1173
+ debug: bool = typer.Option(False, "--debug"),
1174
+ ):
1175
+ """Answer."""
1176
+ api = get_api(debug=debug)
1177
+ url = f"https://webexapis.com/v1/telephony/calls/members/me/answer"
1178
+ if json_body:
1179
+ body = json.loads(json_body)
1180
+ else:
1181
+ body = {}
1182
+ if call_id is not None:
1183
+ body["callId"] = call_id
1184
+ if endpoint_id is not None:
1185
+ body["endpointId"] = endpoint_id
1186
+ if line_owner_id is not None:
1187
+ body["lineOwnerId"] = line_owner_id
1188
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
1189
+ if _missing:
1190
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1191
+ raise typer.Exit(1)
1192
+ try:
1193
+ result = api.session.rest_post(url, json=body)
1194
+ except WebexError as e:
1195
+ handle_rest_error(e)
1196
+ if output == "json":
1197
+ print_json(result)
1198
+ elif isinstance(result, dict) and "id" in result:
1199
+ typer.echo(f"Created: {result['id']}")
1200
+ elif not result or result == {}:
1201
+ typer.echo("Created.")
1202
+ else:
1203
+ print_json(result)
1204
+
1205
+
1206
+
1207
+ @app.command("create-hangup-me")
1208
+ def create_hangup_me(
1209
+ call_id: str = typer.Option(None, "--call-id", help="(required) The call identifier of the call to hangup."),
1210
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
1211
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1212
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1213
+ debug: bool = typer.Option(False, "--debug"),
1214
+ ):
1215
+ """Hangup."""
1216
+ api = get_api(debug=debug)
1217
+ url = f"https://webexapis.com/v1/telephony/calls/members/me/hangup"
1218
+ if json_body:
1219
+ body = json.loads(json_body)
1220
+ else:
1221
+ body = {}
1222
+ if call_id is not None:
1223
+ body["callId"] = call_id
1224
+ if line_owner_id is not None:
1225
+ body["lineOwnerId"] = line_owner_id
1226
+ _missing = [f for f in ['callId'] if f not in body or body[f] is None]
1227
+ if _missing:
1228
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1229
+ raise typer.Exit(1)
1230
+ try:
1231
+ result = api.session.rest_post(url, json=body)
1232
+ except WebexError as e:
1233
+ handle_rest_error(e)
1234
+ if output == "json":
1235
+ print_json(result)
1236
+ elif isinstance(result, dict) and "id" in result:
1237
+ typer.echo(f"Created: {result['id']}")
1238
+ elif not result or result == {}:
1239
+ typer.echo("Created.")
1240
+ else:
1241
+ print_json(result)
1242
+
1243
+
1244
+
1245
+ @app.command("list-calls-me")
1246
+ def list_calls_me(
1247
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
1248
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1249
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1250
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1251
+ debug: bool = typer.Option(False, "--debug"),
1252
+ ):
1253
+ """List Calls."""
1254
+ api = get_api(debug=debug)
1255
+ url = f"https://webexapis.com/v1/telephony/calls/members/me/calls"
1256
+ params = {}
1257
+ if line_owner_id is not None:
1258
+ params["lineOwnerId"] = line_owner_id
1259
+ if limit > 0:
1260
+ params["max"] = limit
1261
+ if offset > 0:
1262
+ params["start"] = offset
1263
+ result = None
1264
+ try:
1265
+ result = api.session.rest_get(url, params=params)
1266
+ except WebexError as e:
1267
+ handle_rest_error(e)
1268
+ result = result or []
1269
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1270
+ if output == "json":
1271
+ print_json(items)
1272
+ else:
1273
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1274
+
1275
+
1276
+
1277
+ @app.command("show-calls-me")
1278
+ def show_calls_me(
1279
+ call_id: str = typer.Argument(help="callId"),
1280
+ line_owner_id: str = typer.Option(None, "--line-owner-id", help="The ID of a user, workspace, or virtual line for which there"),
1281
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1282
+ debug: bool = typer.Option(False, "--debug"),
1283
+ ):
1284
+ """Get Call Details."""
1285
+ api = get_api(debug=debug)
1286
+ url = f"https://webexapis.com/v1/telephony/calls/members/me/calls/{call_id}"
1287
+ params = {}
1288
+ if line_owner_id is not None:
1289
+ params["lineOwnerId"] = line_owner_id
1290
+ try:
1291
+ result = api.session.rest_get(url, params=params)
1292
+ except WebexError as e:
1293
+ handle_rest_error(e)
1294
+ if output == "json":
1295
+ print_json(result)
1296
+ else:
1297
+ if isinstance(result, dict):
1298
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1299
+ elif isinstance(result, list):
1300
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1301
+ else:
1302
+ print_json(result)
1303
+
1304
+