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,3577 @@
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
+
7
+
8
+ app = typer.Typer(help="Manage Webex Calling my-call-settings.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
14
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
15
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
16
+ debug: bool = typer.Option(False, "--debug"),
17
+ ):
18
+ """Get List Available Preferred Answer Endpoints."""
19
+ api = get_api(debug=debug)
20
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/availablePreferredAnswerEndpoints"
21
+ params = {}
22
+ if limit > 0:
23
+ params["max"] = limit
24
+ if offset > 0:
25
+ params["start"] = offset
26
+ result = None
27
+ try:
28
+ result = api.session.rest_get(url, params=params)
29
+ except WebexError as e:
30
+ handle_rest_error(e)
31
+ result = result or []
32
+ items = result.get("endpoints", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
33
+ if output == "json":
34
+ print_json(items)
35
+ else:
36
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
37
+
38
+
39
+
40
+ @app.command("list-available-preferred-answer-endpoints")
41
+ def list_available_preferred_answer_endpoints(
42
+ line_owner_id: str = typer.Argument(help="lineOwnerId"),
43
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
44
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
45
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
46
+ debug: bool = typer.Option(False, "--debug"),
47
+ ):
48
+ """Get My Secondary Line Owner's Available Preferred Answer Endpoint List."""
49
+ api = get_api(debug=debug)
50
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{line_owner_id}/availablePreferredAnswerEndpoints"
51
+ params = {}
52
+ if limit > 0:
53
+ params["max"] = limit
54
+ if offset > 0:
55
+ params["start"] = offset
56
+ result = None
57
+ try:
58
+ result = api.session.rest_get(url, params=params)
59
+ except WebexError as e:
60
+ handle_rest_error(e)
61
+ result = result or []
62
+ items = result.get("endpoints", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
63
+ if output == "json":
64
+ print_json(items)
65
+ else:
66
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
67
+
68
+
69
+
70
+ @app.command("show")
71
+ def show(
72
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
73
+ debug: bool = typer.Option(False, "--debug"),
74
+ ):
75
+ """Get Preferred Answer Endpoint."""
76
+ api = get_api(debug=debug)
77
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/preferredAnswerEndpoint"
78
+ try:
79
+ result = api.session.rest_get(url)
80
+ except WebexError as e:
81
+ handle_rest_error(e)
82
+ if output == "json":
83
+ print_json(result)
84
+ else:
85
+ if isinstance(result, dict):
86
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
87
+ elif isinstance(result, list):
88
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
89
+ else:
90
+ print_json(result)
91
+
92
+
93
+
94
+ @app.command("update")
95
+ def update(
96
+ preferred_answer_endpoint_id: str = typer.Option(None, "--preferred-answer-endpoint-id", help="Person’s preferred answer endpoint."),
97
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
98
+ debug: bool = typer.Option(False, "--debug"),
99
+ ):
100
+ """Modify Preferred Answer Endpoint."""
101
+ api = get_api(debug=debug)
102
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/preferredAnswerEndpoint"
103
+ if json_body:
104
+ body = json.loads(json_body)
105
+ else:
106
+ body = {}
107
+ if preferred_answer_endpoint_id is not None:
108
+ body["preferredAnswerEndpointId"] = preferred_answer_endpoint_id
109
+ try:
110
+ result = api.session.rest_put(url, json=body)
111
+ except WebexError as e:
112
+ handle_rest_error(e)
113
+ typer.echo(f"Updated.")
114
+
115
+
116
+
117
+ @app.command("show-preferred-answer-endpoint")
118
+ def show_preferred_answer_endpoint(
119
+ line_owner_id: str = typer.Argument(help="lineOwnerId"),
120
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
121
+ debug: bool = typer.Option(False, "--debug"),
122
+ ):
123
+ """Get My Secondary Line Owner's Preferred Answer Endpoint."""
124
+ api = get_api(debug=debug)
125
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{line_owner_id}/preferredAnswerEndpoint"
126
+ try:
127
+ result = api.session.rest_get(url)
128
+ except WebexError as e:
129
+ handle_rest_error(e)
130
+ if output == "json":
131
+ print_json(result)
132
+ else:
133
+ if isinstance(result, dict):
134
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
135
+ elif isinstance(result, list):
136
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
137
+ else:
138
+ print_json(result)
139
+
140
+
141
+
142
+ @app.command("update-preferred-answer-endpoint")
143
+ def update_preferred_answer_endpoint(
144
+ line_owner_id: str = typer.Argument(help="lineOwnerId"),
145
+ preferred_answer_endpoint_id: str = typer.Option(None, "--preferred-answer-endpoint-id", help="Person’s preferred answer endpoint."),
146
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
147
+ debug: bool = typer.Option(False, "--debug"),
148
+ ):
149
+ """Modify My Secondary Line Owner's Preferred Answer Endpoint."""
150
+ api = get_api(debug=debug)
151
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{line_owner_id}/preferredAnswerEndpoint"
152
+ if json_body:
153
+ body = json.loads(json_body)
154
+ else:
155
+ body = {}
156
+ if preferred_answer_endpoint_id is not None:
157
+ body["preferredAnswerEndpointId"] = preferred_answer_endpoint_id
158
+ try:
159
+ result = api.session.rest_put(url, json=body)
160
+ except WebexError as e:
161
+ handle_rest_error(e)
162
+ typer.echo(f"Updated.")
163
+
164
+
165
+
166
+ @app.command("show-webex-go-override")
167
+ def show_webex_go_override(
168
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
169
+ debug: bool = typer.Option(False, "--debug"),
170
+ ):
171
+ """Get My WebexGoOverride Settings."""
172
+ api = get_api(debug=debug)
173
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/webexGoOverride"
174
+ try:
175
+ result = api.session.rest_get(url)
176
+ except WebexError as e:
177
+ handle_rest_error(e)
178
+ if output == "json":
179
+ print_json(result)
180
+ else:
181
+ if isinstance(result, dict):
182
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
183
+ elif isinstance(result, list):
184
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
185
+ else:
186
+ print_json(result)
187
+
188
+
189
+
190
+ @app.command("update-webex-go-override")
191
+ def update_webex_go_override(
192
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="True if the \"Mobile User Aware\" override setting for Do Not"),
193
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
194
+ debug: bool = typer.Option(False, "--debug"),
195
+ ):
196
+ """Modify My WebexGoOverride Settings."""
197
+ api = get_api(debug=debug)
198
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/webexGoOverride"
199
+ if json_body:
200
+ body = json.loads(json_body)
201
+ else:
202
+ body = {}
203
+ if enabled is not None:
204
+ body["enabled"] = enabled
205
+ try:
206
+ result = api.session.rest_put(url, json=body)
207
+ except WebexError as e:
208
+ handle_rest_error(e)
209
+ typer.echo(f"Updated.")
210
+
211
+
212
+
213
+ @app.command("show-caller-id-settings")
214
+ def show_caller_id_settings(
215
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
216
+ debug: bool = typer.Option(False, "--debug"),
217
+ ):
218
+ """Get My Caller ID Settings."""
219
+ api = get_api(debug=debug)
220
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callerId"
221
+ try:
222
+ result = api.session.rest_get(url)
223
+ except WebexError as e:
224
+ handle_rest_error(e)
225
+ if output == "json":
226
+ print_json(result)
227
+ else:
228
+ if isinstance(result, dict):
229
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
230
+ elif isinstance(result, list):
231
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
232
+ else:
233
+ print_json(result)
234
+
235
+
236
+
237
+ @app.command("update-caller-id-settings")
238
+ def update_caller_id_settings(
239
+ calling_line_id_delivery_blocking_enabled: bool = typer.Option(None, "--calling-line-id-delivery-blocking-enabled/--no-calling-line-id-delivery-blocking-enabled", help="If `true`, the user's name and phone number are not shown to"),
240
+ connected_line_identification_restriction_enabled: bool = typer.Option(None, "--connected-line-identification-restriction-enabled/--no-connected-line-identification-restriction-enabled", help="If `true`, the user's name and phone number are not shown wh"),
241
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
242
+ debug: bool = typer.Option(False, "--debug"),
243
+ ):
244
+ """Modify My Caller ID Settings."""
245
+ api = get_api(debug=debug)
246
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callerId"
247
+ if json_body:
248
+ body = json.loads(json_body)
249
+ else:
250
+ body = {}
251
+ if calling_line_id_delivery_blocking_enabled is not None:
252
+ body["callingLineIdDeliveryBlockingEnabled"] = calling_line_id_delivery_blocking_enabled
253
+ if connected_line_identification_restriction_enabled is not None:
254
+ body["connectedLineIdentificationRestrictionEnabled"] = connected_line_identification_restriction_enabled
255
+ try:
256
+ result = api.session.rest_put(url, json=body)
257
+ except WebexError as e:
258
+ handle_rest_error(e)
259
+ typer.echo(f"Updated.")
260
+
261
+
262
+
263
+ @app.command("show-caller-id-secondary-lines")
264
+ def show_caller_id_secondary_lines(
265
+ lineowner_id: str = typer.Argument(help="lineownerId"),
266
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
267
+ debug: bool = typer.Option(False, "--debug"),
268
+ ):
269
+ """Get My Secondary Line Owner Caller ID Settings."""
270
+ api = get_api(debug=debug)
271
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callerId"
272
+ try:
273
+ result = api.session.rest_get(url)
274
+ except WebexError as e:
275
+ handle_rest_error(e)
276
+ if output == "json":
277
+ print_json(result)
278
+ else:
279
+ if isinstance(result, dict):
280
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
281
+ elif isinstance(result, list):
282
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
283
+ else:
284
+ print_json(result)
285
+
286
+
287
+
288
+ @app.command("update-caller-id-secondary-lines")
289
+ def update_caller_id_secondary_lines(
290
+ lineowner_id: str = typer.Argument(help="lineownerId"),
291
+ calling_line_id_delivery_blocking_enabled: bool = typer.Option(None, "--calling-line-id-delivery-blocking-enabled/--no-calling-line-id-delivery-blocking-enabled", help="If `true`, the user's name and phone number are not shown to"),
292
+ connected_line_identification_restriction_enabled: bool = typer.Option(None, "--connected-line-identification-restriction-enabled/--no-connected-line-identification-restriction-enabled", help="If `true`, the user's name and phone number are not shown wh"),
293
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
294
+ debug: bool = typer.Option(False, "--debug"),
295
+ ):
296
+ """Modify My Secondary Line Owner Caller ID Settings."""
297
+ api = get_api(debug=debug)
298
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callerId"
299
+ if json_body:
300
+ body = json.loads(json_body)
301
+ else:
302
+ body = {}
303
+ if calling_line_id_delivery_blocking_enabled is not None:
304
+ body["callingLineIdDeliveryBlockingEnabled"] = calling_line_id_delivery_blocking_enabled
305
+ if connected_line_identification_restriction_enabled is not None:
306
+ body["connectedLineIdentificationRestrictionEnabled"] = connected_line_identification_restriction_enabled
307
+ try:
308
+ result = api.session.rest_put(url, json=body)
309
+ except WebexError as e:
310
+ handle_rest_error(e)
311
+ typer.echo(f"Updated.")
312
+
313
+
314
+
315
+ @app.command("show-selected-caller-id-settings")
316
+ def show_selected_caller_id_settings(
317
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
318
+ debug: bool = typer.Option(False, "--debug"),
319
+ ):
320
+ """Read My Selected Caller ID Settings."""
321
+ api = get_api(debug=debug)
322
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectedCallerId"
323
+ try:
324
+ result = api.session.rest_get(url)
325
+ except WebexError as e:
326
+ handle_rest_error(e)
327
+ if output == "json":
328
+ print_json(result)
329
+ else:
330
+ if isinstance(result, dict):
331
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
332
+ elif isinstance(result, list):
333
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
334
+ else:
335
+ print_json(result)
336
+
337
+
338
+
339
+ @app.command("update-selected-caller-id-settings")
340
+ def update_selected_caller_id_settings(
341
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
342
+ debug: bool = typer.Option(False, "--debug"),
343
+ ):
344
+ """Configure My Selected Caller ID Settings\n\nExample --json-body:\n '{"selected":{"type":"DEFAULT_CLID","id":"...","directNumber":"..."}}'."""
345
+ api = get_api(debug=debug)
346
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectedCallerId"
347
+ if json_body:
348
+ body = json.loads(json_body)
349
+ else:
350
+ body = {}
351
+ try:
352
+ result = api.session.rest_put(url, json=body)
353
+ except WebexError as e:
354
+ handle_rest_error(e)
355
+ typer.echo(f"Updated.")
356
+
357
+
358
+
359
+ @app.command("show-selected-caller-id-secondary-lines")
360
+ def show_selected_caller_id_secondary_lines(
361
+ lineowner_id: str = typer.Argument(help="lineownerId"),
362
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
363
+ debug: bool = typer.Option(False, "--debug"),
364
+ ):
365
+ """Get My Secondary Line Owner's Selected Caller ID Settings."""
366
+ api = get_api(debug=debug)
367
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/selectedCallerId"
368
+ try:
369
+ result = api.session.rest_get(url)
370
+ except WebexError as e:
371
+ handle_rest_error(e)
372
+ if output == "json":
373
+ print_json(result)
374
+ else:
375
+ if isinstance(result, dict):
376
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
377
+ elif isinstance(result, list):
378
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
379
+ else:
380
+ print_json(result)
381
+
382
+
383
+
384
+ @app.command("update-selected-caller-id-secondary-lines")
385
+ def update_selected_caller_id_secondary_lines(
386
+ lineowner_id: str = typer.Argument(help="lineownerId"),
387
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
388
+ debug: bool = typer.Option(False, "--debug"),
389
+ ):
390
+ """Modify My Secondary Line Owner's Selected Caller ID Settings\n\nExample --json-body:\n '{"selected":{"type":"DEFAULT_CLID","id":"...","directNumber":"..."}}'."""
391
+ api = get_api(debug=debug)
392
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/selectedCallerId"
393
+ if json_body:
394
+ body = json.loads(json_body)
395
+ else:
396
+ body = {}
397
+ try:
398
+ result = api.session.rest_put(url, json=body)
399
+ except WebexError as e:
400
+ handle_rest_error(e)
401
+ typer.echo(f"Updated.")
402
+
403
+
404
+
405
+ @app.command("list-available-caller-ids-settings")
406
+ def list_available_caller_ids_settings(
407
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
408
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
409
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
410
+ debug: bool = typer.Option(False, "--debug"),
411
+ ):
412
+ """Get My Available Caller ID List."""
413
+ api = get_api(debug=debug)
414
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/availableCallerIds"
415
+ params = {}
416
+ if limit > 0:
417
+ params["max"] = limit
418
+ if offset > 0:
419
+ params["start"] = offset
420
+ result = None
421
+ try:
422
+ result = api.session.rest_get(url, params=params)
423
+ except WebexError as e:
424
+ handle_rest_error(e)
425
+ result = result or []
426
+ items = result.get("availableCallerIds", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
427
+ if output == "json":
428
+ print_json(items)
429
+ else:
430
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
431
+
432
+
433
+
434
+ @app.command("list-available-caller-ids-secondary-lines")
435
+ def list_available_caller_ids_secondary_lines(
436
+ lineowner_id: str = typer.Argument(help="lineownerId"),
437
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
438
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
439
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
440
+ debug: bool = typer.Option(False, "--debug"),
441
+ ):
442
+ """Get My Secondary Line Owner's Available Caller ID List."""
443
+ api = get_api(debug=debug)
444
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/availableCallerIds"
445
+ params = {}
446
+ if limit > 0:
447
+ params["max"] = limit
448
+ if offset > 0:
449
+ params["start"] = offset
450
+ result = None
451
+ try:
452
+ result = api.session.rest_get(url, params=params)
453
+ except WebexError as e:
454
+ handle_rest_error(e)
455
+ result = result or []
456
+ items = result.get("availableCallerIds", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
457
+ if output == "json":
458
+ print_json(items)
459
+ else:
460
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
461
+
462
+
463
+
464
+ @app.command("list-endpoints")
465
+ def list_endpoints(
466
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
467
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
468
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
469
+ debug: bool = typer.Option(False, "--debug"),
470
+ ):
471
+ """Read the List of My Endpoints."""
472
+ api = get_api(debug=debug)
473
+ url = f"https://webexapis.com/v1/telephony/config/people/me/endpoints"
474
+ params = {}
475
+ if limit > 0:
476
+ params["max"] = limit
477
+ if offset > 0:
478
+ params["start"] = offset
479
+ result = None
480
+ try:
481
+ result = api.session.rest_get(url, params=params)
482
+ except WebexError as e:
483
+ handle_rest_error(e)
484
+ result = result or []
485
+ items = result.get("endpoints", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
486
+ if output == "json":
487
+ print_json(items)
488
+ else:
489
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
490
+
491
+
492
+
493
+ @app.command("show-endpoints")
494
+ def show_endpoints(
495
+ endpoint_id: str = typer.Argument(help="endpointId"),
496
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
497
+ debug: bool = typer.Option(False, "--debug"),
498
+ ):
499
+ """Get My Endpoints Details."""
500
+ api = get_api(debug=debug)
501
+ url = f"https://webexapis.com/v1/telephony/config/people/me/endpoints/{endpoint_id}"
502
+ try:
503
+ result = api.session.rest_get(url)
504
+ except WebexError as e:
505
+ handle_rest_error(e)
506
+ if output == "json":
507
+ print_json(result)
508
+ else:
509
+ if isinstance(result, dict):
510
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
511
+ elif isinstance(result, list):
512
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
513
+ else:
514
+ print_json(result)
515
+
516
+
517
+
518
+ @app.command("update-endpoints")
519
+ def update_endpoints(
520
+ endpoint_id: str = typer.Argument(help="endpointId"),
521
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
522
+ debug: bool = typer.Option(False, "--debug"),
523
+ ):
524
+ """Modify My Endpoints Details\n\nExample --json-body:\n '{"mobilitySettings":{"alertingEnabled":true}}'."""
525
+ api = get_api(debug=debug)
526
+ url = f"https://webexapis.com/v1/telephony/config/people/me/endpoints/{endpoint_id}"
527
+ if json_body:
528
+ body = json.loads(json_body)
529
+ else:
530
+ body = {}
531
+ try:
532
+ result = api.session.rest_put(url, json=body)
533
+ except WebexError as e:
534
+ handle_rest_error(e)
535
+ typer.echo(f"Updated.")
536
+
537
+
538
+
539
+ @app.command("show-call-recording-settings")
540
+ def show_call_recording_settings(
541
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
542
+ debug: bool = typer.Option(False, "--debug"),
543
+ ):
544
+ """Get My Call Recording Settings."""
545
+ api = get_api(debug=debug)
546
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callRecording"
547
+ try:
548
+ result = api.session.rest_get(url)
549
+ except WebexError as e:
550
+ handle_rest_error(e)
551
+ if output == "json":
552
+ print_json(result)
553
+ else:
554
+ if isinstance(result, dict):
555
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
556
+ elif isinstance(result, list):
557
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
558
+ else:
559
+ print_json(result)
560
+
561
+
562
+
563
+ @app.command("show-call-recording-secondary-lines")
564
+ def show_call_recording_secondary_lines(
565
+ lineowner_id: str = typer.Argument(help="lineownerId"),
566
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
567
+ debug: bool = typer.Option(False, "--debug"),
568
+ ):
569
+ """Get My Secondary Line Owner's Call Recording Settings."""
570
+ api = get_api(debug=debug)
571
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callRecording"
572
+ try:
573
+ result = api.session.rest_get(url)
574
+ except WebexError as e:
575
+ handle_rest_error(e)
576
+ if output == "json":
577
+ print_json(result)
578
+ else:
579
+ if isinstance(result, dict):
580
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
581
+ elif isinstance(result, list):
582
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
583
+ else:
584
+ print_json(result)
585
+
586
+
587
+
588
+ @app.command("show-me")
589
+ def show_me(
590
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
591
+ debug: bool = typer.Option(False, "--debug"),
592
+ ):
593
+ """Get My Own Details."""
594
+ api = get_api(debug=debug)
595
+ url = f"https://webexapis.com/v1/telephony/config/people/me"
596
+ try:
597
+ result = api.session.rest_get(url)
598
+ except WebexError as e:
599
+ handle_rest_error(e)
600
+ if output == "json":
601
+ print_json(result)
602
+ else:
603
+ if isinstance(result, dict):
604
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
605
+ elif isinstance(result, list):
606
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
607
+ else:
608
+ print_json(result)
609
+
610
+
611
+
612
+ @app.command("list-feature-access-code-settings")
613
+ def list_feature_access_code_settings(
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
+ """Get My Feature Access Codes."""
620
+ api = get_api(debug=debug)
621
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/featureAccessCode"
622
+ params = {}
623
+ if limit > 0:
624
+ params["max"] = limit
625
+ if offset > 0:
626
+ params["start"] = offset
627
+ result = None
628
+ try:
629
+ result = api.session.rest_get(url, params=params)
630
+ except WebexError as e:
631
+ handle_rest_error(e)
632
+ result = result or []
633
+ items = result.get("featureAccessCodeList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
634
+ if output == "json":
635
+ print_json(items)
636
+ else:
637
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
638
+
639
+
640
+
641
+ @app.command("list-feature-access-code-secondary-lines")
642
+ def list_feature_access_code_secondary_lines(
643
+ lineowner_id: str = typer.Argument(help="lineownerId"),
644
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
645
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
646
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
647
+ debug: bool = typer.Option(False, "--debug"),
648
+ ):
649
+ """Get My Feature Access Codes For Secondary Line Owner."""
650
+ api = get_api(debug=debug)
651
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/featureAccessCode"
652
+ params = {}
653
+ if limit > 0:
654
+ params["max"] = limit
655
+ if offset > 0:
656
+ params["start"] = offset
657
+ result = None
658
+ try:
659
+ result = api.session.rest_get(url, params=params)
660
+ except WebexError as e:
661
+ handle_rest_error(e)
662
+ result = result or []
663
+ items = result.get("featureAccessCodeList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
664
+ if output == "json":
665
+ print_json(items)
666
+ else:
667
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
668
+
669
+
670
+
671
+ @app.command("list-assigned-assistants")
672
+ def list_assigned_assistants(
673
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
674
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
675
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
676
+ debug: bool = typer.Option(False, "--debug"),
677
+ ):
678
+ """Get My Executive Assigned Assistants."""
679
+ api = get_api(debug=debug)
680
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/executive/assignedAssistants"
681
+ params = {}
682
+ if limit > 0:
683
+ params["max"] = limit
684
+ if offset > 0:
685
+ params["start"] = offset
686
+ result = None
687
+ try:
688
+ result = api.session.rest_get(url, params=params)
689
+ except WebexError as e:
690
+ handle_rest_error(e)
691
+ result = result or []
692
+ items = result.get("assistants", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
693
+ if output == "json":
694
+ print_json(items)
695
+ else:
696
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
697
+
698
+
699
+
700
+ @app.command("update-assigned-assistants")
701
+ def update_assigned_assistants(
702
+ allow_opt_in_out_enabled: bool = typer.Option(None, "--allow-opt-in-out-enabled/--no-allow-opt-in-out-enabled", help="If `true`, the executive can allow assistants to opt in or o"),
703
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
704
+ debug: bool = typer.Option(False, "--debug"),
705
+ ):
706
+ """Modify My Executive Assigned Assistants\n\nExample --json-body:\n '{"allowOptInOutEnabled":true,"assistantIds":["..."]}'."""
707
+ api = get_api(debug=debug)
708
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/executive/assignedAssistants"
709
+ if json_body:
710
+ body = json.loads(json_body)
711
+ else:
712
+ body = {}
713
+ if allow_opt_in_out_enabled is not None:
714
+ body["allowOptInOutEnabled"] = allow_opt_in_out_enabled
715
+ try:
716
+ result = api.session.rest_put(url, json=body)
717
+ except WebexError as e:
718
+ handle_rest_error(e)
719
+ typer.echo(f"Updated.")
720
+
721
+
722
+
723
+ @app.command("list-available-assistants")
724
+ def list_available_assistants(
725
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
726
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
727
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
728
+ debug: bool = typer.Option(False, "--debug"),
729
+ ):
730
+ """Get My Executive Available Assistants."""
731
+ api = get_api(debug=debug)
732
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/executive/availableAssistants"
733
+ params = {}
734
+ if limit > 0:
735
+ params["max"] = limit
736
+ if offset > 0:
737
+ params["start"] = offset
738
+ result = None
739
+ try:
740
+ result = api.session.rest_get(url, params=params)
741
+ except WebexError as e:
742
+ handle_rest_error(e)
743
+ result = result or []
744
+ items = result.get("assistants", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
745
+ if output == "json":
746
+ print_json(items)
747
+ else:
748
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
749
+
750
+
751
+
752
+ @app.command("list-assistant")
753
+ def list_assistant(
754
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
755
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
756
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
757
+ debug: bool = typer.Option(False, "--debug"),
758
+ ):
759
+ """Get My Executive Assistant Settings."""
760
+ api = get_api(debug=debug)
761
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/executive/assistant"
762
+ params = {}
763
+ if limit > 0:
764
+ params["max"] = limit
765
+ if offset > 0:
766
+ params["start"] = offset
767
+ result = None
768
+ try:
769
+ result = api.session.rest_get(url, params=params)
770
+ except WebexError as e:
771
+ handle_rest_error(e)
772
+ result = result or []
773
+ items = result.get("executives", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
774
+ if output == "json":
775
+ print_json(items)
776
+ else:
777
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
778
+
779
+
780
+
781
+ @app.command("update-assistant")
782
+ def update_assistant(
783
+ forward_filtered_calls_enabled: bool = typer.Option(None, "--forward-filtered-calls-enabled/--no-forward-filtered-calls-enabled", help="If `true`, filtered calls to assistant are forwarded to the"),
784
+ forward_to_phone_number: str = typer.Option(None, "--forward-to-phone-number", help="Phone number to forward the filtered calls to. Mandatory if"),
785
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
786
+ debug: bool = typer.Option(False, "--debug"),
787
+ ):
788
+ """Modify My Executive Assistant Settings\n\nExample --json-body:\n '{"forwardFilteredCallsEnabled":true,"forwardToPhoneNumber":"...","executives":[{"personId":"...","optInEnabled":"..."}]}'."""
789
+ api = get_api(debug=debug)
790
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/executive/assistant"
791
+ if json_body:
792
+ body = json.loads(json_body)
793
+ else:
794
+ body = {}
795
+ if forward_filtered_calls_enabled is not None:
796
+ body["forwardFilteredCallsEnabled"] = forward_filtered_calls_enabled
797
+ if forward_to_phone_number is not None:
798
+ body["forwardToPhoneNumber"] = forward_to_phone_number
799
+ try:
800
+ result = api.session.rest_put(url, json=body)
801
+ except WebexError as e:
802
+ handle_rest_error(e)
803
+ typer.echo(f"Updated.")
804
+
805
+
806
+
807
+ @app.command("list-services-settings")
808
+ def list_services_settings(
809
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
810
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
811
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
812
+ debug: bool = typer.Option(False, "--debug"),
813
+ ):
814
+ """Get My Calling Services List."""
815
+ api = get_api(debug=debug)
816
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/services"
817
+ params = {}
818
+ if limit > 0:
819
+ params["max"] = limit
820
+ if offset > 0:
821
+ params["start"] = offset
822
+ result = None
823
+ try:
824
+ result = api.session.rest_get(url, params=params)
825
+ except WebexError as e:
826
+ handle_rest_error(e)
827
+ result = result or []
828
+ items = result.get("services", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
829
+ if output == "json":
830
+ print_json(items)
831
+ else:
832
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
833
+
834
+
835
+
836
+ @app.command("list-services-secondary-lines")
837
+ def list_services_secondary_lines(
838
+ lineowner_id: str = typer.Argument(help="lineownerId"),
839
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
840
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
841
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
842
+ debug: bool = typer.Option(False, "--debug"),
843
+ ):
844
+ """Get My Secondary Line Owner Calling Services List."""
845
+ api = get_api(debug=debug)
846
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/services"
847
+ params = {}
848
+ if limit > 0:
849
+ params["max"] = limit
850
+ if offset > 0:
851
+ params["start"] = offset
852
+ result = None
853
+ try:
854
+ result = api.session.rest_get(url, params=params)
855
+ except WebexError as e:
856
+ handle_rest_error(e)
857
+ result = result or []
858
+ items = result.get("services", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
859
+ if output == "json":
860
+ print_json(items)
861
+ else:
862
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
863
+
864
+
865
+
866
+ @app.command("list-single-number-reach")
867
+ def list_single_number_reach(
868
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
869
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
870
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
871
+ debug: bool = typer.Option(False, "--debug"),
872
+ ):
873
+ """Get User's Single Number Reach Settings."""
874
+ api = get_api(debug=debug)
875
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/singleNumberReach"
876
+ params = {}
877
+ if limit > 0:
878
+ params["max"] = limit
879
+ if offset > 0:
880
+ params["start"] = offset
881
+ result = None
882
+ try:
883
+ result = api.session.rest_get(url, params=params)
884
+ except WebexError as e:
885
+ handle_rest_error(e)
886
+ result = result or []
887
+ items = result.get("numbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
888
+ if output == "json":
889
+ print_json(items)
890
+ else:
891
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
892
+
893
+
894
+
895
+ @app.command("update-single-number-reach")
896
+ def update_single_number_reach(
897
+ alert_all_locations_for_click_to_dial_calls_enabled: bool = typer.Option(None, "--alert-all-locations-for-click-to-dial-calls-enabled/--no-alert-all-locations-for-click-to-dial-calls-enabled", help="If `true`, all locations will be alerted for click-to-dial c"),
898
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
899
+ debug: bool = typer.Option(False, "--debug"),
900
+ ):
901
+ """Modify User's Single Number Reach Settings."""
902
+ api = get_api(debug=debug)
903
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/singleNumberReach"
904
+ if json_body:
905
+ body = json.loads(json_body)
906
+ else:
907
+ body = {}
908
+ if alert_all_locations_for_click_to_dial_calls_enabled is not None:
909
+ body["alertAllLocationsForClickToDialCallsEnabled"] = alert_all_locations_for_click_to_dial_calls_enabled
910
+ try:
911
+ result = api.session.rest_put(url, json=body)
912
+ except WebexError as e:
913
+ handle_rest_error(e)
914
+ typer.echo(f"Updated.")
915
+
916
+
917
+
918
+ @app.command("create")
919
+ def create(
920
+ phone_number: str = typer.Option(None, "--phone-number", help="(required) Phone number."),
921
+ name: str = typer.Option(None, "--name", help="(required) Name associated with the phone number."),
922
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="(required) If `true`, the phone number is enabled."),
923
+ do_not_forward_calls_enabled: bool = typer.Option(None, "--do-not-forward-calls-enabled/--no-do-not-forward-calls-enabled", help="Note that this setting attempts to prevent the Single Number"),
924
+ answer_confirmation_enabled: bool = typer.Option(None, "--answer-confirmation-enabled/--no-answer-confirmation-enabled", help="If `true`, answer confirmation is enabled. The default value"),
925
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
926
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
927
+ debug: bool = typer.Option(False, "--debug"),
928
+ ):
929
+ """Add phone number as User's Single Number Reach."""
930
+ api = get_api(debug=debug)
931
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/singleNumberReach/numbers"
932
+ if json_body:
933
+ body = json.loads(json_body)
934
+ else:
935
+ body = {}
936
+ if phone_number is not None:
937
+ body["phoneNumber"] = phone_number
938
+ if name is not None:
939
+ body["name"] = name
940
+ if enabled is not None:
941
+ body["enabled"] = enabled
942
+ if do_not_forward_calls_enabled is not None:
943
+ body["doNotForwardCallsEnabled"] = do_not_forward_calls_enabled
944
+ if answer_confirmation_enabled is not None:
945
+ body["answerConfirmationEnabled"] = answer_confirmation_enabled
946
+ _missing = [f for f in ['phoneNumber', 'name', 'enabled'] if f not in body or body[f] is None]
947
+ if _missing:
948
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
949
+ raise typer.Exit(1)
950
+ try:
951
+ result = api.session.rest_post(url, json=body)
952
+ except WebexError as e:
953
+ handle_rest_error(e)
954
+ if output == "json":
955
+ print_json(result)
956
+ elif isinstance(result, dict) and "id" in result:
957
+ typer.echo(f"Created: {result['id']}")
958
+ elif not result or result == {}:
959
+ typer.echo("Created.")
960
+ else:
961
+ print_json(result)
962
+
963
+
964
+
965
+ @app.command("update-numbers")
966
+ def update_numbers(
967
+ phone_number_id: str = typer.Argument(help="phoneNumberId"),
968
+ phone_number: str = typer.Option(None, "--phone-number", help="Phone number."),
969
+ name: str = typer.Option(None, "--name", help="Name associated with the phone number."),
970
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="If `true`, the phone number is enabled."),
971
+ do_not_forward_calls_enabled: bool = typer.Option(None, "--do-not-forward-calls-enabled/--no-do-not-forward-calls-enabled", help="If `true`, calls are not forwarded."),
972
+ answer_confirmation_enabled: bool = typer.Option(None, "--answer-confirmation-enabled/--no-answer-confirmation-enabled", help="If `true`, answer confirmation is enabled."),
973
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
974
+ debug: bool = typer.Option(False, "--debug"),
975
+ ):
976
+ """Modify User's Single Number Reach Contact Settings."""
977
+ api = get_api(debug=debug)
978
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/singleNumberReach/numbers/{phone_number_id}"
979
+ if json_body:
980
+ body = json.loads(json_body)
981
+ else:
982
+ body = {}
983
+ if phone_number is not None:
984
+ body["phoneNumber"] = phone_number
985
+ if name is not None:
986
+ body["name"] = name
987
+ if enabled is not None:
988
+ body["enabled"] = enabled
989
+ if do_not_forward_calls_enabled is not None:
990
+ body["doNotForwardCallsEnabled"] = do_not_forward_calls_enabled
991
+ if answer_confirmation_enabled is not None:
992
+ body["answerConfirmationEnabled"] = answer_confirmation_enabled
993
+ try:
994
+ result = api.session.rest_put(url, json=body)
995
+ except WebexError as e:
996
+ handle_rest_error(e)
997
+ typer.echo(f"Updated.")
998
+
999
+
1000
+
1001
+ @app.command("delete")
1002
+ def delete(
1003
+ phone_number_id: str = typer.Argument(help="phoneNumberId"),
1004
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
1005
+ debug: bool = typer.Option(False, "--debug"),
1006
+ ):
1007
+ """Delete User's Single Number Reach Contact Settings."""
1008
+ if not force:
1009
+ typer.confirm(f"Delete {phone_number_id}?", abort=True)
1010
+ api = get_api(debug=debug)
1011
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/singleNumberReach/numbers/{phone_number_id}"
1012
+ try:
1013
+ api.session.rest_delete(url)
1014
+ except WebexError as e:
1015
+ handle_rest_error(e)
1016
+ typer.echo(f"Deleted: {phone_number_id}")
1017
+
1018
+
1019
+
1020
+ @app.command("show-call-forwarding-settings")
1021
+ def show_call_forwarding_settings(
1022
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1023
+ debug: bool = typer.Option(False, "--debug"),
1024
+ ):
1025
+ """Read My Call Forwarding Settings."""
1026
+ api = get_api(debug=debug)
1027
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callForwarding"
1028
+ try:
1029
+ result = api.session.rest_get(url)
1030
+ except WebexError as e:
1031
+ handle_rest_error(e)
1032
+ if output == "json":
1033
+ print_json(result)
1034
+ else:
1035
+ if isinstance(result, dict):
1036
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1037
+ elif isinstance(result, list):
1038
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1039
+ else:
1040
+ print_json(result)
1041
+
1042
+
1043
+
1044
+ @app.command("update-call-forwarding-settings")
1045
+ def update_call_forwarding_settings(
1046
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1047
+ debug: bool = typer.Option(False, "--debug"),
1048
+ ):
1049
+ """Configure My Call Forwarding Settings\n\nExample --json-body:\n '{"callForwarding":{"always":{"enabled":"...","destination":"...","ringReminderEnabled":"...","destinationVoicemailEnabled":"..."},"busy":{"enabled":"...","destination":"...","destinationVoicemailEnabled":"..."},"noAnswer":{"enabled":"...","destination":"...","numberOfRings":"...","destinationVoicemailEnabled":"..."}},"businessContinuity":{"enabled":true,"destination":"...","destinationVoicemailEnabled":true}}'."""
1050
+ api = get_api(debug=debug)
1051
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callForwarding"
1052
+ if json_body:
1053
+ body = json.loads(json_body)
1054
+ else:
1055
+ body = {}
1056
+ try:
1057
+ result = api.session.rest_put(url, json=body)
1058
+ except WebexError as e:
1059
+ handle_rest_error(e)
1060
+ typer.echo(f"Updated.")
1061
+
1062
+
1063
+
1064
+ @app.command("show-call-forwarding-secondary-lines")
1065
+ def show_call_forwarding_secondary_lines(
1066
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1067
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1068
+ debug: bool = typer.Option(False, "--debug"),
1069
+ ):
1070
+ """Get My Secondary Line Owner's Call Forwarding Settings."""
1071
+ api = get_api(debug=debug)
1072
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callForwarding"
1073
+ try:
1074
+ result = api.session.rest_get(url)
1075
+ except WebexError as e:
1076
+ handle_rest_error(e)
1077
+ if output == "json":
1078
+ print_json(result)
1079
+ else:
1080
+ if isinstance(result, dict):
1081
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1082
+ elif isinstance(result, list):
1083
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1084
+ else:
1085
+ print_json(result)
1086
+
1087
+
1088
+
1089
+ @app.command("update-call-forwarding-secondary-lines")
1090
+ def update_call_forwarding_secondary_lines(
1091
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1092
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1093
+ debug: bool = typer.Option(False, "--debug"),
1094
+ ):
1095
+ """Modify My Secondary Line Owner's Call Forwarding Settings\n\nExample --json-body:\n '{"callForwarding":{"always":{"enabled":"...","destination":"...","ringReminderEnabled":"...","destinationVoicemailEnabled":"..."},"busy":{"enabled":"...","destination":"...","destinationVoicemailEnabled":"..."},"noAnswer":{"enabled":"...","destination":"...","numberOfRings":"...","destinationVoicemailEnabled":"..."}},"businessContinuity":{"enabled":true,"destination":"...","destinationVoicemailEnabled":true}}'."""
1096
+ api = get_api(debug=debug)
1097
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callForwarding"
1098
+ if json_body:
1099
+ body = json.loads(json_body)
1100
+ else:
1101
+ body = {}
1102
+ try:
1103
+ result = api.session.rest_put(url, json=body)
1104
+ except WebexError as e:
1105
+ handle_rest_error(e)
1106
+ typer.echo(f"Updated.")
1107
+
1108
+
1109
+
1110
+ @app.command("list-call-pickup-group-settings")
1111
+ def list_call_pickup_group_settings(
1112
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1113
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1114
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1115
+ debug: bool = typer.Option(False, "--debug"),
1116
+ ):
1117
+ """Get My Call Pickup Group Settings."""
1118
+ api = get_api(debug=debug)
1119
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callPickupGroup"
1120
+ params = {}
1121
+ if limit > 0:
1122
+ params["max"] = limit
1123
+ if offset > 0:
1124
+ params["start"] = offset
1125
+ result = None
1126
+ try:
1127
+ result = api.session.rest_get(url, params=params)
1128
+ except WebexError as e:
1129
+ handle_rest_error(e)
1130
+ result = result or []
1131
+ items = result.get("memberList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1132
+ if output == "json":
1133
+ print_json(items)
1134
+ else:
1135
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1136
+
1137
+
1138
+
1139
+ @app.command("list-call-pickup-group-secondary-lines")
1140
+ def list_call_pickup_group_secondary_lines(
1141
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1142
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1143
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1144
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1145
+ debug: bool = typer.Option(False, "--debug"),
1146
+ ):
1147
+ """Get My Secondary Line Owner Call Pickup Group Settings."""
1148
+ api = get_api(debug=debug)
1149
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callPickupGroup"
1150
+ params = {}
1151
+ if limit > 0:
1152
+ params["max"] = limit
1153
+ if offset > 0:
1154
+ params["start"] = offset
1155
+ result = None
1156
+ try:
1157
+ result = api.session.rest_get(url, params=params)
1158
+ except WebexError as e:
1159
+ handle_rest_error(e)
1160
+ result = result or []
1161
+ items = result.get("memberList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1162
+ if output == "json":
1163
+ print_json(items)
1164
+ else:
1165
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1166
+
1167
+
1168
+
1169
+ @app.command("list-call-park-settings")
1170
+ def list_call_park_settings(
1171
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1172
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1173
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1174
+ debug: bool = typer.Option(False, "--debug"),
1175
+ ):
1176
+ """Get My Call Park Settings."""
1177
+ api = get_api(debug=debug)
1178
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callPark"
1179
+ params = {}
1180
+ if limit > 0:
1181
+ params["max"] = limit
1182
+ if offset > 0:
1183
+ params["start"] = offset
1184
+ result = None
1185
+ try:
1186
+ result = api.session.rest_get(url, params=params)
1187
+ except WebexError as e:
1188
+ handle_rest_error(e)
1189
+ result = result or []
1190
+ items = result.get("memberList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1191
+ if output == "json":
1192
+ print_json(items)
1193
+ else:
1194
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1195
+
1196
+
1197
+
1198
+ @app.command("list-call-park-secondary-lines")
1199
+ def list_call_park_secondary_lines(
1200
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1201
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1202
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1203
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1204
+ debug: bool = typer.Option(False, "--debug"),
1205
+ ):
1206
+ """Get My Secondary Line Owner Call Park Settings."""
1207
+ api = get_api(debug=debug)
1208
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/callPark"
1209
+ params = {}
1210
+ if limit > 0:
1211
+ params["max"] = limit
1212
+ if offset > 0:
1213
+ params["start"] = offset
1214
+ result = None
1215
+ try:
1216
+ result = api.session.rest_get(url, params=params)
1217
+ except WebexError as e:
1218
+ handle_rest_error(e)
1219
+ result = result or []
1220
+ items = result.get("memberList", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1221
+ if output == "json":
1222
+ print_json(items)
1223
+ else:
1224
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1225
+
1226
+
1227
+
1228
+ @app.command("show-voicemail-settings")
1229
+ def show_voicemail_settings(
1230
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1231
+ debug: bool = typer.Option(False, "--debug"),
1232
+ ):
1233
+ """Read Voicemail Settings for a Person."""
1234
+ api = get_api(debug=debug)
1235
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/voicemail"
1236
+ try:
1237
+ result = api.session.rest_get(url)
1238
+ except WebexError as e:
1239
+ handle_rest_error(e)
1240
+ if output == "json":
1241
+ print_json(result)
1242
+ else:
1243
+ if isinstance(result, dict):
1244
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1245
+ elif isinstance(result, list):
1246
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1247
+ else:
1248
+ print_json(result)
1249
+
1250
+
1251
+
1252
+ @app.command("update-voicemail-settings")
1253
+ def update_voicemail_settings(
1254
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Voicemail is enabled or disabled."),
1255
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1256
+ debug: bool = typer.Option(False, "--debug"),
1257
+ ):
1258
+ """Configure Voicemail Settings for a Person\n\nExample --json-body:\n '{"notifications":{"enabled":true,"destination":"...","smsDestination":"..."},"transferToNumber":{"enabled":true,"destination":"..."},"enabled":true,"sendAllCalls":{"enabled":true},"sendBusyCalls":{"enabled":true,"greeting":"DEFAULT"},"sendUnansweredCalls":{"enabled":true,"greeting":"DEFAULT","numberOfRings":0},"emailCopyOfMessage":{"enabled":true,"emailId":"..."},"messageStorage":{"mwiEnabled":true,"storageType":"INTERNAL","externalEmail":"..."}}'."""
1259
+ api = get_api(debug=debug)
1260
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/voicemail"
1261
+ if json_body:
1262
+ body = json.loads(json_body)
1263
+ else:
1264
+ body = {}
1265
+ if enabled is not None:
1266
+ body["enabled"] = enabled
1267
+ try:
1268
+ result = api.session.rest_put(url, json=body)
1269
+ except WebexError as e:
1270
+ handle_rest_error(e)
1271
+ typer.echo(f"Updated.")
1272
+
1273
+
1274
+
1275
+ @app.command("show-voicemail-secondary-lines")
1276
+ def show_voicemail_secondary_lines(
1277
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1278
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1279
+ debug: bool = typer.Option(False, "--debug"),
1280
+ ):
1281
+ """Get My Secondary Line Owner's Voicemail Settings."""
1282
+ api = get_api(debug=debug)
1283
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/voicemail"
1284
+ try:
1285
+ result = api.session.rest_get(url)
1286
+ except WebexError as e:
1287
+ handle_rest_error(e)
1288
+ if output == "json":
1289
+ print_json(result)
1290
+ else:
1291
+ if isinstance(result, dict):
1292
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1293
+ elif isinstance(result, list):
1294
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1295
+ else:
1296
+ print_json(result)
1297
+
1298
+
1299
+
1300
+ @app.command("update-voicemail-secondary-lines")
1301
+ def update_voicemail_secondary_lines(
1302
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1303
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Voicemail is enabled or disabled."),
1304
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1305
+ debug: bool = typer.Option(False, "--debug"),
1306
+ ):
1307
+ """Modify My Secondary Line Owner's Voicemail Settings\n\nExample --json-body:\n '{"notifications":{"enabled":true,"destination":"...","smsDestination":"..."},"transferToNumber":{"enabled":true,"destination":"..."},"enabled":true,"sendAllCalls":{"enabled":true},"sendBusyCalls":{"enabled":true,"greeting":"DEFAULT"},"sendUnansweredCalls":{"enabled":true,"greeting":"DEFAULT","numberOfRings":0},"emailCopyOfMessage":{"enabled":true,"emailId":"..."},"messageStorage":{"mwiEnabled":true,"storageType":"INTERNAL","externalEmail":"..."}}'."""
1308
+ api = get_api(debug=debug)
1309
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/voicemail"
1310
+ if json_body:
1311
+ body = json.loads(json_body)
1312
+ else:
1313
+ body = {}
1314
+ if enabled is not None:
1315
+ body["enabled"] = enabled
1316
+ try:
1317
+ result = api.session.rest_put(url, json=body)
1318
+ except WebexError as e:
1319
+ handle_rest_error(e)
1320
+ typer.echo(f"Updated.")
1321
+
1322
+
1323
+
1324
+ @app.command("list-call-block")
1325
+ def list_call_block(
1326
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1327
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1328
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1329
+ debug: bool = typer.Option(False, "--debug"),
1330
+ ):
1331
+ """Get My Call Block Settings."""
1332
+ api = get_api(debug=debug)
1333
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callBlock"
1334
+ params = {}
1335
+ if limit > 0:
1336
+ params["max"] = limit
1337
+ if offset > 0:
1338
+ params["start"] = offset
1339
+ result = None
1340
+ try:
1341
+ result = api.session.rest_get(url, params=params)
1342
+ except WebexError as e:
1343
+ handle_rest_error(e)
1344
+ result = result or []
1345
+ items = result.get("numbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1346
+ if output == "json":
1347
+ print_json(items)
1348
+ else:
1349
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1350
+
1351
+
1352
+
1353
+ @app.command("create-numbers")
1354
+ def create_numbers(
1355
+ phone_number: str = typer.Option(None, "--phone-number", help="(required) Phone number which is blocked by user."),
1356
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1357
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1358
+ debug: bool = typer.Option(False, "--debug"),
1359
+ ):
1360
+ """Add a phone number to user's Call Block List."""
1361
+ api = get_api(debug=debug)
1362
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callBlock/numbers"
1363
+ if json_body:
1364
+ body = json.loads(json_body)
1365
+ else:
1366
+ body = {}
1367
+ if phone_number is not None:
1368
+ body["phoneNumber"] = phone_number
1369
+ _missing = [f for f in ['phoneNumber'] if f not in body or body[f] is None]
1370
+ if _missing:
1371
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1372
+ raise typer.Exit(1)
1373
+ try:
1374
+ result = api.session.rest_post(url, json=body)
1375
+ except WebexError as e:
1376
+ handle_rest_error(e)
1377
+ if output == "json":
1378
+ print_json(result)
1379
+ elif isinstance(result, dict) and "id" in result:
1380
+ typer.echo(f"Created: {result['id']}")
1381
+ elif not result or result == {}:
1382
+ typer.echo("Created.")
1383
+ else:
1384
+ print_json(result)
1385
+
1386
+
1387
+
1388
+ @app.command("show-numbers")
1389
+ def show_numbers(
1390
+ phone_number_id: str = typer.Argument(help="phoneNumberId"),
1391
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1392
+ debug: bool = typer.Option(False, "--debug"),
1393
+ ):
1394
+ """Get My Call Block State For Specific Number."""
1395
+ api = get_api(debug=debug)
1396
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callBlock/numbers/{phone_number_id}"
1397
+ try:
1398
+ result = api.session.rest_get(url)
1399
+ except WebexError as e:
1400
+ handle_rest_error(e)
1401
+ if output == "json":
1402
+ print_json(result)
1403
+ else:
1404
+ if isinstance(result, dict):
1405
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1406
+ elif isinstance(result, list):
1407
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1408
+ else:
1409
+ print_json(result)
1410
+
1411
+
1412
+
1413
+ @app.command("delete-numbers")
1414
+ def delete_numbers(
1415
+ phone_number_id: str = typer.Argument(help="phoneNumberId"),
1416
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
1417
+ debug: bool = typer.Option(False, "--debug"),
1418
+ ):
1419
+ """Delete User Call Block Number."""
1420
+ if not force:
1421
+ typer.confirm(f"Delete {phone_number_id}?", abort=True)
1422
+ api = get_api(debug=debug)
1423
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callBlock/numbers/{phone_number_id}"
1424
+ try:
1425
+ api.session.rest_delete(url)
1426
+ except WebexError as e:
1427
+ handle_rest_error(e)
1428
+ typer.echo(f"Deleted: {phone_number_id}")
1429
+
1430
+
1431
+
1432
+ @app.command("list-monitoring")
1433
+ def list_monitoring(
1434
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1435
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1436
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1437
+ debug: bool = typer.Option(False, "--debug"),
1438
+ ):
1439
+ """Get My Monitoring Settings."""
1440
+ api = get_api(debug=debug)
1441
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/monitoring"
1442
+ params = {}
1443
+ if limit > 0:
1444
+ params["max"] = limit
1445
+ if offset > 0:
1446
+ params["start"] = offset
1447
+ result = None
1448
+ try:
1449
+ result = api.session.rest_get(url, params=params)
1450
+ except WebexError as e:
1451
+ handle_rest_error(e)
1452
+ result = result or []
1453
+ items = result.get("monitoredElements", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1454
+ if output == "json":
1455
+ print_json(items)
1456
+ else:
1457
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1458
+
1459
+
1460
+
1461
+ @app.command("list-queues-settings")
1462
+ def list_queues_settings(
1463
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1464
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1465
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1466
+ debug: bool = typer.Option(False, "--debug"),
1467
+ ):
1468
+ """Get My Call Center Settings."""
1469
+ api = get_api(debug=debug)
1470
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/queues"
1471
+ params = {}
1472
+ if limit > 0:
1473
+ params["max"] = limit
1474
+ if offset > 0:
1475
+ params["start"] = offset
1476
+ result = None
1477
+ try:
1478
+ result = api.session.rest_get(url, params=params)
1479
+ except WebexError as e:
1480
+ handle_rest_error(e)
1481
+ result = result or []
1482
+ items = result.get("queues", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1483
+ if output == "json":
1484
+ print_json(items)
1485
+ else:
1486
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1487
+
1488
+
1489
+
1490
+ @app.command("update-queues-settings")
1491
+ def update_queues_settings(
1492
+ agent_acd_state: str = typer.Option(None, "--agent-acd-state", help="Choices: SIGN_IN, SIGN_OUT, AVAILABLE, UNAVAILABLE, WRAP_UP"),
1493
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1494
+ debug: bool = typer.Option(False, "--debug"),
1495
+ ):
1496
+ """Modify My Call Center Settings\n\nExample --json-body:\n '{"agentACDState":"SIGN_IN","queues":[{"id":"...","available":"..."}]}'."""
1497
+ api = get_api(debug=debug)
1498
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/queues"
1499
+ if json_body:
1500
+ body = json.loads(json_body)
1501
+ else:
1502
+ body = {}
1503
+ if agent_acd_state is not None:
1504
+ body["agentACDState"] = agent_acd_state
1505
+ try:
1506
+ result = api.session.rest_put(url, json=body)
1507
+ except WebexError as e:
1508
+ handle_rest_error(e)
1509
+ typer.echo(f"Updated.")
1510
+
1511
+
1512
+
1513
+ @app.command("list-queues-secondary-lines")
1514
+ def list_queues_secondary_lines(
1515
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1516
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1517
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1518
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1519
+ debug: bool = typer.Option(False, "--debug"),
1520
+ ):
1521
+ """Get My Secondary Line Owner's Call Center Settings."""
1522
+ api = get_api(debug=debug)
1523
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/queues"
1524
+ params = {}
1525
+ if limit > 0:
1526
+ params["max"] = limit
1527
+ if offset > 0:
1528
+ params["start"] = offset
1529
+ result = None
1530
+ try:
1531
+ result = api.session.rest_get(url, params=params)
1532
+ except WebexError as e:
1533
+ handle_rest_error(e)
1534
+ result = result or []
1535
+ items = result.get("queues", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1536
+ if output == "json":
1537
+ print_json(items)
1538
+ else:
1539
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1540
+
1541
+
1542
+
1543
+ @app.command("update-queues-secondary-lines")
1544
+ def update_queues_secondary_lines(
1545
+ lineowner_id: str = typer.Argument(help="lineownerId"),
1546
+ agent_acd_state: str = typer.Option(None, "--agent-acd-state", help="Choices: SIGN_IN, SIGN_OUT, AVAILABLE, UNAVAILABLE, WRAP_UP"),
1547
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1548
+ debug: bool = typer.Option(False, "--debug"),
1549
+ ):
1550
+ """Modify My Secondary Line Owner's Call Center Settings\n\nExample --json-body:\n '{"agentACDState":"SIGN_IN","queues":[{"id":"...","available":"..."}]}'."""
1551
+ api = get_api(debug=debug)
1552
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/secondaryLines/{lineowner_id}/queues"
1553
+ if json_body:
1554
+ body = json.loads(json_body)
1555
+ else:
1556
+ body = {}
1557
+ if agent_acd_state is not None:
1558
+ body["agentACDState"] = agent_acd_state
1559
+ try:
1560
+ result = api.session.rest_put(url, json=body)
1561
+ except WebexError as e:
1562
+ handle_rest_error(e)
1563
+ typer.echo(f"Updated.")
1564
+
1565
+
1566
+
1567
+ @app.command("show-call-captions")
1568
+ def show_call_captions(
1569
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1570
+ debug: bool = typer.Option(False, "--debug"),
1571
+ ):
1572
+ """Get my call captions settings."""
1573
+ api = get_api(debug=debug)
1574
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callCaptions"
1575
+ try:
1576
+ result = api.session.rest_get(url)
1577
+ except WebexError as e:
1578
+ handle_rest_error(e)
1579
+ if output == "json":
1580
+ print_json(result)
1581
+ else:
1582
+ if isinstance(result, dict):
1583
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1584
+ elif isinstance(result, list):
1585
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1586
+ else:
1587
+ print_json(result)
1588
+
1589
+
1590
+
1591
+ @app.command("list-priority-alert")
1592
+ def list_priority_alert(
1593
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1594
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1595
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1596
+ debug: bool = typer.Option(False, "--debug"),
1597
+ ):
1598
+ """Get Priority Alert Settings."""
1599
+ api = get_api(debug=debug)
1600
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert"
1601
+ params = {}
1602
+ if limit > 0:
1603
+ params["max"] = limit
1604
+ if offset > 0:
1605
+ params["start"] = offset
1606
+ result = None
1607
+ try:
1608
+ result = api.session.rest_get(url, params=params)
1609
+ except WebexError as e:
1610
+ handle_rest_error(e)
1611
+ result = result or []
1612
+ items = result.get("criteria", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1613
+ if output == "json":
1614
+ print_json(items)
1615
+ else:
1616
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1617
+
1618
+
1619
+
1620
+ @app.command("update-priority-alert")
1621
+ def update_priority_alert(
1622
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="`true` if the Priority Alert feature is enabled."),
1623
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1624
+ debug: bool = typer.Option(False, "--debug"),
1625
+ ):
1626
+ """Modify Priority Alert Settings for User."""
1627
+ api = get_api(debug=debug)
1628
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert"
1629
+ if json_body:
1630
+ body = json.loads(json_body)
1631
+ else:
1632
+ body = {}
1633
+ if enabled is not None:
1634
+ body["enabled"] = enabled
1635
+ try:
1636
+ result = api.session.rest_put(url, json=body)
1637
+ except WebexError as e:
1638
+ handle_rest_error(e)
1639
+ typer.echo(f"Updated.")
1640
+
1641
+
1642
+
1643
+ @app.command("create-criteria-priority-alert")
1644
+ def create_criteria_priority_alert(
1645
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
1646
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
1647
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
1648
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
1649
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
1650
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
1651
+ notification_enabled: bool = typer.Option(None, "--notification-enabled/--no-notification-enabled", help="Determines whether priority alerting is applied for calls ma"),
1652
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1653
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1654
+ debug: bool = typer.Option(False, "--debug"),
1655
+ ):
1656
+ """Add a Priority Alert Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"notificationEnabled":true}'."""
1657
+ api = get_api(debug=debug)
1658
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert/criteria"
1659
+ if json_body:
1660
+ body = json.loads(json_body)
1661
+ else:
1662
+ body = {}
1663
+ if schedule_name is not None:
1664
+ body["scheduleName"] = schedule_name
1665
+ if schedule_type is not None:
1666
+ body["scheduleType"] = schedule_type
1667
+ if schedule_level is not None:
1668
+ body["scheduleLevel"] = schedule_level
1669
+ if calls_from is not None:
1670
+ body["callsFrom"] = calls_from
1671
+ if anonymous_callers_enabled is not None:
1672
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
1673
+ if unavailable_callers_enabled is not None:
1674
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
1675
+ if notification_enabled is not None:
1676
+ body["notificationEnabled"] = notification_enabled
1677
+ try:
1678
+ result = api.session.rest_post(url, json=body)
1679
+ except WebexError as e:
1680
+ handle_rest_error(e)
1681
+ if output == "json":
1682
+ print_json(result)
1683
+ elif isinstance(result, dict) and "id" in result:
1684
+ typer.echo(f"Created: {result['id']}")
1685
+ elif not result or result == {}:
1686
+ typer.echo("Created.")
1687
+ else:
1688
+ print_json(result)
1689
+
1690
+
1691
+
1692
+ @app.command("show-criteria-priority-alert")
1693
+ def show_criteria_priority_alert(
1694
+ id: str = typer.Argument(help="id"),
1695
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1696
+ debug: bool = typer.Option(False, "--debug"),
1697
+ ):
1698
+ """Get Priority Alert Criteria Settings."""
1699
+ api = get_api(debug=debug)
1700
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert/criteria/{id}"
1701
+ try:
1702
+ result = api.session.rest_get(url)
1703
+ except WebexError as e:
1704
+ handle_rest_error(e)
1705
+ if output == "json":
1706
+ print_json(result)
1707
+ else:
1708
+ if isinstance(result, dict):
1709
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1710
+ elif isinstance(result, list):
1711
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1712
+ else:
1713
+ print_json(result)
1714
+
1715
+
1716
+
1717
+ @app.command("update-criteria-priority-alert")
1718
+ def update_criteria_priority_alert(
1719
+ id: str = typer.Argument(help="id"),
1720
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
1721
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
1722
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
1723
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
1724
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
1725
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
1726
+ notification_enabled: bool = typer.Option(None, "--notification-enabled/--no-notification-enabled", help="Determines whether priority alerting is applied for calls ma"),
1727
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1728
+ debug: bool = typer.Option(False, "--debug"),
1729
+ ):
1730
+ """Modify Settings for a Priority Alert Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"notificationEnabled":true}'."""
1731
+ api = get_api(debug=debug)
1732
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert/criteria/{id}"
1733
+ if json_body:
1734
+ body = json.loads(json_body)
1735
+ else:
1736
+ body = {}
1737
+ if schedule_name is not None:
1738
+ body["scheduleName"] = schedule_name
1739
+ if schedule_type is not None:
1740
+ body["scheduleType"] = schedule_type
1741
+ if schedule_level is not None:
1742
+ body["scheduleLevel"] = schedule_level
1743
+ if calls_from is not None:
1744
+ body["callsFrom"] = calls_from
1745
+ if anonymous_callers_enabled is not None:
1746
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
1747
+ if unavailable_callers_enabled is not None:
1748
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
1749
+ if notification_enabled is not None:
1750
+ body["notificationEnabled"] = notification_enabled
1751
+ try:
1752
+ result = api.session.rest_put(url, json=body)
1753
+ except WebexError as e:
1754
+ handle_rest_error(e)
1755
+ typer.echo(f"Updated.")
1756
+
1757
+
1758
+
1759
+ @app.command("delete-criteria-priority-alert")
1760
+ def delete_criteria_priority_alert(
1761
+ id: str = typer.Argument(help="id"),
1762
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
1763
+ debug: bool = typer.Option(False, "--debug"),
1764
+ ):
1765
+ """Delete a Priority Alert Criteria."""
1766
+ if not force:
1767
+ typer.confirm(f"Delete {id}?", abort=True)
1768
+ api = get_api(debug=debug)
1769
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/priorityAlert/criteria/{id}"
1770
+ try:
1771
+ api.session.rest_delete(url)
1772
+ except WebexError as e:
1773
+ handle_rest_error(e)
1774
+ typer.echo(f"Deleted: {id}")
1775
+
1776
+
1777
+
1778
+ @app.command("list-schedules")
1779
+ def list_schedules(
1780
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
1781
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
1782
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
1783
+ debug: bool = typer.Option(False, "--debug"),
1784
+ ):
1785
+ """Get User (and Location) Schedules."""
1786
+ api = get_api(debug=debug)
1787
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules"
1788
+ params = {}
1789
+ if limit > 0:
1790
+ params["max"] = limit
1791
+ if offset > 0:
1792
+ params["start"] = offset
1793
+ result = None
1794
+ try:
1795
+ result = api.session.rest_get(url, params=params)
1796
+ except WebexError as e:
1797
+ handle_rest_error(e)
1798
+ result = result or []
1799
+ items = result.get("schedules", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
1800
+ if output == "json":
1801
+ print_json(items)
1802
+ else:
1803
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
1804
+
1805
+
1806
+
1807
+ @app.command("create-schedules")
1808
+ def create_schedules(
1809
+ type_param: str = typer.Option(None, "--type", help="(required) Choices: businessHours, holidays"),
1810
+ name: str = typer.Option(None, "--name", help="(required) Unique name for the schedule."),
1811
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1812
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1813
+ debug: bool = typer.Option(False, "--debug"),
1814
+ ):
1815
+ """Add a User level Schedule for Call Settings\n\nExample --json-body:\n '{"type":"businessHours","name":"...","events":[{"name":"...","startDate":"...","endDate":"...","startTime":"...","endTime":"...","allDayEnabled":"...","recurrence":"..."}]}'."""
1816
+ api = get_api(debug=debug)
1817
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules"
1818
+ if json_body:
1819
+ body = json.loads(json_body)
1820
+ else:
1821
+ body = {}
1822
+ if type_param is not None:
1823
+ body["type"] = type_param
1824
+ if name is not None:
1825
+ body["name"] = name
1826
+ _missing = [f for f in ['type', 'name'] if f not in body or body[f] is None]
1827
+ if _missing:
1828
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1829
+ raise typer.Exit(1)
1830
+ try:
1831
+ result = api.session.rest_post(url, json=body)
1832
+ except WebexError as e:
1833
+ handle_rest_error(e)
1834
+ if output == "json":
1835
+ print_json(result)
1836
+ elif isinstance(result, dict) and "id" in result:
1837
+ typer.echo(f"Created: {result['id']}")
1838
+ elif not result or result == {}:
1839
+ typer.echo("Created.")
1840
+ else:
1841
+ print_json(result)
1842
+
1843
+
1844
+
1845
+ @app.command("show-schedules-me")
1846
+ def show_schedules_me(
1847
+ schedule_type: str = typer.Argument(help="scheduleType"),
1848
+ schedule_id: str = typer.Argument(help="scheduleId"),
1849
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1850
+ debug: bool = typer.Option(False, "--debug"),
1851
+ ):
1852
+ """Get User Schedule."""
1853
+ api = get_api(debug=debug)
1854
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}"
1855
+ try:
1856
+ result = api.session.rest_get(url)
1857
+ except WebexError as e:
1858
+ handle_rest_error(e)
1859
+ if output == "json":
1860
+ print_json(result)
1861
+ else:
1862
+ if isinstance(result, dict):
1863
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1864
+ elif isinstance(result, list):
1865
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1866
+ else:
1867
+ print_json(result)
1868
+
1869
+
1870
+
1871
+ @app.command("update-schedules")
1872
+ def update_schedules(
1873
+ schedule_type: str = typer.Argument(help="scheduleType"),
1874
+ schedule_id: str = typer.Argument(help="scheduleId"),
1875
+ name: str = typer.Option(None, "--name", help="Name of the schedule."),
1876
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1877
+ debug: bool = typer.Option(False, "--debug"),
1878
+ ):
1879
+ """Modify User Schedule\n\nExample --json-body:\n '{"name":"...","events":[{"name":"...","startDate":"...","endDate":"...","allDayEnabled":"...","newName":"...","startTime":"...","endTime":"...","recurrence":"..."}]}'."""
1880
+ api = get_api(debug=debug)
1881
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}"
1882
+ if json_body:
1883
+ body = json.loads(json_body)
1884
+ else:
1885
+ body = {}
1886
+ if name is not None:
1887
+ body["name"] = name
1888
+ try:
1889
+ result = api.session.rest_put(url, json=body)
1890
+ except WebexError as e:
1891
+ handle_rest_error(e)
1892
+ typer.echo(f"Updated.")
1893
+
1894
+
1895
+
1896
+ @app.command("delete-schedules")
1897
+ def delete_schedules(
1898
+ schedule_type: str = typer.Argument(help="scheduleType"),
1899
+ schedule_id: str = typer.Argument(help="scheduleId"),
1900
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
1901
+ debug: bool = typer.Option(False, "--debug"),
1902
+ ):
1903
+ """Delete a User Schedule."""
1904
+ if not force:
1905
+ typer.confirm(f"Delete {schedule_id}?", abort=True)
1906
+ api = get_api(debug=debug)
1907
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}"
1908
+ try:
1909
+ api.session.rest_delete(url)
1910
+ except WebexError as e:
1911
+ handle_rest_error(e)
1912
+ typer.echo(f"Deleted: {schedule_id}")
1913
+
1914
+
1915
+
1916
+ @app.command("create-events")
1917
+ def create_events(
1918
+ schedule_type: str = typer.Argument(help="scheduleType"),
1919
+ schedule_id: str = typer.Argument(help="scheduleId"),
1920
+ name: str = typer.Option(None, "--name", help="(required) Name for the event."),
1921
+ start_date: str = typer.Option(None, "--start-date", help="(required) Start Date of Event."),
1922
+ end_date: str = typer.Option(None, "--end-date", help="(required) End Date of Event."),
1923
+ start_time: str = typer.Option(None, "--start-time", help="Start time of event."),
1924
+ end_time: str = typer.Option(None, "--end-time", help="End time of event."),
1925
+ all_day_enabled: bool = typer.Option(None, "--all-day-enabled/--no-all-day-enabled", help="(required) An indication of whether given event is an all-day event or"),
1926
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
1927
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
1928
+ debug: bool = typer.Option(False, "--debug"),
1929
+ ):
1930
+ """Add an event for a User Schedule\n\nExample --json-body:\n '{"name":"...","startDate":"...","endDate":"...","allDayEnabled":true,"startTime":"...","endTime":"...","recurrence":{"recurForEver":true,"recurEndDate":"...","recurEndOccurrence":0,"recurDaily":{"recurInterval":"..."},"recurWeekly":{"sunday":"...","monday":"...","tuesday":"...","wednesday":"...","thursday":"...","friday":"...","saturday":"..."}}}'."""
1931
+ api = get_api(debug=debug)
1932
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}/events"
1933
+ if json_body:
1934
+ body = json.loads(json_body)
1935
+ else:
1936
+ body = {}
1937
+ if name is not None:
1938
+ body["name"] = name
1939
+ if start_date is not None:
1940
+ body["startDate"] = start_date
1941
+ if end_date is not None:
1942
+ body["endDate"] = end_date
1943
+ if start_time is not None:
1944
+ body["startTime"] = start_time
1945
+ if end_time is not None:
1946
+ body["endTime"] = end_time
1947
+ if all_day_enabled is not None:
1948
+ body["allDayEnabled"] = all_day_enabled
1949
+ _missing = [f for f in ['name', 'startDate', 'endDate', 'allDayEnabled'] if f not in body or body[f] is None]
1950
+ if _missing:
1951
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
1952
+ raise typer.Exit(1)
1953
+ try:
1954
+ result = api.session.rest_post(url, json=body)
1955
+ except WebexError as e:
1956
+ handle_rest_error(e)
1957
+ if output == "json":
1958
+ print_json(result)
1959
+ elif isinstance(result, dict) and "id" in result:
1960
+ typer.echo(f"Created: {result['id']}")
1961
+ elif not result or result == {}:
1962
+ typer.echo("Created.")
1963
+ else:
1964
+ print_json(result)
1965
+
1966
+
1967
+
1968
+ @app.command("show-events")
1969
+ def show_events(
1970
+ schedule_type: str = typer.Argument(help="scheduleType"),
1971
+ schedule_id: str = typer.Argument(help="scheduleId"),
1972
+ event_id: str = typer.Argument(help="eventId"),
1973
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
1974
+ debug: bool = typer.Option(False, "--debug"),
1975
+ ):
1976
+ """Get User Schedule Event."""
1977
+ api = get_api(debug=debug)
1978
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}/events/{event_id}"
1979
+ try:
1980
+ result = api.session.rest_get(url)
1981
+ except WebexError as e:
1982
+ handle_rest_error(e)
1983
+ if output == "json":
1984
+ print_json(result)
1985
+ else:
1986
+ if isinstance(result, dict):
1987
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
1988
+ elif isinstance(result, list):
1989
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
1990
+ else:
1991
+ print_json(result)
1992
+
1993
+
1994
+
1995
+ @app.command("update-events")
1996
+ def update_events(
1997
+ schedule_type: str = typer.Argument(help="scheduleType"),
1998
+ schedule_id: str = typer.Argument(help="scheduleId"),
1999
+ event_id: str = typer.Argument(help="eventId"),
2000
+ name: str = typer.Option(None, "--name", help="Name for the event."),
2001
+ new_name: str = typer.Option(None, "--new-name", help="New Name for the event."),
2002
+ start_date: str = typer.Option(None, "--start-date", help="Start Date of Event."),
2003
+ end_date: str = typer.Option(None, "--end-date", help="End Date of Event."),
2004
+ start_time: str = typer.Option(None, "--start-time", help="Start time of event."),
2005
+ end_time: str = typer.Option(None, "--end-time", help="End time of event."),
2006
+ all_day_enabled: bool = typer.Option(None, "--all-day-enabled/--no-all-day-enabled", help="An indication of whether given event is an all-day event or"),
2007
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2008
+ debug: bool = typer.Option(False, "--debug"),
2009
+ ):
2010
+ """Modify User Schedule Event\n\nExample --json-body:\n '{"name":"...","startDate":"...","endDate":"...","allDayEnabled":true,"newName":"...","startTime":"...","endTime":"...","recurrence":{"recurForEver":true,"recurEndDate":"...","recurEndOccurrence":0,"recurDaily":{"recurInterval":"..."},"recurWeekly":{"sunday":"...","monday":"...","tuesday":"...","wednesday":"...","thursday":"...","friday":"...","saturday":"..."}}}'."""
2011
+ api = get_api(debug=debug)
2012
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}/events/{event_id}"
2013
+ if json_body:
2014
+ body = json.loads(json_body)
2015
+ else:
2016
+ body = {}
2017
+ if name is not None:
2018
+ body["name"] = name
2019
+ if new_name is not None:
2020
+ body["newName"] = new_name
2021
+ if start_date is not None:
2022
+ body["startDate"] = start_date
2023
+ if end_date is not None:
2024
+ body["endDate"] = end_date
2025
+ if start_time is not None:
2026
+ body["startTime"] = start_time
2027
+ if end_time is not None:
2028
+ body["endTime"] = end_time
2029
+ if all_day_enabled is not None:
2030
+ body["allDayEnabled"] = all_day_enabled
2031
+ try:
2032
+ result = api.session.rest_put(url, json=body)
2033
+ except WebexError as e:
2034
+ handle_rest_error(e)
2035
+ typer.echo(f"Updated.")
2036
+
2037
+
2038
+
2039
+ @app.command("delete-events")
2040
+ def delete_events(
2041
+ schedule_type: str = typer.Argument(help="scheduleType"),
2042
+ schedule_id: str = typer.Argument(help="scheduleId"),
2043
+ event_id: str = typer.Argument(help="eventId"),
2044
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
2045
+ debug: bool = typer.Option(False, "--debug"),
2046
+ ):
2047
+ """Delete User a Schedule Event."""
2048
+ if not force:
2049
+ typer.confirm(f"Delete {event_id}?", abort=True)
2050
+ api = get_api(debug=debug)
2051
+ url = f"https://webexapis.com/v1/telephony/config/people/me/schedules/{schedule_type}/{schedule_id}/events/{event_id}"
2052
+ try:
2053
+ api.session.rest_delete(url)
2054
+ except WebexError as e:
2055
+ handle_rest_error(e)
2056
+ typer.echo(f"Deleted: {event_id}")
2057
+
2058
+
2059
+
2060
+ @app.command("show-schedules-locations")
2061
+ def show_schedules_locations(
2062
+ schedule_type: str = typer.Argument(help="scheduleType"),
2063
+ schedule_id: str = typer.Argument(help="scheduleId"),
2064
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2065
+ debug: bool = typer.Option(False, "--debug"),
2066
+ ):
2067
+ """Get User's Location Level Schedule."""
2068
+ api = get_api(debug=debug)
2069
+ url = f"https://webexapis.com/v1/telephony/config/people/me/locations/schedules/{schedule_type}/{schedule_id}"
2070
+ try:
2071
+ result = api.session.rest_get(url)
2072
+ except WebexError as e:
2073
+ handle_rest_error(e)
2074
+ if output == "json":
2075
+ print_json(result)
2076
+ else:
2077
+ if isinstance(result, dict):
2078
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2079
+ elif isinstance(result, list):
2080
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2081
+ else:
2082
+ print_json(result)
2083
+
2084
+
2085
+
2086
+ @app.command("list-call-notify")
2087
+ def list_call_notify(
2088
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
2089
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
2090
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
2091
+ debug: bool = typer.Option(False, "--debug"),
2092
+ ):
2093
+ """Get Call Notify Settings for User."""
2094
+ api = get_api(debug=debug)
2095
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify"
2096
+ params = {}
2097
+ if limit > 0:
2098
+ params["max"] = limit
2099
+ if offset > 0:
2100
+ params["start"] = offset
2101
+ result = None
2102
+ try:
2103
+ result = api.session.rest_get(url, params=params)
2104
+ except WebexError as e:
2105
+ handle_rest_error(e)
2106
+ result = result or []
2107
+ items = result.get("criteria", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
2108
+ if output == "json":
2109
+ print_json(items)
2110
+ else:
2111
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
2112
+
2113
+
2114
+
2115
+ @app.command("update-call-notify")
2116
+ def update_call_notify(
2117
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Indicates whether the call notify feature should be enabled"),
2118
+ email_address: str = typer.Option(None, "--email-address", help="Email Address to which call notifications to be received."),
2119
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2120
+ debug: bool = typer.Option(False, "--debug"),
2121
+ ):
2122
+ """Modify Call Notify Settings for User."""
2123
+ api = get_api(debug=debug)
2124
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify"
2125
+ if json_body:
2126
+ body = json.loads(json_body)
2127
+ else:
2128
+ body = {}
2129
+ if enabled is not None:
2130
+ body["enabled"] = enabled
2131
+ if email_address is not None:
2132
+ body["emailAddress"] = email_address
2133
+ try:
2134
+ result = api.session.rest_put(url, json=body)
2135
+ except WebexError as e:
2136
+ handle_rest_error(e)
2137
+ typer.echo(f"Updated.")
2138
+
2139
+
2140
+
2141
+ @app.command("create-criteria-call-notify")
2142
+ def create_criteria_call_notify(
2143
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
2144
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2145
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
2146
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
2147
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
2148
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
2149
+ notification_enabled: bool = typer.Option(None, "--notification-enabled/--no-notification-enabled", help="Determines whether call notification is applied for calls ma"),
2150
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2151
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
2152
+ debug: bool = typer.Option(False, "--debug"),
2153
+ ):
2154
+ """Add a Call Notify Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"notificationEnabled":true}'."""
2155
+ api = get_api(debug=debug)
2156
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify/criteria"
2157
+ if json_body:
2158
+ body = json.loads(json_body)
2159
+ else:
2160
+ body = {}
2161
+ if schedule_name is not None:
2162
+ body["scheduleName"] = schedule_name
2163
+ if schedule_type is not None:
2164
+ body["scheduleType"] = schedule_type
2165
+ if schedule_level is not None:
2166
+ body["scheduleLevel"] = schedule_level
2167
+ if calls_from is not None:
2168
+ body["callsFrom"] = calls_from
2169
+ if anonymous_callers_enabled is not None:
2170
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2171
+ if unavailable_callers_enabled is not None:
2172
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2173
+ if notification_enabled is not None:
2174
+ body["notificationEnabled"] = notification_enabled
2175
+ try:
2176
+ result = api.session.rest_post(url, json=body)
2177
+ except WebexError as e:
2178
+ handle_rest_error(e)
2179
+ if output == "json":
2180
+ print_json(result)
2181
+ elif isinstance(result, dict) and "id" in result:
2182
+ typer.echo(f"Created: {result['id']}")
2183
+ elif not result or result == {}:
2184
+ typer.echo("Created.")
2185
+ else:
2186
+ print_json(result)
2187
+
2188
+
2189
+
2190
+ @app.command("show-criteria-call-notify")
2191
+ def show_criteria_call_notify(
2192
+ id: str = typer.Argument(help="id"),
2193
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2194
+ debug: bool = typer.Option(False, "--debug"),
2195
+ ):
2196
+ """Get Call Notify Criteria Settings."""
2197
+ api = get_api(debug=debug)
2198
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify/criteria/{id}"
2199
+ try:
2200
+ result = api.session.rest_get(url)
2201
+ except WebexError as e:
2202
+ handle_rest_error(e)
2203
+ if output == "json":
2204
+ print_json(result)
2205
+ else:
2206
+ if isinstance(result, dict):
2207
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2208
+ elif isinstance(result, list):
2209
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2210
+ else:
2211
+ print_json(result)
2212
+
2213
+
2214
+
2215
+ @app.command("update-criteria-call-notify")
2216
+ def update_criteria_call_notify(
2217
+ id: str = typer.Argument(help="id"),
2218
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
2219
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2220
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
2221
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
2222
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
2223
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
2224
+ notification_enabled: bool = typer.Option(None, "--notification-enabled/--no-notification-enabled", help="Determines whether call notification is applied for calls ma"),
2225
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2226
+ debug: bool = typer.Option(False, "--debug"),
2227
+ ):
2228
+ """Modify a Call Notify Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"notificationEnabled":true}'."""
2229
+ api = get_api(debug=debug)
2230
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify/criteria/{id}"
2231
+ if json_body:
2232
+ body = json.loads(json_body)
2233
+ else:
2234
+ body = {}
2235
+ if schedule_name is not None:
2236
+ body["scheduleName"] = schedule_name
2237
+ if schedule_type is not None:
2238
+ body["scheduleType"] = schedule_type
2239
+ if schedule_level is not None:
2240
+ body["scheduleLevel"] = schedule_level
2241
+ if calls_from is not None:
2242
+ body["callsFrom"] = calls_from
2243
+ if anonymous_callers_enabled is not None:
2244
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2245
+ if unavailable_callers_enabled is not None:
2246
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2247
+ if notification_enabled is not None:
2248
+ body["notificationEnabled"] = notification_enabled
2249
+ try:
2250
+ result = api.session.rest_put(url, json=body)
2251
+ except WebexError as e:
2252
+ handle_rest_error(e)
2253
+ typer.echo(f"Updated.")
2254
+
2255
+
2256
+
2257
+ @app.command("delete-criteria-call-notify")
2258
+ def delete_criteria_call_notify(
2259
+ id: str = typer.Argument(help="id"),
2260
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
2261
+ debug: bool = typer.Option(False, "--debug"),
2262
+ ):
2263
+ """Delete a Call Notify Criteria."""
2264
+ if not force:
2265
+ typer.confirm(f"Delete {id}?", abort=True)
2266
+ api = get_api(debug=debug)
2267
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callNotify/criteria/{id}"
2268
+ try:
2269
+ api.session.rest_delete(url)
2270
+ except WebexError as e:
2271
+ handle_rest_error(e)
2272
+ typer.echo(f"Deleted: {id}")
2273
+
2274
+
2275
+
2276
+ @app.command("list-selective-accept")
2277
+ def list_selective_accept(
2278
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
2279
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
2280
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
2281
+ debug: bool = typer.Option(False, "--debug"),
2282
+ ):
2283
+ """Get Selective Call Accept Settings for User."""
2284
+ api = get_api(debug=debug)
2285
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept"
2286
+ params = {}
2287
+ if limit > 0:
2288
+ params["max"] = limit
2289
+ if offset > 0:
2290
+ params["start"] = offset
2291
+ result = None
2292
+ try:
2293
+ result = api.session.rest_get(url, params=params)
2294
+ except WebexError as e:
2295
+ handle_rest_error(e)
2296
+ result = result or []
2297
+ items = result.get("criteria", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
2298
+ if output == "json":
2299
+ print_json(items)
2300
+ else:
2301
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
2302
+
2303
+
2304
+
2305
+ @app.command("update-selective-accept")
2306
+ def update_selective_accept(
2307
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="indicates whether selective accept is enabled or not."),
2308
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2309
+ debug: bool = typer.Option(False, "--debug"),
2310
+ ):
2311
+ """Modify Selective Call Accept Settings for User."""
2312
+ api = get_api(debug=debug)
2313
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept"
2314
+ if json_body:
2315
+ body = json.loads(json_body)
2316
+ else:
2317
+ body = {}
2318
+ if enabled is not None:
2319
+ body["enabled"] = enabled
2320
+ try:
2321
+ result = api.session.rest_put(url, json=body)
2322
+ except WebexError as e:
2323
+ handle_rest_error(e)
2324
+ typer.echo(f"Updated.")
2325
+
2326
+
2327
+
2328
+ @app.command("create-criteria-selective-accept")
2329
+ def create_criteria_selective_accept(
2330
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to which the criteria is created."),
2331
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2332
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, GROUP"),
2333
+ calls_from: str = typer.Option(None, "--calls-from", help="(required) Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
2334
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Boolean flag indicating if calls from custom numbers, privat"),
2335
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Boolean flag indicating if calls from custom numbers, unavai"),
2336
+ accept_enabled: bool = typer.Option(None, "--accept-enabled/--no-accept-enabled", help="(required) Boolean flag indicating if selective call accept is enabled."),
2337
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2338
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
2339
+ debug: bool = typer.Option(False, "--debug"),
2340
+ ):
2341
+ """Add User Selective Call Accept Criteria\n\nExample --json-body:\n '{"callsFrom":"ANY_PHONE_NUMBER","acceptEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
2342
+ api = get_api(debug=debug)
2343
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept/criteria"
2344
+ if json_body:
2345
+ body = json.loads(json_body)
2346
+ else:
2347
+ body = {}
2348
+ if schedule_name is not None:
2349
+ body["scheduleName"] = schedule_name
2350
+ if schedule_type is not None:
2351
+ body["scheduleType"] = schedule_type
2352
+ if schedule_level is not None:
2353
+ body["scheduleLevel"] = schedule_level
2354
+ if calls_from is not None:
2355
+ body["callsFrom"] = calls_from
2356
+ if anonymous_callers_enabled is not None:
2357
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2358
+ if unavailable_callers_enabled is not None:
2359
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2360
+ if accept_enabled is not None:
2361
+ body["acceptEnabled"] = accept_enabled
2362
+ _missing = [f for f in ['callsFrom', 'acceptEnabled'] if f not in body or body[f] is None]
2363
+ if _missing:
2364
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
2365
+ raise typer.Exit(1)
2366
+ try:
2367
+ result = api.session.rest_post(url, json=body)
2368
+ except WebexError as e:
2369
+ handle_rest_error(e)
2370
+ if output == "json":
2371
+ print_json(result)
2372
+ elif isinstance(result, dict) and "id" in result:
2373
+ typer.echo(f"Created: {result['id']}")
2374
+ elif not result or result == {}:
2375
+ typer.echo("Created.")
2376
+ else:
2377
+ print_json(result)
2378
+
2379
+
2380
+
2381
+ @app.command("show-criteria-selective-accept")
2382
+ def show_criteria_selective_accept(
2383
+ id: str = typer.Argument(help="id"),
2384
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2385
+ debug: bool = typer.Option(False, "--debug"),
2386
+ ):
2387
+ """Get Selective Call Accept Criteria Settings for User."""
2388
+ api = get_api(debug=debug)
2389
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept/criteria/{id}"
2390
+ try:
2391
+ result = api.session.rest_get(url)
2392
+ except WebexError as e:
2393
+ handle_rest_error(e)
2394
+ if output == "json":
2395
+ print_json(result)
2396
+ else:
2397
+ if isinstance(result, dict):
2398
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2399
+ elif isinstance(result, list):
2400
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2401
+ else:
2402
+ print_json(result)
2403
+
2404
+
2405
+
2406
+ @app.command("update-criteria-selective-accept")
2407
+ def update_criteria_selective_accept(
2408
+ id: str = typer.Argument(help="id"),
2409
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to which the criteria is created."),
2410
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2411
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, GROUP"),
2412
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
2413
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Boolean flag indicating if calls from custom numbers, privat"),
2414
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Boolean flag indicating if calls from custom numbers, unavai"),
2415
+ accept_enabled: bool = typer.Option(None, "--accept-enabled/--no-accept-enabled", help="Boolean flag to enable/disable the selective accept criteria"),
2416
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2417
+ debug: bool = typer.Option(False, "--debug"),
2418
+ ):
2419
+ """Modify a Selective Call Accept Criteria\n\nExample --json-body:\n '{"callsFrom":"ANY_PHONE_NUMBER","acceptEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
2420
+ api = get_api(debug=debug)
2421
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept/criteria/{id}"
2422
+ if json_body:
2423
+ body = json.loads(json_body)
2424
+ else:
2425
+ body = {}
2426
+ if schedule_name is not None:
2427
+ body["scheduleName"] = schedule_name
2428
+ if schedule_type is not None:
2429
+ body["scheduleType"] = schedule_type
2430
+ if schedule_level is not None:
2431
+ body["scheduleLevel"] = schedule_level
2432
+ if calls_from is not None:
2433
+ body["callsFrom"] = calls_from
2434
+ if anonymous_callers_enabled is not None:
2435
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2436
+ if unavailable_callers_enabled is not None:
2437
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2438
+ if accept_enabled is not None:
2439
+ body["acceptEnabled"] = accept_enabled
2440
+ try:
2441
+ result = api.session.rest_put(url, json=body)
2442
+ except WebexError as e:
2443
+ handle_rest_error(e)
2444
+ typer.echo(f"Updated.")
2445
+
2446
+
2447
+
2448
+ @app.command("delete-criteria-selective-accept")
2449
+ def delete_criteria_selective_accept(
2450
+ id: str = typer.Argument(help="id"),
2451
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
2452
+ debug: bool = typer.Option(False, "--debug"),
2453
+ ):
2454
+ """Delete a Selective Call Accept Criteria."""
2455
+ if not force:
2456
+ typer.confirm(f"Delete {id}?", abort=True)
2457
+ api = get_api(debug=debug)
2458
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveAccept/criteria/{id}"
2459
+ try:
2460
+ api.session.rest_delete(url)
2461
+ except WebexError as e:
2462
+ handle_rest_error(e)
2463
+ typer.echo(f"Deleted: {id}")
2464
+
2465
+
2466
+
2467
+ @app.command("list-assigned-numbers")
2468
+ def list_assigned_numbers(
2469
+ name: str = typer.Option(None, "--name", help="List numbers whose owner name contains this string."),
2470
+ phone_number: str = typer.Option(None, "--phone-number", help="List numbers whose phoneNumber contains this string."),
2471
+ extension: str = typer.Option(None, "--extension", help="List numbers whose extension contains this string."),
2472
+ order: str = typer.Option(None, "--order", help="Sort the list of numbers based on `lastName`, `dn`, `extensi"),
2473
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
2474
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
2475
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
2476
+ debug: bool = typer.Option(False, "--debug"),
2477
+ ):
2478
+ """Get Available Numbers for User's Location."""
2479
+ api = get_api(debug=debug)
2480
+ url = f"https://webexapis.com/v1/telephony/config/people/me/location/assignedNumbers"
2481
+ params = {}
2482
+ if name is not None:
2483
+ params["name"] = name
2484
+ if phone_number is not None:
2485
+ params["phoneNumber"] = phone_number
2486
+ if extension is not None:
2487
+ params["extension"] = extension
2488
+ if order is not None:
2489
+ params["order"] = order
2490
+ if limit > 0:
2491
+ params["max"] = limit
2492
+ if offset > 0:
2493
+ params["start"] = offset
2494
+ result = None
2495
+ try:
2496
+ result = api.session.rest_get(url, params=params)
2497
+ except WebexError as e:
2498
+ handle_rest_error(e)
2499
+ result = result or []
2500
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
2501
+ if output == "json":
2502
+ print_json(items)
2503
+ else:
2504
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
2505
+
2506
+
2507
+
2508
+ @app.command("create-criteria-selective-forward")
2509
+ def create_criteria_selective_forward(
2510
+ forward_to_phone_number: str = typer.Option(None, "--forward-to-phone-number", help="The phone number to which calls are forwarded when the crite"),
2511
+ destination_voicemail_enabled: bool = typer.Option(None, "--destination-voicemail-enabled/--no-destination-voicemail-enabled", help="Indicates whether calls that meet the criteria are forwarded"),
2512
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
2513
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2514
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
2515
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS, ANY_INTERNAL, ANY_EXTERNAL"),
2516
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
2517
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
2518
+ forward_enabled: bool = typer.Option(None, "--forward-enabled/--no-forward-enabled", help="Determines whether selective call forwarding is applied for"),
2519
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2520
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
2521
+ debug: bool = typer.Option(False, "--debug"),
2522
+ ):
2523
+ """Add a Selective Call Forwarding Criteria\n\nExample --json-body:\n '{"forwardToPhoneNumber":"...","destinationVoicemailEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true}'."""
2524
+ api = get_api(debug=debug)
2525
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward/criteria"
2526
+ if json_body:
2527
+ body = json.loads(json_body)
2528
+ else:
2529
+ body = {}
2530
+ if forward_to_phone_number is not None:
2531
+ body["forwardToPhoneNumber"] = forward_to_phone_number
2532
+ if destination_voicemail_enabled is not None:
2533
+ body["destinationVoicemailEnabled"] = destination_voicemail_enabled
2534
+ if schedule_name is not None:
2535
+ body["scheduleName"] = schedule_name
2536
+ if schedule_type is not None:
2537
+ body["scheduleType"] = schedule_type
2538
+ if schedule_level is not None:
2539
+ body["scheduleLevel"] = schedule_level
2540
+ if calls_from is not None:
2541
+ body["callsFrom"] = calls_from
2542
+ if anonymous_callers_enabled is not None:
2543
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2544
+ if unavailable_callers_enabled is not None:
2545
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2546
+ if forward_enabled is not None:
2547
+ body["forwardEnabled"] = forward_enabled
2548
+ try:
2549
+ result = api.session.rest_post(url, json=body)
2550
+ except WebexError as e:
2551
+ handle_rest_error(e)
2552
+ if output == "json":
2553
+ print_json(result)
2554
+ elif isinstance(result, dict) and "id" in result:
2555
+ typer.echo(f"Created: {result['id']}")
2556
+ elif not result or result == {}:
2557
+ typer.echo("Created.")
2558
+ else:
2559
+ print_json(result)
2560
+
2561
+
2562
+
2563
+ @app.command("show-criteria-selective-forward")
2564
+ def show_criteria_selective_forward(
2565
+ id: str = typer.Argument(help="id"),
2566
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2567
+ debug: bool = typer.Option(False, "--debug"),
2568
+ ):
2569
+ """Get Settings for a Selective Call Forwarding Criteria."""
2570
+ api = get_api(debug=debug)
2571
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward/criteria/{id}"
2572
+ try:
2573
+ result = api.session.rest_get(url)
2574
+ except WebexError as e:
2575
+ handle_rest_error(e)
2576
+ if output == "json":
2577
+ print_json(result)
2578
+ else:
2579
+ if isinstance(result, dict):
2580
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2581
+ elif isinstance(result, list):
2582
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2583
+ else:
2584
+ print_json(result)
2585
+
2586
+
2587
+
2588
+ @app.command("update-criteria-selective-forward")
2589
+ def update_criteria_selective_forward(
2590
+ id: str = typer.Argument(help="id"),
2591
+ forward_to_phone_number: str = typer.Option(None, "--forward-to-phone-number", help="The phone number to which calls are forwarded when the crite"),
2592
+ destination_voicemail_enabled: bool = typer.Option(None, "--destination-voicemail-enabled/--no-destination-voicemail-enabled", help="Indicates whether calls that meet the criteria are forwarded"),
2593
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
2594
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2595
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
2596
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS, ANY_INTERNAL, ANY_EXTERNAL"),
2597
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Indicates whether anonymous callers are included in this cri"),
2598
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Indicates whether unavailable callers are included in this c"),
2599
+ forward_enabled: bool = typer.Option(None, "--forward-enabled/--no-forward-enabled", help="Determines whether selective call forwarding is applied for"),
2600
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2601
+ debug: bool = typer.Option(False, "--debug"),
2602
+ ):
2603
+ """Modify Settings for a Selective Call Forwarding Criteria\n\nExample --json-body:\n '{"forwardToPhoneNumber":"...","destinationVoicemailEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true}'."""
2604
+ api = get_api(debug=debug)
2605
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward/criteria/{id}"
2606
+ if json_body:
2607
+ body = json.loads(json_body)
2608
+ else:
2609
+ body = {}
2610
+ if forward_to_phone_number is not None:
2611
+ body["forwardToPhoneNumber"] = forward_to_phone_number
2612
+ if destination_voicemail_enabled is not None:
2613
+ body["destinationVoicemailEnabled"] = destination_voicemail_enabled
2614
+ if schedule_name is not None:
2615
+ body["scheduleName"] = schedule_name
2616
+ if schedule_type is not None:
2617
+ body["scheduleType"] = schedule_type
2618
+ if schedule_level is not None:
2619
+ body["scheduleLevel"] = schedule_level
2620
+ if calls_from is not None:
2621
+ body["callsFrom"] = calls_from
2622
+ if anonymous_callers_enabled is not None:
2623
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2624
+ if unavailable_callers_enabled is not None:
2625
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2626
+ if forward_enabled is not None:
2627
+ body["forwardEnabled"] = forward_enabled
2628
+ try:
2629
+ result = api.session.rest_put(url, json=body)
2630
+ except WebexError as e:
2631
+ handle_rest_error(e)
2632
+ typer.echo(f"Updated.")
2633
+
2634
+
2635
+
2636
+ @app.command("delete-criteria-selective-forward")
2637
+ def delete_criteria_selective_forward(
2638
+ id: str = typer.Argument(help="id"),
2639
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
2640
+ debug: bool = typer.Option(False, "--debug"),
2641
+ ):
2642
+ """Delete a Selective Call Forwarding Criteria."""
2643
+ if not force:
2644
+ typer.confirm(f"Delete {id}?", abort=True)
2645
+ api = get_api(debug=debug)
2646
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward/criteria/{id}"
2647
+ try:
2648
+ api.session.rest_delete(url)
2649
+ except WebexError as e:
2650
+ handle_rest_error(e)
2651
+ typer.echo(f"Deleted: {id}")
2652
+
2653
+
2654
+
2655
+ @app.command("list-selective-forward")
2656
+ def list_selective_forward(
2657
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
2658
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
2659
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
2660
+ debug: bool = typer.Option(False, "--debug"),
2661
+ ):
2662
+ """Get Selective Call Forward Settings for User."""
2663
+ api = get_api(debug=debug)
2664
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward"
2665
+ params = {}
2666
+ if limit > 0:
2667
+ params["max"] = limit
2668
+ if offset > 0:
2669
+ params["start"] = offset
2670
+ result = None
2671
+ try:
2672
+ result = api.session.rest_get(url, params=params)
2673
+ except WebexError as e:
2674
+ handle_rest_error(e)
2675
+ result = result or []
2676
+ items = result.get("criteria", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
2677
+ if output == "json":
2678
+ print_json(items)
2679
+ else:
2680
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
2681
+
2682
+
2683
+
2684
+ @app.command("update-selective-forward")
2685
+ def update_selective_forward(
2686
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="`true` if the Selective Forward feature is enabled."),
2687
+ default_phone_number_to_forward: str = typer.Option(None, "--default-phone-number-to-forward", help="Enter the phone number to forward calls to during this sched"),
2688
+ ring_reminder_enabled: bool = typer.Option(None, "--ring-reminder-enabled/--no-ring-reminder-enabled", help="When `true`, enables a ring reminder for such calls."),
2689
+ destination_voicemail_enabled: bool = typer.Option(None, "--destination-voicemail-enabled/--no-destination-voicemail-enabled", help="Enables forwarding for all calls to voicemail. This option i"),
2690
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2691
+ debug: bool = typer.Option(False, "--debug"),
2692
+ ):
2693
+ """Modify Selective Call Forward Settings for User."""
2694
+ api = get_api(debug=debug)
2695
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveForward"
2696
+ if json_body:
2697
+ body = json.loads(json_body)
2698
+ else:
2699
+ body = {}
2700
+ if enabled is not None:
2701
+ body["enabled"] = enabled
2702
+ if default_phone_number_to_forward is not None:
2703
+ body["defaultPhoneNumberToForward"] = default_phone_number_to_forward
2704
+ if ring_reminder_enabled is not None:
2705
+ body["ringReminderEnabled"] = ring_reminder_enabled
2706
+ if destination_voicemail_enabled is not None:
2707
+ body["destinationVoicemailEnabled"] = destination_voicemail_enabled
2708
+ try:
2709
+ result = api.session.rest_put(url, json=body)
2710
+ except WebexError as e:
2711
+ handle_rest_error(e)
2712
+ typer.echo(f"Updated.")
2713
+
2714
+
2715
+
2716
+ @app.command("list-selective-reject")
2717
+ def list_selective_reject(
2718
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
2719
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
2720
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
2721
+ debug: bool = typer.Option(False, "--debug"),
2722
+ ):
2723
+ """Get Selective Call Reject Settings for User."""
2724
+ api = get_api(debug=debug)
2725
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject"
2726
+ params = {}
2727
+ if limit > 0:
2728
+ params["max"] = limit
2729
+ if offset > 0:
2730
+ params["start"] = offset
2731
+ result = None
2732
+ try:
2733
+ result = api.session.rest_get(url, params=params)
2734
+ except WebexError as e:
2735
+ handle_rest_error(e)
2736
+ result = result or []
2737
+ items = result.get("criteria", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
2738
+ if output == "json":
2739
+ print_json(items)
2740
+ else:
2741
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
2742
+
2743
+
2744
+
2745
+ @app.command("update-selective-reject")
2746
+ def update_selective_reject(
2747
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="if `true`, selective reject is enabled."),
2748
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2749
+ debug: bool = typer.Option(False, "--debug"),
2750
+ ):
2751
+ """Modify Selective Call Reject Settings for User."""
2752
+ api = get_api(debug=debug)
2753
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject"
2754
+ if json_body:
2755
+ body = json.loads(json_body)
2756
+ else:
2757
+ body = {}
2758
+ if enabled is not None:
2759
+ body["enabled"] = enabled
2760
+ try:
2761
+ result = api.session.rest_put(url, json=body)
2762
+ except WebexError as e:
2763
+ handle_rest_error(e)
2764
+ typer.echo(f"Updated.")
2765
+
2766
+
2767
+
2768
+ @app.command("create-criteria-selective-reject")
2769
+ def create_criteria_selective_reject(
2770
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to which the criteria is created."),
2771
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2772
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, GROUP"),
2773
+ calls_from: str = typer.Option(None, "--calls-from", help="(required) Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS, FORWARDED"),
2774
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Boolean flag indicating if calls from custom numbers, privat"),
2775
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Boolean flag indicating if calls from custom numbers, unavai"),
2776
+ reject_enabled: bool = typer.Option(None, "--reject-enabled/--no-reject-enabled", help="(required) Boolean flag to enable/disable rejection."),
2777
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2778
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
2779
+ debug: bool = typer.Option(False, "--debug"),
2780
+ ):
2781
+ """Add User Selective Call Reject Criteria\n\nExample --json-body:\n '{"callsFrom":"ANY_PHONE_NUMBER","rejectEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
2782
+ api = get_api(debug=debug)
2783
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject/criteria"
2784
+ if json_body:
2785
+ body = json.loads(json_body)
2786
+ else:
2787
+ body = {}
2788
+ if schedule_name is not None:
2789
+ body["scheduleName"] = schedule_name
2790
+ if schedule_type is not None:
2791
+ body["scheduleType"] = schedule_type
2792
+ if schedule_level is not None:
2793
+ body["scheduleLevel"] = schedule_level
2794
+ if calls_from is not None:
2795
+ body["callsFrom"] = calls_from
2796
+ if anonymous_callers_enabled is not None:
2797
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2798
+ if unavailable_callers_enabled is not None:
2799
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2800
+ if reject_enabled is not None:
2801
+ body["rejectEnabled"] = reject_enabled
2802
+ _missing = [f for f in ['callsFrom', 'rejectEnabled'] if f not in body or body[f] is None]
2803
+ if _missing:
2804
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
2805
+ raise typer.Exit(1)
2806
+ try:
2807
+ result = api.session.rest_post(url, json=body)
2808
+ except WebexError as e:
2809
+ handle_rest_error(e)
2810
+ if output == "json":
2811
+ print_json(result)
2812
+ elif isinstance(result, dict) and "id" in result:
2813
+ typer.echo(f"Created: {result['id']}")
2814
+ elif not result or result == {}:
2815
+ typer.echo("Created.")
2816
+ else:
2817
+ print_json(result)
2818
+
2819
+
2820
+
2821
+ @app.command("show-anonymous-call-reject")
2822
+ def show_anonymous_call_reject(
2823
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2824
+ debug: bool = typer.Option(False, "--debug"),
2825
+ ):
2826
+ """Get Anonymous Call Rejection Settings for User."""
2827
+ api = get_api(debug=debug)
2828
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/anonymousCallReject"
2829
+ try:
2830
+ result = api.session.rest_get(url)
2831
+ except WebexError as e:
2832
+ handle_rest_error(e)
2833
+ if output == "json":
2834
+ print_json(result)
2835
+ else:
2836
+ if isinstance(result, dict):
2837
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2838
+ elif isinstance(result, list):
2839
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2840
+ else:
2841
+ print_json(result)
2842
+
2843
+
2844
+
2845
+ @app.command("update-anonymous-call-reject")
2846
+ def update_anonymous_call_reject(
2847
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Indicates whether Anonymous Call Rejection is enabled or not"),
2848
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2849
+ debug: bool = typer.Option(False, "--debug"),
2850
+ ):
2851
+ """Modify Anonymous Call Rejection Settings for User."""
2852
+ api = get_api(debug=debug)
2853
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/anonymousCallReject"
2854
+ if json_body:
2855
+ body = json.loads(json_body)
2856
+ else:
2857
+ body = {}
2858
+ if enabled is not None:
2859
+ body["enabled"] = enabled
2860
+ try:
2861
+ result = api.session.rest_put(url, json=body)
2862
+ except WebexError as e:
2863
+ handle_rest_error(e)
2864
+ typer.echo(f"Updated.")
2865
+
2866
+
2867
+
2868
+ @app.command("show-criteria-selective-reject")
2869
+ def show_criteria_selective_reject(
2870
+ id: str = typer.Argument(help="id"),
2871
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2872
+ debug: bool = typer.Option(False, "--debug"),
2873
+ ):
2874
+ """Get Selective Call Reject Criteria Settings for User."""
2875
+ api = get_api(debug=debug)
2876
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject/criteria/{id}"
2877
+ try:
2878
+ result = api.session.rest_get(url)
2879
+ except WebexError as e:
2880
+ handle_rest_error(e)
2881
+ if output == "json":
2882
+ print_json(result)
2883
+ else:
2884
+ if isinstance(result, dict):
2885
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2886
+ elif isinstance(result, list):
2887
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2888
+ else:
2889
+ print_json(result)
2890
+
2891
+
2892
+
2893
+ @app.command("update-criteria-selective-reject")
2894
+ def update_criteria_selective_reject(
2895
+ id: str = typer.Argument(help="id"),
2896
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to which the criteria is created."),
2897
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
2898
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, GROUP"),
2899
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS, FORWARDED"),
2900
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="Boolean flag indicating if calls from custom numbers, privat"),
2901
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="Boolean flag indicating if calls from custom numbers, unavai"),
2902
+ reject_enabled: bool = typer.Option(None, "--reject-enabled/--no-reject-enabled", help="Boolean flag to enable/disable rejection."),
2903
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2904
+ debug: bool = typer.Option(False, "--debug"),
2905
+ ):
2906
+ """Modify a Selective Call Reject Criteria\n\nExample --json-body:\n '{"callsFrom":"ANY_PHONE_NUMBER","rejectEnabled":true,"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
2907
+ api = get_api(debug=debug)
2908
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject/criteria/{id}"
2909
+ if json_body:
2910
+ body = json.loads(json_body)
2911
+ else:
2912
+ body = {}
2913
+ if schedule_name is not None:
2914
+ body["scheduleName"] = schedule_name
2915
+ if schedule_type is not None:
2916
+ body["scheduleType"] = schedule_type
2917
+ if schedule_level is not None:
2918
+ body["scheduleLevel"] = schedule_level
2919
+ if calls_from is not None:
2920
+ body["callsFrom"] = calls_from
2921
+ if anonymous_callers_enabled is not None:
2922
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
2923
+ if unavailable_callers_enabled is not None:
2924
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
2925
+ if reject_enabled is not None:
2926
+ body["rejectEnabled"] = reject_enabled
2927
+ try:
2928
+ result = api.session.rest_put(url, json=body)
2929
+ except WebexError as e:
2930
+ handle_rest_error(e)
2931
+ typer.echo(f"Updated.")
2932
+
2933
+
2934
+
2935
+ @app.command("delete-criteria-selective-reject")
2936
+ def delete_criteria_selective_reject(
2937
+ id: str = typer.Argument(help="id"),
2938
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
2939
+ debug: bool = typer.Option(False, "--debug"),
2940
+ ):
2941
+ """Delete a Selective Call Reject Criteria."""
2942
+ if not force:
2943
+ typer.confirm(f"Delete {id}?", abort=True)
2944
+ api = get_api(debug=debug)
2945
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/selectiveReject/criteria/{id}"
2946
+ try:
2947
+ api.session.rest_delete(url)
2948
+ except WebexError as e:
2949
+ handle_rest_error(e)
2950
+ typer.echo(f"Deleted: {id}")
2951
+
2952
+
2953
+
2954
+ @app.command("show-call-waiting")
2955
+ def show_call_waiting(
2956
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
2957
+ debug: bool = typer.Option(False, "--debug"),
2958
+ ):
2959
+ """Get Call Waiting Settings for User."""
2960
+ api = get_api(debug=debug)
2961
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callWaiting"
2962
+ try:
2963
+ result = api.session.rest_get(url)
2964
+ except WebexError as e:
2965
+ handle_rest_error(e)
2966
+ if output == "json":
2967
+ print_json(result)
2968
+ else:
2969
+ if isinstance(result, dict):
2970
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
2971
+ elif isinstance(result, list):
2972
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
2973
+ else:
2974
+ print_json(result)
2975
+
2976
+
2977
+
2978
+ @app.command("update-call-waiting")
2979
+ def update_call_waiting(
2980
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Enable or disable Call Waiting for the user."),
2981
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
2982
+ debug: bool = typer.Option(False, "--debug"),
2983
+ ):
2984
+ """Modify Call Waiting Settings for User."""
2985
+ api = get_api(debug=debug)
2986
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/callWaiting"
2987
+ if json_body:
2988
+ body = json.loads(json_body)
2989
+ else:
2990
+ body = {}
2991
+ if enabled is not None:
2992
+ body["enabled"] = enabled
2993
+ try:
2994
+ result = api.session.rest_put(url, json=body)
2995
+ except WebexError as e:
2996
+ handle_rest_error(e)
2997
+ typer.echo(f"Updated.")
2998
+
2999
+
3000
+
3001
+ @app.command("list-sequential-ring")
3002
+ def list_sequential_ring(
3003
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3004
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3005
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3006
+ debug: bool = typer.Option(False, "--debug"),
3007
+ ):
3008
+ """Get Sequential Ring Settings for User."""
3009
+ api = get_api(debug=debug)
3010
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing"
3011
+ params = {}
3012
+ if limit > 0:
3013
+ params["max"] = limit
3014
+ if offset > 0:
3015
+ params["start"] = offset
3016
+ result = None
3017
+ try:
3018
+ result = api.session.rest_get(url, params=params)
3019
+ except WebexError as e:
3020
+ handle_rest_error(e)
3021
+ result = result or []
3022
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3023
+ if output == "json":
3024
+ print_json(items)
3025
+ else:
3026
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3027
+
3028
+
3029
+
3030
+ @app.command("update-sequential-ring")
3031
+ def update_sequential_ring(
3032
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Enable or disable sequential ring for the user."),
3033
+ ring_base_location_first_enabled: bool = typer.Option(None, "--ring-base-location-first-enabled/--no-ring-base-location-first-enabled", help="When `true`, the user's own devices ring before sequential r"),
3034
+ base_location_number_of_rings: str = typer.Option(None, "--base-location-number-of-rings", help="Number of rings for the user's own devices. Minimum: 2, Maxi"),
3035
+ continue_if_base_location_is_busy_enabled: bool = typer.Option(None, "--continue-if-base-location-is-busy-enabled/--no-continue-if-base-location-is-busy-enabled", help="When `true`, sequential ring continues even when the user is"),
3036
+ calls_to_voicemail_enabled: bool = typer.Option(None, "--calls-to-voicemail-enabled/--no-calls-to-voicemail-enabled", help="When `true`, the caller is provided the option to press the"),
3037
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3038
+ debug: bool = typer.Option(False, "--debug"),
3039
+ ):
3040
+ """Modify Sequential Ring Settings for User\n\nExample --json-body:\n '{"enabled":true,"ringBaseLocationFirstEnabled":true,"baseLocationNumberOfRings":0,"continueIfBaseLocationIsBusyEnabled":true,"callsToVoicemailEnabled":true,"phoneNumbers":[{"answerConfirmationRequiredEnabled":"...","numberOfRings":"...","phoneNumber":"..."}]}'."""
3041
+ api = get_api(debug=debug)
3042
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing"
3043
+ if json_body:
3044
+ body = json.loads(json_body)
3045
+ else:
3046
+ body = {}
3047
+ if enabled is not None:
3048
+ body["enabled"] = enabled
3049
+ if ring_base_location_first_enabled is not None:
3050
+ body["ringBaseLocationFirstEnabled"] = ring_base_location_first_enabled
3051
+ if base_location_number_of_rings is not None:
3052
+ body["baseLocationNumberOfRings"] = base_location_number_of_rings
3053
+ if continue_if_base_location_is_busy_enabled is not None:
3054
+ body["continueIfBaseLocationIsBusyEnabled"] = continue_if_base_location_is_busy_enabled
3055
+ if calls_to_voicemail_enabled is not None:
3056
+ body["callsToVoicemailEnabled"] = calls_to_voicemail_enabled
3057
+ try:
3058
+ result = api.session.rest_put(url, json=body)
3059
+ except WebexError as e:
3060
+ handle_rest_error(e)
3061
+ typer.echo(f"Updated.")
3062
+
3063
+
3064
+
3065
+ @app.command("create-criteria-sequential-ring")
3066
+ def create_criteria_sequential_ring(
3067
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the location's schedule which determines when the se"),
3068
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: holidays, businessHours"),
3069
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: GROUP"),
3070
+ calls_from: str = typer.Option(None, "--calls-from", help="(required) Choices: SELECT_PHONE_NUMBERS, ANY_PHONE_NUMBER"),
3071
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="When `true` incoming calls from private numbers are allowed."),
3072
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="When `true` incoming calls from unavailable numbers are allo"),
3073
+ ring_enabled: bool = typer.Option(None, "--ring-enabled/--no-ring-enabled", help="(required) When set to `true` sequential ringing is enabled for calls t"),
3074
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3075
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
3076
+ debug: bool = typer.Option(False, "--debug"),
3077
+ ):
3078
+ """Add User Sequential Ring Criteria\n\nExample --json-body:\n '{"callsFrom":"SELECT_PHONE_NUMBERS","ringEnabled":true,"scheduleName":"...","scheduleType":"holidays","scheduleLevel":"GROUP","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
3079
+ api = get_api(debug=debug)
3080
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing/criteria"
3081
+ if json_body:
3082
+ body = json.loads(json_body)
3083
+ else:
3084
+ body = {}
3085
+ if schedule_name is not None:
3086
+ body["scheduleName"] = schedule_name
3087
+ if schedule_type is not None:
3088
+ body["scheduleType"] = schedule_type
3089
+ if schedule_level is not None:
3090
+ body["scheduleLevel"] = schedule_level
3091
+ if calls_from is not None:
3092
+ body["callsFrom"] = calls_from
3093
+ if anonymous_callers_enabled is not None:
3094
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
3095
+ if unavailable_callers_enabled is not None:
3096
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
3097
+ if ring_enabled is not None:
3098
+ body["ringEnabled"] = ring_enabled
3099
+ _missing = [f for f in ['callsFrom', 'ringEnabled'] if f not in body or body[f] is None]
3100
+ if _missing:
3101
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
3102
+ raise typer.Exit(1)
3103
+ try:
3104
+ result = api.session.rest_post(url, json=body)
3105
+ except WebexError as e:
3106
+ handle_rest_error(e)
3107
+ if output == "json":
3108
+ print_json(result)
3109
+ elif isinstance(result, dict) and "id" in result:
3110
+ typer.echo(f"Created: {result['id']}")
3111
+ elif not result or result == {}:
3112
+ typer.echo("Created.")
3113
+ else:
3114
+ print_json(result)
3115
+
3116
+
3117
+
3118
+ @app.command("show-criteria-sequential-ring")
3119
+ def show_criteria_sequential_ring(
3120
+ id: str = typer.Argument(help="id"),
3121
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
3122
+ debug: bool = typer.Option(False, "--debug"),
3123
+ ):
3124
+ """Get Sequential Ring Criteria Settings for User."""
3125
+ api = get_api(debug=debug)
3126
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing/criteria/{id}"
3127
+ try:
3128
+ result = api.session.rest_get(url)
3129
+ except WebexError as e:
3130
+ handle_rest_error(e)
3131
+ if output == "json":
3132
+ print_json(result)
3133
+ else:
3134
+ if isinstance(result, dict):
3135
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
3136
+ elif isinstance(result, list):
3137
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
3138
+ else:
3139
+ print_json(result)
3140
+
3141
+
3142
+
3143
+ @app.command("update-criteria-sequential-ring")
3144
+ def update_criteria_sequential_ring(
3145
+ id: str = typer.Argument(help="id"),
3146
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule to be associated with the criteria."),
3147
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
3148
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, LOCATION"),
3149
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
3150
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="When `true`, means this criteria applies for anonymous calle"),
3151
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="When `true`, means this criteria applies for unavailable cal"),
3152
+ ring_enabled: bool = typer.Option(None, "--ring-enabled/--no-ring-enabled", help="Determines whether sequential ring is applied for calls matc"),
3153
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3154
+ debug: bool = typer.Option(False, "--debug"),
3155
+ ):
3156
+ """Modify Sequential Ring Criteria Settings for User\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"ringEnabled":true}'."""
3157
+ api = get_api(debug=debug)
3158
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing/criteria/{id}"
3159
+ if json_body:
3160
+ body = json.loads(json_body)
3161
+ else:
3162
+ body = {}
3163
+ if schedule_name is not None:
3164
+ body["scheduleName"] = schedule_name
3165
+ if schedule_type is not None:
3166
+ body["scheduleType"] = schedule_type
3167
+ if schedule_level is not None:
3168
+ body["scheduleLevel"] = schedule_level
3169
+ if calls_from is not None:
3170
+ body["callsFrom"] = calls_from
3171
+ if anonymous_callers_enabled is not None:
3172
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
3173
+ if unavailable_callers_enabled is not None:
3174
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
3175
+ if ring_enabled is not None:
3176
+ body["ringEnabled"] = ring_enabled
3177
+ try:
3178
+ result = api.session.rest_put(url, json=body)
3179
+ except WebexError as e:
3180
+ handle_rest_error(e)
3181
+ typer.echo(f"Updated.")
3182
+
3183
+
3184
+
3185
+ @app.command("delete-criteria-sequential-ring")
3186
+ def delete_criteria_sequential_ring(
3187
+ id: str = typer.Argument(help="id"),
3188
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
3189
+ debug: bool = typer.Option(False, "--debug"),
3190
+ ):
3191
+ """Delete Sequential Ring Criteria."""
3192
+ if not force:
3193
+ typer.confirm(f"Delete {id}?", abort=True)
3194
+ api = get_api(debug=debug)
3195
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/sequentialRing/criteria/{id}"
3196
+ try:
3197
+ api.session.rest_delete(url)
3198
+ except WebexError as e:
3199
+ handle_rest_error(e)
3200
+ typer.echo(f"Deleted: {id}")
3201
+
3202
+
3203
+
3204
+ @app.command("list-simultaneous-ring")
3205
+ def list_simultaneous_ring(
3206
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3207
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3208
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3209
+ debug: bool = typer.Option(False, "--debug"),
3210
+ ):
3211
+ """Retrieve My Simultaneous Ring Settings."""
3212
+ api = get_api(debug=debug)
3213
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing"
3214
+ params = {}
3215
+ if limit > 0:
3216
+ params["max"] = limit
3217
+ if offset > 0:
3218
+ params["start"] = offset
3219
+ result = None
3220
+ try:
3221
+ result = api.session.rest_get(url, params=params)
3222
+ except WebexError as e:
3223
+ handle_rest_error(e)
3224
+ result = result or []
3225
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3226
+ if output == "json":
3227
+ print_json(items)
3228
+ else:
3229
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3230
+
3231
+
3232
+
3233
+ @app.command("update-simultaneous-ring")
3234
+ def update_simultaneous_ring(
3235
+ enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Simultaneous Ring is enabled or not."),
3236
+ do_not_ring_if_on_call_enabled: bool = typer.Option(None, "--do-not-ring-if-on-call-enabled/--no-do-not-ring-if-on-call-enabled", help="When set to `true`, the configured phone numbers won't ring"),
3237
+ criterias_enabled: bool = typer.Option(None, "--criterias-enabled/--no-criterias-enabled", help="Controls whether the criteria for simultaneous ring are enab"),
3238
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3239
+ debug: bool = typer.Option(False, "--debug"),
3240
+ ):
3241
+ """Modify My Simultaneous Ring Settings\n\nExample --json-body:\n '{"enabled":true,"doNotRingIfOnCallEnabled":true,"phoneNumbers":[{"phoneNumber":"...","answerConfirmationEnabled":"..."}],"criteriasEnabled":true}'."""
3242
+ api = get_api(debug=debug)
3243
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing"
3244
+ if json_body:
3245
+ body = json.loads(json_body)
3246
+ else:
3247
+ body = {}
3248
+ if enabled is not None:
3249
+ body["enabled"] = enabled
3250
+ if do_not_ring_if_on_call_enabled is not None:
3251
+ body["doNotRingIfOnCallEnabled"] = do_not_ring_if_on_call_enabled
3252
+ if criterias_enabled is not None:
3253
+ body["criteriasEnabled"] = criterias_enabled
3254
+ try:
3255
+ result = api.session.rest_put(url, json=body)
3256
+ except WebexError as e:
3257
+ handle_rest_error(e)
3258
+ typer.echo(f"Updated.")
3259
+
3260
+
3261
+
3262
+ @app.command("show-criteria-simultaneous-ring")
3263
+ def show_criteria_simultaneous_ring(
3264
+ id: str = typer.Argument(help="id"),
3265
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
3266
+ debug: bool = typer.Option(False, "--debug"),
3267
+ ):
3268
+ """Retrieve My Simultaneous Ring Criteria."""
3269
+ api = get_api(debug=debug)
3270
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing/criteria/{id}"
3271
+ try:
3272
+ result = api.session.rest_get(url)
3273
+ except WebexError as e:
3274
+ handle_rest_error(e)
3275
+ if output == "json":
3276
+ print_json(result)
3277
+ else:
3278
+ if isinstance(result, dict):
3279
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
3280
+ elif isinstance(result, list):
3281
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
3282
+ else:
3283
+ print_json(result)
3284
+
3285
+
3286
+
3287
+ @app.command("update-criteria-simultaneous-ring")
3288
+ def update_criteria_simultaneous_ring(
3289
+ id: str = typer.Argument(help="id"),
3290
+ schedule_name: str = typer.Option(None, "--schedule-name", help="Name of the schedule which determines when the simultaneous"),
3291
+ schedule_type: str = typer.Option(None, "--schedule-type", help="Choices: businessHours, holidays"),
3292
+ schedule_level: str = typer.Option(None, "--schedule-level", help="Choices: PEOPLE, GROUP"),
3293
+ calls_from: str = typer.Option(None, "--calls-from", help="Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
3294
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="When `true`, the criteria applies to calls from anonymous ca"),
3295
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="When `true`, the criteria applies to calls from unavailable"),
3296
+ ring_enabled: bool = typer.Option(None, "--ring-enabled/--no-ring-enabled", help="When set to `true` simultaneous ringing is enabled for calls"),
3297
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3298
+ debug: bool = typer.Option(False, "--debug"),
3299
+ ):
3300
+ """Modify My Simultaneous Ring Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."],"ringEnabled":true}'."""
3301
+ api = get_api(debug=debug)
3302
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing/criteria/{id}"
3303
+ if json_body:
3304
+ body = json.loads(json_body)
3305
+ else:
3306
+ body = {}
3307
+ if schedule_name is not None:
3308
+ body["scheduleName"] = schedule_name
3309
+ if schedule_type is not None:
3310
+ body["scheduleType"] = schedule_type
3311
+ if schedule_level is not None:
3312
+ body["scheduleLevel"] = schedule_level
3313
+ if calls_from is not None:
3314
+ body["callsFrom"] = calls_from
3315
+ if anonymous_callers_enabled is not None:
3316
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
3317
+ if unavailable_callers_enabled is not None:
3318
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
3319
+ if ring_enabled is not None:
3320
+ body["ringEnabled"] = ring_enabled
3321
+ try:
3322
+ result = api.session.rest_put(url, json=body)
3323
+ except WebexError as e:
3324
+ handle_rest_error(e)
3325
+ typer.echo(f"Updated.")
3326
+
3327
+
3328
+
3329
+ @app.command("delete-criteria-simultaneous-ring")
3330
+ def delete_criteria_simultaneous_ring(
3331
+ id: str = typer.Argument(help="id"),
3332
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
3333
+ debug: bool = typer.Option(False, "--debug"),
3334
+ ):
3335
+ """Delete My Simultaneous Ring Criteria."""
3336
+ if not force:
3337
+ typer.confirm(f"Delete {id}?", abort=True)
3338
+ api = get_api(debug=debug)
3339
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing/criteria/{id}"
3340
+ try:
3341
+ api.session.rest_delete(url)
3342
+ except WebexError as e:
3343
+ handle_rest_error(e)
3344
+ typer.echo(f"Deleted: {id}")
3345
+
3346
+
3347
+
3348
+ @app.command("create-criteria-simultaneous-ring")
3349
+ def create_criteria_simultaneous_ring(
3350
+ schedule_name: str = typer.Option(None, "--schedule-name", help="(required) Name of the schedule which determines when the simultaneous"),
3351
+ schedule_type: str = typer.Option(None, "--schedule-type", help="(required) Choices: businessHours, holidays"),
3352
+ schedule_level: str = typer.Option(None, "--schedule-level", help="(required) Choices: PEOPLE, GROUP"),
3353
+ calls_from: str = typer.Option(None, "--calls-from", help="(required) Choices: ANY_PHONE_NUMBER, SELECT_PHONE_NUMBERS"),
3354
+ anonymous_callers_enabled: bool = typer.Option(None, "--anonymous-callers-enabled/--no-anonymous-callers-enabled", help="When `true`, the criteria applies to calls from anonymous ca"),
3355
+ unavailable_callers_enabled: bool = typer.Option(None, "--unavailable-callers-enabled/--no-unavailable-callers-enabled", help="When `true`, the criteria applies to calls from unavailable"),
3356
+ ring_enabled: bool = typer.Option(None, "--ring-enabled/--no-ring-enabled", help="(required) When set to `true` simultaneous ringing is enabled for calls"),
3357
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3358
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
3359
+ debug: bool = typer.Option(False, "--debug"),
3360
+ ):
3361
+ """Create My Simultaneous Ring Criteria\n\nExample --json-body:\n '{"scheduleName":"...","scheduleType":"businessHours","scheduleLevel":"PEOPLE","callsFrom":"ANY_PHONE_NUMBER","ringEnabled":true,"anonymousCallersEnabled":true,"unavailableCallersEnabled":true,"phoneNumbers":["..."]}'."""
3362
+ api = get_api(debug=debug)
3363
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/simultaneousRing/criteria"
3364
+ if json_body:
3365
+ body = json.loads(json_body)
3366
+ else:
3367
+ body = {}
3368
+ if schedule_name is not None:
3369
+ body["scheduleName"] = schedule_name
3370
+ if schedule_type is not None:
3371
+ body["scheduleType"] = schedule_type
3372
+ if schedule_level is not None:
3373
+ body["scheduleLevel"] = schedule_level
3374
+ if calls_from is not None:
3375
+ body["callsFrom"] = calls_from
3376
+ if anonymous_callers_enabled is not None:
3377
+ body["anonymousCallersEnabled"] = anonymous_callers_enabled
3378
+ if unavailable_callers_enabled is not None:
3379
+ body["unavailableCallersEnabled"] = unavailable_callers_enabled
3380
+ if ring_enabled is not None:
3381
+ body["ringEnabled"] = ring_enabled
3382
+ _missing = [f for f in ['scheduleName', 'scheduleType', 'scheduleLevel', 'callsFrom', 'ringEnabled'] if f not in body or body[f] is None]
3383
+ if _missing:
3384
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
3385
+ raise typer.Exit(1)
3386
+ try:
3387
+ result = api.session.rest_post(url, json=body)
3388
+ except WebexError as e:
3389
+ handle_rest_error(e)
3390
+ if output == "json":
3391
+ print_json(result)
3392
+ elif isinstance(result, dict) and "id" in result:
3393
+ typer.echo(f"Created: {result['id']}")
3394
+ elif not result or result == {}:
3395
+ typer.echo("Created.")
3396
+ else:
3397
+ print_json(result)
3398
+
3399
+
3400
+
3401
+ @app.command("list-numbers")
3402
+ def list_numbers(
3403
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3404
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3405
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3406
+ debug: bool = typer.Option(False, "--debug"),
3407
+ ):
3408
+ """Retrieve My Guest Calling Numbers."""
3409
+ api = get_api(debug=debug)
3410
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/guestCalling/numbers"
3411
+ params = {}
3412
+ if limit > 0:
3413
+ params["max"] = limit
3414
+ if offset > 0:
3415
+ params["start"] = offset
3416
+ result = None
3417
+ try:
3418
+ result = api.session.rest_get(url, params=params)
3419
+ except WebexError as e:
3420
+ handle_rest_error(e)
3421
+ result = result or []
3422
+ items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3423
+ if output == "json":
3424
+ print_json(items)
3425
+ else:
3426
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3427
+
3428
+
3429
+
3430
+ @app.command("list-speed-dials")
3431
+ def list_speed_dials(
3432
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3433
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3434
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3435
+ debug: bool = typer.Option(False, "--debug"),
3436
+ ):
3437
+ """Get Speed Dials."""
3438
+ api = get_api(debug=debug)
3439
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/speedDials"
3440
+ params = {}
3441
+ if limit > 0:
3442
+ params["max"] = limit
3443
+ if offset > 0:
3444
+ params["start"] = offset
3445
+ result = None
3446
+ try:
3447
+ result = api.session.rest_get(url, params=params)
3448
+ except WebexError as e:
3449
+ handle_rest_error(e)
3450
+ result = result or []
3451
+ items = result.get("speedDials", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3452
+ if output == "json":
3453
+ print_json(items)
3454
+ else:
3455
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3456
+
3457
+
3458
+
3459
+ @app.command("update-speed-dials")
3460
+ def update_speed_dials(
3461
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
3462
+ debug: bool = typer.Option(False, "--debug"),
3463
+ ):
3464
+ """Modify Speed Dials\n\nExample --json-body:\n '{"speedDials":[{"id":"...","phoneNumber":"...","lineKeyLabel":"..."}]}'."""
3465
+ api = get_api(debug=debug)
3466
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/speedDials"
3467
+ if json_body:
3468
+ body = json.loads(json_body)
3469
+ else:
3470
+ body = {}
3471
+ try:
3472
+ result = api.session.rest_put(url, json=body)
3473
+ except WebexError as e:
3474
+ handle_rest_error(e)
3475
+ typer.echo(f"Updated.")
3476
+
3477
+
3478
+
3479
+ @app.command("list-available-members")
3480
+ def list_available_members(
3481
+ location_id: str = typer.Option(None, "--location-id", help="Return the members list available in this location."),
3482
+ name: str = typer.Option(None, "--name", help="Search (Contains) based on first name and last name."),
3483
+ phone_number: str = typer.Option(None, "--phone-number", help="Search (Contains) based on number and extension."),
3484
+ order: str = typer.Option(None, "--order", help="Sort by first name (`firstName`) or last name (`lastName`)."),
3485
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3486
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3487
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3488
+ debug: bool = typer.Option(False, "--debug"),
3489
+ ):
3490
+ """Get Speed Dial Available Members."""
3491
+ api = get_api(debug=debug)
3492
+ url = f"https://webexapis.com/v1/telephony/config/people/me/settings/speedDials/availableMembers"
3493
+ params = {}
3494
+ if location_id is not None:
3495
+ params["locationId"] = location_id
3496
+ if name is not None:
3497
+ params["name"] = name
3498
+ if phone_number is not None:
3499
+ params["phoneNumber"] = phone_number
3500
+ if order is not None:
3501
+ params["order"] = order
3502
+ if limit > 0:
3503
+ params["max"] = limit
3504
+ if offset > 0:
3505
+ params["start"] = offset
3506
+ result = None
3507
+ try:
3508
+ result = api.session.rest_get(url, params=params)
3509
+ except WebexError as e:
3510
+ handle_rest_error(e)
3511
+ result = result or []
3512
+ items = result.get("members", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3513
+ if output == "json":
3514
+ print_json(items)
3515
+ else:
3516
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3517
+
3518
+
3519
+
3520
+ @app.command("list-organization")
3521
+ def list_organization(
3522
+ name: str = typer.Option(None, "--name", help="Search (Contains) based on location name. Multiple values ar"),
3523
+ order: str = typer.Option(None, "--order", help="Sort by location name (`name`). Sort directions asc or desc."),
3524
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
3525
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
3526
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
3527
+ debug: bool = typer.Option(False, "--debug"),
3528
+ ):
3529
+ """Get Location List for My Organization."""
3530
+ api = get_api(debug=debug)
3531
+ url = f"https://webexapis.com/v1/telephony/config/people/me/organization/locations"
3532
+ params = {}
3533
+ if name is not None:
3534
+ params["name"] = name
3535
+ if order is not None:
3536
+ params["order"] = order
3537
+ if limit > 0:
3538
+ params["max"] = limit
3539
+ if offset > 0:
3540
+ params["start"] = offset
3541
+ result = None
3542
+ try:
3543
+ result = api.session.rest_get(url, params=params)
3544
+ except WebexError as e:
3545
+ handle_rest_error(e)
3546
+ result = result or []
3547
+ items = result.get("locations", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
3548
+ if output == "json":
3549
+ print_json(items)
3550
+ else:
3551
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
3552
+
3553
+
3554
+
3555
+ @app.command("show-large-org-status")
3556
+ def show_large_org_status(
3557
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
3558
+ debug: bool = typer.Option(False, "--debug"),
3559
+ ):
3560
+ """Get Large Organization Status."""
3561
+ api = get_api(debug=debug)
3562
+ url = f"https://webexapis.com/v1/telephony/config/people/me/organization/largeOrgStatus"
3563
+ try:
3564
+ result = api.session.rest_get(url)
3565
+ except WebexError as e:
3566
+ handle_rest_error(e)
3567
+ if output == "json":
3568
+ print_json(result)
3569
+ else:
3570
+ if isinstance(result, dict):
3571
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
3572
+ elif isinstance(result, list):
3573
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
3574
+ else:
3575
+ print_json(result)
3576
+
3577
+