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,642 @@
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 auto-attendant.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ location_id: str = typer.Option(None, "--location-id", help="Return the list of auto attendants for this location."),
15
+ name: str = typer.Option(None, "--name", help="Only return auto attendants with the matching name."),
16
+ phone_number: str = typer.Option(None, "--phone-number", help="Only return auto attendants with the matching phone number."),
17
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
18
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
19
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
20
+ debug: bool = typer.Option(False, "--debug"),
21
+ ):
22
+ """Read the List of Auto Attendants."""
23
+ api = get_api(debug=debug)
24
+ url = f"https://webexapis.com/v1/telephony/config/autoAttendants"
25
+ params = {}
26
+ if location_id is not None:
27
+ params["locationId"] = location_id
28
+ if name is not None:
29
+ params["name"] = name
30
+ if phone_number is not None:
31
+ params["phoneNumber"] = phone_number
32
+ if limit > 0:
33
+ params["max"] = limit
34
+ if offset > 0:
35
+ params["start"] = offset
36
+ org_id = get_org_id()
37
+ if org_id is not None:
38
+ params["orgId"] = org_id
39
+ try:
40
+ if limit > 0:
41
+ result = api.session.rest_get(url, params=params)
42
+ result = result or {}
43
+ items = result.get("autoAttendants", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
44
+ else:
45
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="autoAttendants"))
46
+ except WebexError as e:
47
+ handle_rest_error(e)
48
+ if output == "json":
49
+ print_json(items)
50
+ else:
51
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
52
+
53
+
54
+
55
+ @app.command("show")
56
+ def show(
57
+ location_id: str = typer.Argument(help="locationId"),
58
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
59
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
60
+ debug: bool = typer.Option(False, "--debug"),
61
+ ):
62
+ """Get Details for an Auto Attendant."""
63
+ api = get_api(debug=debug)
64
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}"
65
+ params = {}
66
+ org_id = get_org_id()
67
+ if org_id is not None:
68
+ params["orgId"] = org_id
69
+ try:
70
+ result = api.session.rest_get(url, params=params)
71
+ except WebexError as e:
72
+ handle_rest_error(e)
73
+ if output == "json":
74
+ print_json(result)
75
+ else:
76
+ if isinstance(result, dict):
77
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
78
+ elif isinstance(result, list):
79
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
80
+ else:
81
+ print_json(result)
82
+
83
+
84
+
85
+ @app.command("update")
86
+ def update(
87
+ location_id: str = typer.Argument(help="locationId"),
88
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
89
+ name: str = typer.Option(None, "--name", help="Unique name for the auto attendant."),
90
+ phone_number: str = typer.Option(None, "--phone-number", help="Auto attendant phone number. Either `phoneNumber` or `exten"),
91
+ extension: str = typer.Option(None, "--extension", help="Auto attendant extension. Either `phoneNumber` or `extensio"),
92
+ first_name: str = typer.Option(None, "--first-name", help="First name defined for an auto attendant. This field has bee"),
93
+ last_name: str = typer.Option(None, "--last-name", help="Last name defined for an auto attendant. This field has been"),
94
+ language_code: str = typer.Option(None, "--language-code", help="Announcement language code for the auto attendant."),
95
+ business_schedule: str = typer.Option(None, "--business-schedule", help="Business hours defined for the auto attendant."),
96
+ holiday_schedule: str = typer.Option(None, "--holiday-schedule", help="Holiday defined for the auto attendant."),
97
+ extension_dialing: str = typer.Option(None, "--extension-dialing", help="Choices: ENTERPRISE, GROUP"),
98
+ name_dialing: str = typer.Option(None, "--name-dialing", help="Choices: ENTERPRISE, GROUP"),
99
+ time_zone: str = typer.Option(None, "--time-zone", help="Time zone defined for the auto attendant."),
100
+ dial_by_name: str = typer.Option(None, "--dial-by-name", help="Sets or clears the name to be used for dial by name function"),
101
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
102
+ debug: bool = typer.Option(False, "--debug"),
103
+ ):
104
+ """Update an Auto Attendant\n\nExample --json-body:\n '{"name":"...","phoneNumber":"...","extension":"...","firstName":"...","lastName":"...","alternateNumbers":[{"phoneNumber":"...","ringPattern":"...","tollFreeNumber":"..."}],"languageCode":"...","businessSchedule":"..."}'."""
105
+ api = get_api(debug=debug)
106
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}"
107
+ params = {}
108
+ org_id = get_org_id()
109
+ if org_id is not None:
110
+ params["orgId"] = org_id
111
+ if json_body:
112
+ body = json.loads(json_body)
113
+ else:
114
+ body = {}
115
+ if name is not None:
116
+ body["name"] = name
117
+ if phone_number is not None:
118
+ body["phoneNumber"] = phone_number
119
+ if extension is not None:
120
+ body["extension"] = extension
121
+ if first_name is not None:
122
+ body["firstName"] = first_name
123
+ if last_name is not None:
124
+ body["lastName"] = last_name
125
+ if language_code is not None:
126
+ body["languageCode"] = language_code
127
+ if business_schedule is not None:
128
+ body["businessSchedule"] = business_schedule
129
+ if holiday_schedule is not None:
130
+ body["holidaySchedule"] = holiday_schedule
131
+ if extension_dialing is not None:
132
+ body["extensionDialing"] = extension_dialing
133
+ if name_dialing is not None:
134
+ body["nameDialing"] = name_dialing
135
+ if time_zone is not None:
136
+ body["timeZone"] = time_zone
137
+ if dial_by_name is not None:
138
+ body["dialByName"] = dial_by_name
139
+ try:
140
+ result = api.session.rest_put(url, json=body, params=params)
141
+ except WebexError as e:
142
+ handle_rest_error(e)
143
+ typer.echo(f"Updated.")
144
+
145
+
146
+
147
+ @app.command("delete")
148
+ def delete(
149
+ location_id: str = typer.Argument(help="locationId"),
150
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
151
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
152
+ debug: bool = typer.Option(False, "--debug"),
153
+ ):
154
+ """Delete an Auto Attendant."""
155
+ if not force:
156
+ typer.confirm(f"Delete {auto_attendant_id}?", abort=True)
157
+ api = get_api(debug=debug)
158
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}"
159
+ params = {}
160
+ org_id = get_org_id()
161
+ if org_id is not None:
162
+ params["orgId"] = org_id
163
+ try:
164
+ api.session.rest_delete(url, params=params)
165
+ except WebexError as e:
166
+ handle_rest_error(e)
167
+ typer.echo(f"Deleted: {auto_attendant_id}")
168
+
169
+
170
+
171
+ @app.command("create")
172
+ def create(
173
+ location_id: str = typer.Argument(help="locationId"),
174
+ name: str = typer.Option(None, "--name", help="(required) Unique name for the auto attendant."),
175
+ phone_number: str = typer.Option(None, "--phone-number", help="Auto attendant phone number. Either `phoneNumber` or `exten"),
176
+ extension: str = typer.Option(None, "--extension", help="Auto attendant extension. Either `phoneNumber` or `extensio"),
177
+ first_name: str = typer.Option(None, "--first-name", help="First name defined for an auto attendant. This field has bee"),
178
+ last_name: str = typer.Option(None, "--last-name", help="Last name defined for an auto attendant. This field has been"),
179
+ language_code: str = typer.Option(None, "--language-code", help="Announcement language code for the auto attendant."),
180
+ business_schedule: str = typer.Option(None, "--business-schedule", help="(required) Business hours defined for the auto attendant."),
181
+ holiday_schedule: str = typer.Option(None, "--holiday-schedule", help="Holiday defined for the auto attendant."),
182
+ extension_dialing: str = typer.Option(None, "--extension-dialing", help="Choices: ENTERPRISE, GROUP"),
183
+ name_dialing: str = typer.Option(None, "--name-dialing", help="Choices: ENTERPRISE, GROUP"),
184
+ time_zone: str = typer.Option(None, "--time-zone", help="Time zone defined for the auto attendant."),
185
+ dial_by_name: str = typer.Option(None, "--dial-by-name", help="The name to be used for dial by name functions. Characters o"),
186
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
187
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
188
+ debug: bool = typer.Option(False, "--debug"),
189
+ ):
190
+ """Create an Auto Attendant\n\nExample --json-body:\n '{"name":"...","businessSchedule":"...","businessHoursMenu":{"greeting":"DEFAULT","extensionEnabled":true,"keyConfigurations":{"key":"...","action":"...","description":"...","value":"...","audioAnnouncementFile":"..."},"audioAnnouncementFile":{"id":"...","fileName":"...","mediaFileType":"...","level":"..."},"callTreatment":{"retryAttemptForNoInput":"...","noInputTimer":"...","actionToBePerformed":"..."}},"afterHoursMenu":{"greeting":"DEFAULT","extensionEnabled":true,"keyConfigurations":{"key":"...","action":"...","description":"...","value":"...","audioAnnouncementFile":"..."},"audioAnnouncementFile":{"id":"...","fileName":"...","mediaFileType":"...","level":"..."},"callTreatment":{"retryAttemptForNoInput":"...","noInputTimer":"...","actionToBePerformed":"..."}},"phoneNumber":"...","extension":"...","firstName":"...","lastName":"..."}'."""
191
+ api = get_api(debug=debug)
192
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants"
193
+ params = {}
194
+ org_id = get_org_id()
195
+ if org_id is not None:
196
+ params["orgId"] = org_id
197
+ if json_body:
198
+ body = json.loads(json_body)
199
+ else:
200
+ body = {}
201
+ if name is not None:
202
+ body["name"] = name
203
+ if phone_number is not None:
204
+ body["phoneNumber"] = phone_number
205
+ if extension is not None:
206
+ body["extension"] = extension
207
+ if first_name is not None:
208
+ body["firstName"] = first_name
209
+ if last_name is not None:
210
+ body["lastName"] = last_name
211
+ if language_code is not None:
212
+ body["languageCode"] = language_code
213
+ if business_schedule is not None:
214
+ body["businessSchedule"] = business_schedule
215
+ if holiday_schedule is not None:
216
+ body["holidaySchedule"] = holiday_schedule
217
+ if extension_dialing is not None:
218
+ body["extensionDialing"] = extension_dialing
219
+ if name_dialing is not None:
220
+ body["nameDialing"] = name_dialing
221
+ if time_zone is not None:
222
+ body["timeZone"] = time_zone
223
+ if dial_by_name is not None:
224
+ body["dialByName"] = dial_by_name
225
+ _missing = [f for f in ['name', 'businessSchedule'] if f not in body or body[f] is None]
226
+ if _missing:
227
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
228
+ raise typer.Exit(1)
229
+ try:
230
+ result = api.session.rest_post(url, json=body, params=params)
231
+ except WebexError as e:
232
+ handle_rest_error(e)
233
+ if output == "json":
234
+ print_json(result)
235
+ elif isinstance(result, dict) and "id" in result:
236
+ typer.echo(f"Created: {result['id']}")
237
+ elif not result or result == {}:
238
+ typer.echo("Created.")
239
+ else:
240
+ print_json(result)
241
+
242
+
243
+
244
+ @app.command("show-call-forwarding")
245
+ def show_call_forwarding(
246
+ location_id: str = typer.Argument(help="locationId"),
247
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
248
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
249
+ debug: bool = typer.Option(False, "--debug"),
250
+ ):
251
+ """Get Call Forwarding Settings for an Auto Attendant."""
252
+ api = get_api(debug=debug)
253
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding"
254
+ params = {}
255
+ org_id = get_org_id()
256
+ if org_id is not None:
257
+ params["orgId"] = org_id
258
+ try:
259
+ result = api.session.rest_get(url, params=params)
260
+ except WebexError as e:
261
+ handle_rest_error(e)
262
+ if output == "json":
263
+ print_json(result)
264
+ else:
265
+ if isinstance(result, dict):
266
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
267
+ elif isinstance(result, list):
268
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
269
+ else:
270
+ print_json(result)
271
+
272
+
273
+
274
+ @app.command("update-call-forwarding")
275
+ def update_call_forwarding(
276
+ location_id: str = typer.Argument(help="locationId"),
277
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
278
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
279
+ debug: bool = typer.Option(False, "--debug"),
280
+ ):
281
+ """Update Call Forwarding Settings for an Auto Attendant\n\nExample --json-body:\n '{"callForwarding":{"always":{"enabled":"...","destination":"...","ringReminderEnabled":"...","sendToVoicemailEnabled":"..."},"selective":{"enabled":"...","destination":"...","ringReminderEnabled":"...","sendToVoicemailEnabled":"..."},"rules":["..."],"operatingModes":{"enabled":"...","modes":"..."}}}'."""
282
+ api = get_api(debug=debug)
283
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding"
284
+ params = {}
285
+ org_id = get_org_id()
286
+ if org_id is not None:
287
+ params["orgId"] = org_id
288
+ if json_body:
289
+ body = json.loads(json_body)
290
+ else:
291
+ body = {}
292
+ try:
293
+ result = api.session.rest_put(url, json=body, params=params)
294
+ except WebexError as e:
295
+ handle_rest_error(e)
296
+ typer.echo(f"Updated.")
297
+
298
+
299
+
300
+ @app.command("create-selective-rules")
301
+ def create_selective_rules(
302
+ location_id: str = typer.Argument(help="locationId"),
303
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
304
+ name: str = typer.Option(None, "--name", help="(required) Unique name for the selective rule in the auto attendant."),
305
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Reflects if rule is enabled."),
306
+ business_schedule: str = typer.Option(None, "--business-schedule", help="Name of the location's business schedule which determines wh"),
307
+ holiday_schedule: str = typer.Option(None, "--holiday-schedule", help="Name of the location's holiday schedule which determines whe"),
308
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
309
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
310
+ debug: bool = typer.Option(False, "--debug"),
311
+ ):
312
+ """Create a Selective Call Forwarding Rule for an Auto Attendant\n\nExample --json-body:\n '{"name":"...","forwardTo":{"selection":"FORWARD_TO_DEFAULT_NUMBER","phoneNumber":"..."},"callsFrom":{"selection":"ANY","customNumbers":{"privateNumberEnabled":"...","unavailableNumberEnabled":"...","numbers":"..."}},"enabled":true,"businessSchedule":"...","holidaySchedule":"...","callsTo":{"numbers":["..."]}}'."""
313
+ api = get_api(debug=debug)
314
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding/selectiveRules"
315
+ params = {}
316
+ org_id = get_org_id()
317
+ if org_id is not None:
318
+ params["orgId"] = org_id
319
+ if json_body:
320
+ body = json.loads(json_body)
321
+ else:
322
+ body = {}
323
+ if name is not None:
324
+ body["name"] = name
325
+ if enabled is not None:
326
+ body["enabled"] = enabled
327
+ if business_schedule is not None:
328
+ body["businessSchedule"] = business_schedule
329
+ if holiday_schedule is not None:
330
+ body["holidaySchedule"] = holiday_schedule
331
+ _missing = [f for f in ['name'] if f not in body or body[f] is None]
332
+ if _missing:
333
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
334
+ raise typer.Exit(1)
335
+ try:
336
+ result = api.session.rest_post(url, json=body, params=params)
337
+ except WebexError as e:
338
+ handle_rest_error(e)
339
+ if output == "json":
340
+ print_json(result)
341
+ elif isinstance(result, dict) and "id" in result:
342
+ typer.echo(f"Created: {result['id']}")
343
+ elif not result or result == {}:
344
+ typer.echo("Created.")
345
+ else:
346
+ print_json(result)
347
+
348
+
349
+
350
+ @app.command("show-selective-rules")
351
+ def show_selective_rules(
352
+ location_id: str = typer.Argument(help="locationId"),
353
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
354
+ rule_id: str = typer.Argument(help="ruleId"),
355
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
356
+ debug: bool = typer.Option(False, "--debug"),
357
+ ):
358
+ """Get Selective Call Forwarding Rule for an Auto Attendant."""
359
+ api = get_api(debug=debug)
360
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding/selectiveRules/{rule_id}"
361
+ params = {}
362
+ org_id = get_org_id()
363
+ if org_id is not None:
364
+ params["orgId"] = org_id
365
+ try:
366
+ result = api.session.rest_get(url, params=params)
367
+ except WebexError as e:
368
+ handle_rest_error(e)
369
+ if output == "json":
370
+ print_json(result)
371
+ else:
372
+ if isinstance(result, dict):
373
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
374
+ elif isinstance(result, list):
375
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
376
+ else:
377
+ print_json(result)
378
+
379
+
380
+
381
+ @app.command("update-selective-rules")
382
+ def update_selective_rules(
383
+ location_id: str = typer.Argument(help="locationId"),
384
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
385
+ rule_id: str = typer.Argument(help="ruleId"),
386
+ name: str = typer.Option(None, "--name", help="Unique name for the selective rule in the auto attendant."),
387
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Reflects if rule is enabled."),
388
+ business_schedule: str = typer.Option(None, "--business-schedule", help="Name of the location's business schedule which determines wh"),
389
+ holiday_schedule: str = typer.Option(None, "--holiday-schedule", help="Name of the location's holiday schedule which determines whe"),
390
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
391
+ debug: bool = typer.Option(False, "--debug"),
392
+ ):
393
+ """Update Selective Call Forwarding Rule for an Auto Attendant\n\nExample --json-body:\n '{"name":"...","enabled":true,"businessSchedule":"...","holidaySchedule":"...","forwardTo":{"selection":"FORWARD_TO_DEFAULT_NUMBER","phoneNumber":"..."},"callsFrom":{"selection":"ANY","customNumbers":{"privateNumberEnabled":"...","unavailableNumberEnabled":"...","numbers":"..."}},"callsTo":{"numbers":["..."]}}'."""
394
+ api = get_api(debug=debug)
395
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding/selectiveRules/{rule_id}"
396
+ params = {}
397
+ org_id = get_org_id()
398
+ if org_id is not None:
399
+ params["orgId"] = org_id
400
+ if json_body:
401
+ body = json.loads(json_body)
402
+ else:
403
+ body = {}
404
+ if name is not None:
405
+ body["name"] = name
406
+ if enabled is not None:
407
+ body["enabled"] = enabled
408
+ if business_schedule is not None:
409
+ body["businessSchedule"] = business_schedule
410
+ if holiday_schedule is not None:
411
+ body["holidaySchedule"] = holiday_schedule
412
+ try:
413
+ result = api.session.rest_put(url, json=body, params=params)
414
+ except WebexError as e:
415
+ handle_rest_error(e)
416
+ typer.echo(f"Updated.")
417
+
418
+
419
+
420
+ @app.command("delete-selective-rules")
421
+ def delete_selective_rules(
422
+ location_id: str = typer.Argument(help="locationId"),
423
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
424
+ rule_id: str = typer.Argument(help="ruleId"),
425
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
426
+ debug: bool = typer.Option(False, "--debug"),
427
+ ):
428
+ """Delete a Selective Call Forwarding Rule for an Auto Attendant."""
429
+ if not force:
430
+ typer.confirm(f"Delete {rule_id}?", abort=True)
431
+ api = get_api(debug=debug)
432
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding/selectiveRules/{rule_id}"
433
+ params = {}
434
+ org_id = get_org_id()
435
+ if org_id is not None:
436
+ params["orgId"] = org_id
437
+ try:
438
+ api.session.rest_delete(url, params=params)
439
+ except WebexError as e:
440
+ handle_rest_error(e)
441
+ typer.echo(f"Deleted: {rule_id}")
442
+
443
+
444
+
445
+ @app.command("list-available-numbers-auto-attendants")
446
+ def list_available_numbers_auto_attendants(
447
+ location_id: str = typer.Argument(help="locationId"),
448
+ phone_number: str = typer.Option(None, "--phone-number", help="Filter phone numbers based on the comma-separated list provi"),
449
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
450
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
451
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
452
+ debug: bool = typer.Option(False, "--debug"),
453
+ ):
454
+ """Get Auto Attendant Primary Available Phone Numbers."""
455
+ api = get_api(debug=debug)
456
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/availableNumbers"
457
+ params = {}
458
+ if phone_number is not None:
459
+ params["phoneNumber"] = phone_number
460
+ if limit > 0:
461
+ params["max"] = limit
462
+ if offset > 0:
463
+ params["start"] = offset
464
+ org_id = get_org_id()
465
+ if org_id is not None:
466
+ params["orgId"] = org_id
467
+ result = None
468
+ try:
469
+ result = api.session.rest_get(url, params=params)
470
+ except WebexError as e:
471
+ handle_rest_error(e)
472
+ result = result or []
473
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
474
+ if output == "json":
475
+ print_json(items)
476
+ else:
477
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
478
+
479
+
480
+
481
+ @app.command("list-available-numbers-alternate")
482
+ def list_available_numbers_alternate(
483
+ location_id: str = typer.Argument(help="locationId"),
484
+ phone_number: str = typer.Option(None, "--phone-number", help="Filter phone numbers based on the comma-separated list provi"),
485
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
486
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
487
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
488
+ debug: bool = typer.Option(False, "--debug"),
489
+ ):
490
+ """Get Auto Attendant Alternate Available Phone Numbers."""
491
+ api = get_api(debug=debug)
492
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/alternate/availableNumbers"
493
+ params = {}
494
+ if phone_number is not None:
495
+ params["phoneNumber"] = phone_number
496
+ if limit > 0:
497
+ params["max"] = limit
498
+ if offset > 0:
499
+ params["start"] = offset
500
+ org_id = get_org_id()
501
+ if org_id is not None:
502
+ params["orgId"] = org_id
503
+ result = None
504
+ try:
505
+ result = api.session.rest_get(url, params=params)
506
+ except WebexError as e:
507
+ handle_rest_error(e)
508
+ result = result or []
509
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
510
+ if output == "json":
511
+ print_json(items)
512
+ else:
513
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
514
+
515
+
516
+
517
+ @app.command("list-available-numbers-call-forwarding")
518
+ def list_available_numbers_call_forwarding(
519
+ location_id: str = typer.Argument(help="locationId"),
520
+ phone_number: str = typer.Option(None, "--phone-number", help="Filter phone numbers based on the comma-separated list provi"),
521
+ owner_name: str = typer.Option(None, "--owner-name", help="Return the list of phone numbers that are owned by the given"),
522
+ extension: str = typer.Option(None, "--extension", help="Returns the list of PSTN phone numbers with the given `exten"),
523
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
524
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
525
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
526
+ debug: bool = typer.Option(False, "--debug"),
527
+ ):
528
+ """Get Auto Attendant Call Forward Available Phone Numbers."""
529
+ api = get_api(debug=debug)
530
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/callForwarding/availableNumbers"
531
+ params = {}
532
+ if phone_number is not None:
533
+ params["phoneNumber"] = phone_number
534
+ if owner_name is not None:
535
+ params["ownerName"] = owner_name
536
+ if extension is not None:
537
+ params["extension"] = extension
538
+ if limit > 0:
539
+ params["max"] = limit
540
+ if offset > 0:
541
+ params["start"] = offset
542
+ org_id = get_org_id()
543
+ if org_id is not None:
544
+ params["orgId"] = org_id
545
+ result = None
546
+ try:
547
+ result = api.session.rest_get(url, params=params)
548
+ except WebexError as e:
549
+ handle_rest_error(e)
550
+ result = result or []
551
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
552
+ if output == "json":
553
+ print_json(items)
554
+ else:
555
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
556
+
557
+
558
+
559
+ @app.command("switch-mode-for")
560
+ def switch_mode_for(
561
+ location_id: str = typer.Argument(help="locationId"),
562
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
563
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body"),
564
+ debug: bool = typer.Option(False, "--debug"),
565
+ ):
566
+ """Switch Mode for Call Forwarding Settings for an Auto Attendant."""
567
+ api = get_api(debug=debug)
568
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/callForwarding/actions/switchMode/invoke"
569
+ params = {}
570
+ org_id = get_org_id()
571
+ if org_id is not None:
572
+ params["orgId"] = org_id
573
+ if json_body:
574
+ body = json.loads(json_body)
575
+ else:
576
+ body = {}
577
+ try:
578
+ result = api.session.rest_post(url, json=body, params=params)
579
+ except WebexError as e:
580
+ handle_rest_error(e)
581
+ print_json(result)
582
+
583
+
584
+
585
+ @app.command("delete-announcements")
586
+ def delete_announcements(
587
+ location_id: str = typer.Argument(help="locationId"),
588
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
589
+ file_name: str = typer.Argument(help="fileName"),
590
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
591
+ debug: bool = typer.Option(False, "--debug"),
592
+ ):
593
+ """Delete a Auto Attendant Announcement File."""
594
+ if not force:
595
+ typer.confirm(f"Delete {file_name}?", abort=True)
596
+ api = get_api(debug=debug)
597
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/announcements/{file_name}"
598
+ params = {}
599
+ org_id = get_org_id()
600
+ if org_id is not None:
601
+ params["orgId"] = org_id
602
+ try:
603
+ api.session.rest_delete(url, params=params)
604
+ except WebexError as e:
605
+ handle_rest_error(e)
606
+ typer.echo(f"Deleted: {file_name}")
607
+
608
+
609
+
610
+ @app.command("list-announcements")
611
+ def list_announcements(
612
+ location_id: str = typer.Argument(help="locationId"),
613
+ auto_attendant_id: str = typer.Argument(help="autoAttendantId"),
614
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
615
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
616
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
617
+ debug: bool = typer.Option(False, "--debug"),
618
+ ):
619
+ """Read the List of Auto Attendant Announcement Files."""
620
+ api = get_api(debug=debug)
621
+ url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/autoAttendants/{auto_attendant_id}/announcements"
622
+ params = {}
623
+ if limit > 0:
624
+ params["max"] = limit
625
+ if offset > 0:
626
+ params["start"] = offset
627
+ org_id = get_org_id()
628
+ if org_id is not None:
629
+ params["orgId"] = org_id
630
+ result = None
631
+ try:
632
+ result = api.session.rest_get(url, params=params)
633
+ except WebexError as e:
634
+ handle_rest_error(e)
635
+ result = result or []
636
+ items = result.get("announcements", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
637
+ if output == "json":
638
+ print_json(items)
639
+ else:
640
+ print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
641
+
642
+