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,770 @@
1
+ import json
2
+ import typer
3
+ from wxcli.auth import get_api
4
+ from wxcli.errors import WebexError, handle_rest_error
5
+ from wxcli.output import print_table, print_json
6
+ from wxcli.config import resolve_org_id, get_cc_base_url, get_cc_org_id
7
+
8
+
9
+ app = typer.Typer(help="Manage Webex Contact Center cc-address-book.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
15
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned.Default all attributes"),
16
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
17
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
18
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
19
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
20
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
21
+ debug: bool = typer.Option(False, "--debug"),
22
+ ):
23
+ """List Address Book(s)."""
24
+ api = get_api(debug=debug)
25
+ cc_base_url = get_cc_base_url()
26
+ orgid = get_cc_org_id(api.session)
27
+ url = f"{cc_base_url}/organization/{orgid}/address-book"
28
+ params = {}
29
+ if filter_param is not None:
30
+ params["filter"] = filter_param
31
+ if attributes is not None:
32
+ params["attributes"] = attributes
33
+ if page is not None:
34
+ params["page"] = page
35
+ if page_size is not None:
36
+ params["pageSize"] = page_size
37
+ if limit > 0:
38
+ params["max"] = limit
39
+ if offset > 0:
40
+ params["start"] = offset
41
+ result = None
42
+ try:
43
+ result = api.session.rest_get(url, params=params)
44
+ except WebexError as e:
45
+ handle_rest_error(e)
46
+ result = result or []
47
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
48
+ if output == "json":
49
+ print_json(items)
50
+ else:
51
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
52
+
53
+
54
+
55
+ @app.command("create")
56
+ def create(
57
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
58
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
59
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
60
+ name: str = typer.Option(None, "--name", help="(required) A name for the address book."),
61
+ description: str = typer.Option(None, "--description", help="A short description indicating the context of the address bo"),
62
+ parent_type: str = typer.Option(None, "--parent-type", help="(required) Choices: ORGANIZATION, SITE"),
63
+ site_id: str = typer.Option(None, "--site-id", help="The specific site id where the address book is accessible."),
64
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
65
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
66
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
67
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
68
+ debug: bool = typer.Option(False, "--debug"),
69
+ ):
70
+ """Create a new Address Book\n\nExample --json-body:\n '{"name":"...","parentType":"ORGANIZATION","organizationId":"...","id":"...","version":0,"description":"...","siteId":"...","addressBookEntries":[{"name":"...","number":"...","organizationId":"...","id":"...","version":"...","createdTime":"...","lastUpdatedTime":"..."}]}'."""
71
+ api = get_api(debug=debug)
72
+ cc_base_url = get_cc_base_url()
73
+ orgid = get_cc_org_id(api.session)
74
+ url = f"{cc_base_url}/organization/{orgid}/address-book"
75
+ if json_body:
76
+ body = json.loads(json_body)
77
+ else:
78
+ body = {}
79
+ if organization_id is not None:
80
+ body["organizationId"] = organization_id
81
+ if id_param is not None:
82
+ body["id"] = id_param
83
+ if version is not None:
84
+ body["version"] = version
85
+ if name is not None:
86
+ body["name"] = name
87
+ if description is not None:
88
+ body["description"] = description
89
+ if parent_type is not None:
90
+ body["parentType"] = parent_type
91
+ if site_id is not None:
92
+ body["siteId"] = site_id
93
+ if created_time is not None:
94
+ body["createdTime"] = created_time
95
+ if last_updated_time is not None:
96
+ body["lastUpdatedTime"] = last_updated_time
97
+ _missing = [f for f in ['name', 'parentType'] if f not in body or body[f] is None]
98
+ if _missing:
99
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
100
+ raise typer.Exit(1)
101
+ try:
102
+ result = api.session.rest_post(url, json=body)
103
+ except WebexError as e:
104
+ handle_rest_error(e)
105
+ if output == "json":
106
+ print_json(result)
107
+ elif isinstance(result, dict) and "id" in result:
108
+ typer.echo(f"Created: {result['id']}")
109
+ elif not result or result == {}:
110
+ typer.echo("Created.")
111
+ else:
112
+ print_json(result)
113
+
114
+
115
+
116
+ @app.command("list-bulk-export")
117
+ def list_bulk_export(
118
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
119
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
120
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
121
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
122
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
123
+ debug: bool = typer.Option(False, "--debug"),
124
+ ):
125
+ """Bulk export Address Book(s)."""
126
+ api = get_api(debug=debug)
127
+ cc_base_url = get_cc_base_url()
128
+ orgid = get_cc_org_id(api.session)
129
+ url = f"{cc_base_url}/organization/{orgid}/address-book/bulk-export"
130
+ params = {}
131
+ if page is not None:
132
+ params["page"] = page
133
+ if page_size is not None:
134
+ params["pageSize"] = page_size
135
+ if limit > 0:
136
+ params["max"] = limit
137
+ if offset > 0:
138
+ params["start"] = offset
139
+ result = None
140
+ try:
141
+ result = api.session.rest_get(url, params=params)
142
+ except WebexError as e:
143
+ handle_rest_error(e)
144
+ result = result or []
145
+ items = result.get("resources", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
146
+ if output == "json":
147
+ print_json(items)
148
+ else:
149
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
150
+
151
+
152
+
153
+ @app.command("create-entry")
154
+ def create_entry(
155
+ address_book_id: str = typer.Argument(help="addressBookId"),
156
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
157
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
158
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
159
+ name: str = typer.Option(None, "--name", help="(required) A name for the address book entry."),
160
+ number: str = typer.Option(None, "--number", help="(required) The phone number for the entry."),
161
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
162
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
163
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
164
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
165
+ debug: bool = typer.Option(False, "--debug"),
166
+ ):
167
+ """Create a new Address Book Entry."""
168
+ api = get_api(debug=debug)
169
+ cc_base_url = get_cc_base_url()
170
+ orgid = get_cc_org_id(api.session)
171
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{address_book_id}/entry"
172
+ if json_body:
173
+ body = json.loads(json_body)
174
+ else:
175
+ body = {}
176
+ if organization_id is not None:
177
+ body["organizationId"] = organization_id
178
+ if id_param is not None:
179
+ body["id"] = id_param
180
+ if version is not None:
181
+ body["version"] = version
182
+ if name is not None:
183
+ body["name"] = name
184
+ if number is not None:
185
+ body["number"] = number
186
+ if created_time is not None:
187
+ body["createdTime"] = created_time
188
+ if last_updated_time is not None:
189
+ body["lastUpdatedTime"] = last_updated_time
190
+ _missing = [f for f in ['name', 'number'] if f not in body or body[f] is None]
191
+ if _missing:
192
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
193
+ raise typer.Exit(1)
194
+ try:
195
+ result = api.session.rest_post(url, json=body)
196
+ except WebexError as e:
197
+ handle_rest_error(e)
198
+ if output == "json":
199
+ print_json(result)
200
+ elif isinstance(result, dict) and "id" in result:
201
+ typer.echo(f"Created: {result['id']}")
202
+ elif not result or result == {}:
203
+ typer.echo("Created.")
204
+ else:
205
+ print_json(result)
206
+
207
+
208
+
209
+ @app.command("create-bulk")
210
+ def create_bulk(
211
+ address_book_id: str = typer.Argument(help="addressBookId"),
212
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
213
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
214
+ debug: bool = typer.Option(False, "--debug"),
215
+ ):
216
+ """Bulk save Address Book Entry(s)\n\nExample --json-body:\n '{"items":[{"itemIdentifier":"...","item":"...","requestAction":"..."}]}'."""
217
+ api = get_api(debug=debug)
218
+ cc_base_url = get_cc_base_url()
219
+ orgid = get_cc_org_id(api.session)
220
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{address_book_id}/entry/bulk"
221
+ if json_body:
222
+ body = json.loads(json_body)
223
+ else:
224
+ body = {}
225
+ try:
226
+ result = api.session.rest_post(url, json=body)
227
+ except WebexError as e:
228
+ handle_rest_error(e)
229
+ if output == "json":
230
+ print_json(result)
231
+ elif isinstance(result, dict) and "id" in result:
232
+ typer.echo(f"Created: {result['id']}")
233
+ elif not result or result == {}:
234
+ typer.echo("Created.")
235
+ else:
236
+ print_json(result)
237
+
238
+
239
+
240
+ @app.command("show")
241
+ def show(
242
+ address_book_id: str = typer.Argument(help="addressBookId"),
243
+ id: str = typer.Argument(help="id"),
244
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
245
+ debug: bool = typer.Option(False, "--debug"),
246
+ ):
247
+ """Get specific Address Book Entry by ID."""
248
+ api = get_api(debug=debug)
249
+ cc_base_url = get_cc_base_url()
250
+ orgid = get_cc_org_id(api.session)
251
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{address_book_id}/entry/{id}"
252
+ try:
253
+ result = api.session.rest_get(url)
254
+ except WebexError as e:
255
+ handle_rest_error(e)
256
+ if output == "json":
257
+ print_json(result)
258
+ else:
259
+ if isinstance(result, dict):
260
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
261
+ elif isinstance(result, list):
262
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
263
+ else:
264
+ print_json(result)
265
+
266
+
267
+
268
+ @app.command("update")
269
+ def update(
270
+ address_book_id: str = typer.Argument(help="addressBookId"),
271
+ id: str = typer.Argument(help="id"),
272
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
273
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
274
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
275
+ name: str = typer.Option(None, "--name", help="A name for the address book entry."),
276
+ number: str = typer.Option(None, "--number", help="The phone number for the entry."),
277
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
278
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
279
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
280
+ debug: bool = typer.Option(False, "--debug"),
281
+ ):
282
+ """Update specific Address Book Entry by ID."""
283
+ api = get_api(debug=debug)
284
+ cc_base_url = get_cc_base_url()
285
+ orgid = get_cc_org_id(api.session)
286
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{address_book_id}/entry/{id}"
287
+ if json_body:
288
+ body = json.loads(json_body)
289
+ else:
290
+ body = {}
291
+ if organization_id is not None:
292
+ body["organizationId"] = organization_id
293
+ if id_param is not None:
294
+ body["id"] = id_param
295
+ if version is not None:
296
+ body["version"] = version
297
+ if name is not None:
298
+ body["name"] = name
299
+ if number is not None:
300
+ body["number"] = number
301
+ if created_time is not None:
302
+ body["createdTime"] = created_time
303
+ if last_updated_time is not None:
304
+ body["lastUpdatedTime"] = last_updated_time
305
+ try:
306
+ result = api.session.rest_put(url, json=body)
307
+ except WebexError as e:
308
+ handle_rest_error(e)
309
+ typer.echo(f"Updated.")
310
+
311
+
312
+
313
+ @app.command("delete")
314
+ def delete(
315
+ address_book_id: str = typer.Argument(help="addressBookId"),
316
+ id: str = typer.Argument(help="id"),
317
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
318
+ debug: bool = typer.Option(False, "--debug"),
319
+ ):
320
+ """Delete specific Address Book Entry by ID."""
321
+ if not force:
322
+ typer.confirm(f"Delete {id}?", abort=True)
323
+ api = get_api(debug=debug)
324
+ cc_base_url = get_cc_base_url()
325
+ orgid = get_cc_org_id(api.session)
326
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{address_book_id}/entry/{id}"
327
+ try:
328
+ api.session.rest_delete(url)
329
+ except WebexError as e:
330
+ handle_rest_error(e)
331
+ typer.echo(f"Deleted: {id}")
332
+
333
+
334
+
335
+ @app.command("show-address-book-organization")
336
+ def show_address_book_organization(
337
+ id: str = typer.Argument(help="id"),
338
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
339
+ debug: bool = typer.Option(False, "--debug"),
340
+ ):
341
+ """Get specific Address Book by ID."""
342
+ api = get_api(debug=debug)
343
+ cc_base_url = get_cc_base_url()
344
+ orgid = get_cc_org_id(api.session)
345
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{id}"
346
+ try:
347
+ result = api.session.rest_get(url)
348
+ except WebexError as e:
349
+ handle_rest_error(e)
350
+ if output == "json":
351
+ print_json(result)
352
+ else:
353
+ if isinstance(result, dict):
354
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
355
+ elif isinstance(result, list):
356
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
357
+ else:
358
+ print_json(result)
359
+
360
+
361
+
362
+ @app.command("update-address-book-organization")
363
+ def update_address_book_organization(
364
+ id: str = typer.Argument(help="id"),
365
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
366
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
367
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
368
+ name: str = typer.Option(None, "--name", help="A name for the address book."),
369
+ description: str = typer.Option(None, "--description", help="A short description indicating the context of the address bo"),
370
+ parent_type: str = typer.Option(None, "--parent-type", help="Choices: ORGANIZATION, SITE"),
371
+ site_id: str = typer.Option(None, "--site-id", help="The specific site id where the address book is accessible."),
372
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
373
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
374
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
375
+ debug: bool = typer.Option(False, "--debug"),
376
+ ):
377
+ """Update specific Address Book by ID\n\nExample --json-body:\n '{"name":"...","parentType":"ORGANIZATION","organizationId":"...","id":"...","version":0,"description":"...","siteId":"...","addressBookEntries":[{"name":"...","number":"...","organizationId":"...","id":"...","version":"...","createdTime":"...","lastUpdatedTime":"..."}]}'."""
378
+ api = get_api(debug=debug)
379
+ cc_base_url = get_cc_base_url()
380
+ orgid = get_cc_org_id(api.session)
381
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{id}"
382
+ if json_body:
383
+ body = json.loads(json_body)
384
+ else:
385
+ body = {}
386
+ if organization_id is not None:
387
+ body["organizationId"] = organization_id
388
+ if id_param is not None:
389
+ body["id"] = id_param
390
+ if version is not None:
391
+ body["version"] = version
392
+ if name is not None:
393
+ body["name"] = name
394
+ if description is not None:
395
+ body["description"] = description
396
+ if parent_type is not None:
397
+ body["parentType"] = parent_type
398
+ if site_id is not None:
399
+ body["siteId"] = site_id
400
+ if created_time is not None:
401
+ body["createdTime"] = created_time
402
+ if last_updated_time is not None:
403
+ body["lastUpdatedTime"] = last_updated_time
404
+ try:
405
+ result = api.session.rest_put(url, json=body)
406
+ except WebexError as e:
407
+ handle_rest_error(e)
408
+ typer.echo(f"Updated.")
409
+
410
+
411
+
412
+ @app.command("delete-address-book-organization")
413
+ def delete_address_book_organization(
414
+ id: str = typer.Argument(help="id"),
415
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
416
+ debug: bool = typer.Option(False, "--debug"),
417
+ ):
418
+ """Delete specific Address Book by ID."""
419
+ if not force:
420
+ typer.confirm(f"Delete {id}?", abort=True)
421
+ api = get_api(debug=debug)
422
+ cc_base_url = get_cc_base_url()
423
+ orgid = get_cc_org_id(api.session)
424
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{id}"
425
+ try:
426
+ api.session.rest_delete(url)
427
+ except WebexError as e:
428
+ handle_rest_error(e)
429
+ typer.echo(f"Deleted: {id}")
430
+
431
+
432
+
433
+ @app.command("list-incoming-references")
434
+ def list_incoming_references(
435
+ id: str = typer.Argument(help="id"),
436
+ type_param: str = typer.Option(None, "--type", help="Entity type of the other entity that has a reference to this"),
437
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
438
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
439
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
440
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
441
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
442
+ debug: bool = typer.Option(False, "--debug"),
443
+ ):
444
+ """List references for a specific Address Book."""
445
+ api = get_api(debug=debug)
446
+ cc_base_url = get_cc_base_url()
447
+ orgid = get_cc_org_id(api.session)
448
+ url = f"{cc_base_url}/organization/{orgid}/address-book/{id}/incoming-references"
449
+ params = {}
450
+ if type_param is not None:
451
+ params["type"] = type_param
452
+ if page is not None:
453
+ params["page"] = page
454
+ if page_size is not None:
455
+ params["pageSize"] = page_size
456
+ if limit > 0:
457
+ params["max"] = limit
458
+ if offset > 0:
459
+ params["start"] = offset
460
+ result = None
461
+ try:
462
+ result = api.session.rest_get(url, params=params)
463
+ except WebexError as e:
464
+ handle_rest_error(e)
465
+ result = result or []
466
+ items = result.get("data", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
467
+ if output == "json":
468
+ print_json(items)
469
+ else:
470
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
471
+
472
+
473
+
474
+ @app.command("list-address-book-v2")
475
+ def list_address_book_v2(
476
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
477
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned.Default all attributes"),
478
+ search: str = typer.Option(None, "--search", help="Filter data based on the search keyword.Supported search col"),
479
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
480
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
481
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
482
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
483
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
484
+ debug: bool = typer.Option(False, "--debug"),
485
+ ):
486
+ """List Address Book(s)."""
487
+ api = get_api(debug=debug)
488
+ cc_base_url = get_cc_base_url()
489
+ orgid = get_cc_org_id(api.session)
490
+ url = f"{cc_base_url}/organization/{orgid}/v2/address-book"
491
+ params = {}
492
+ if filter_param is not None:
493
+ params["filter"] = filter_param
494
+ if attributes is not None:
495
+ params["attributes"] = attributes
496
+ if search is not None:
497
+ params["search"] = search
498
+ if page is not None:
499
+ params["page"] = page
500
+ if page_size is not None:
501
+ params["pageSize"] = page_size
502
+ if limit > 0:
503
+ params["max"] = limit
504
+ if offset > 0:
505
+ params["start"] = offset
506
+ result = None
507
+ try:
508
+ result = api.session.rest_get(url, params=params)
509
+ except WebexError as e:
510
+ handle_rest_error(e)
511
+ result = result or []
512
+ items = result.get("data", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
513
+ if output == "json":
514
+ print_json(items)
515
+ else:
516
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
517
+
518
+
519
+
520
+ @app.command("list-entry")
521
+ def list_entry(
522
+ address_book_id: str = typer.Argument(help="addressBookId"),
523
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
524
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned.Default all attributes"),
525
+ search: str = typer.Option(None, "--search", help="Filter data based on the search keyword.Supported search col"),
526
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
527
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
528
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
529
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
530
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
531
+ debug: bool = typer.Option(False, "--debug"),
532
+ ):
533
+ """List Address Book Entry(s)."""
534
+ api = get_api(debug=debug)
535
+ cc_base_url = get_cc_base_url()
536
+ orgid = get_cc_org_id(api.session)
537
+ url = f"{cc_base_url}/organization/{orgid}/v2/address-book/{address_book_id}/entry"
538
+ params = {}
539
+ if filter_param is not None:
540
+ params["filter"] = filter_param
541
+ if attributes is not None:
542
+ params["attributes"] = attributes
543
+ if search is not None:
544
+ params["search"] = search
545
+ if page is not None:
546
+ params["page"] = page
547
+ if page_size is not None:
548
+ params["pageSize"] = page_size
549
+ if limit > 0:
550
+ params["max"] = limit
551
+ if offset > 0:
552
+ params["start"] = offset
553
+ result = None
554
+ try:
555
+ result = api.session.rest_get(url, params=params)
556
+ except WebexError as e:
557
+ handle_rest_error(e)
558
+ result = result or []
559
+ items = result.get("data", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
560
+ if output == "json":
561
+ print_json(items)
562
+ else:
563
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
564
+
565
+
566
+
567
+ @app.command("list-address-book-v3")
568
+ def list_address_book_v3(
569
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
570
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned.Default all attributes"),
571
+ search: str = typer.Option(None, "--search", help="Filter data based on the search keyword.Supported search col"),
572
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
573
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
574
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
575
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
576
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
577
+ debug: bool = typer.Option(False, "--debug"),
578
+ ):
579
+ """List Address Book(s)."""
580
+ api = get_api(debug=debug)
581
+ cc_base_url = get_cc_base_url()
582
+ orgid = get_cc_org_id(api.session)
583
+ url = f"{cc_base_url}/organization/{orgid}/v3/address-book"
584
+ params = {}
585
+ if filter_param is not None:
586
+ params["filter"] = filter_param
587
+ if attributes is not None:
588
+ params["attributes"] = attributes
589
+ if search is not None:
590
+ params["search"] = search
591
+ if page is not None:
592
+ params["page"] = page
593
+ if page_size is not None:
594
+ params["pageSize"] = page_size
595
+ if limit > 0:
596
+ params["max"] = limit
597
+ if offset > 0:
598
+ params["start"] = offset
599
+ result = None
600
+ try:
601
+ result = api.session.rest_get(url, params=params)
602
+ except WebexError as e:
603
+ handle_rest_error(e)
604
+ result = result or []
605
+ items = result.get("data", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
606
+ if output == "json":
607
+ print_json(items)
608
+ else:
609
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
610
+
611
+
612
+
613
+ @app.command("create-address-book")
614
+ def create_address_book(
615
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
616
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
617
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
618
+ name: str = typer.Option(None, "--name", help="(required) A name for the address book."),
619
+ description: str = typer.Option(None, "--description", help="A short description indicating the context of the address bo"),
620
+ parent_type: str = typer.Option(None, "--parent-type", help="(required) Choices: ORGANIZATION, SITE"),
621
+ site_id: str = typer.Option(None, "--site-id", help="The specific site id where the address book is accessible."),
622
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
623
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
624
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
625
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
626
+ debug: bool = typer.Option(False, "--debug"),
627
+ ):
628
+ """Create a new Address Book."""
629
+ api = get_api(debug=debug)
630
+ cc_base_url = get_cc_base_url()
631
+ orgid = get_cc_org_id(api.session)
632
+ url = f"{cc_base_url}/organization/{orgid}/v3/address-book"
633
+ if json_body:
634
+ body = json.loads(json_body)
635
+ else:
636
+ body = {}
637
+ if organization_id is not None:
638
+ body["organizationId"] = organization_id
639
+ if id_param is not None:
640
+ body["id"] = id_param
641
+ if version is not None:
642
+ body["version"] = version
643
+ if name is not None:
644
+ body["name"] = name
645
+ if description is not None:
646
+ body["description"] = description
647
+ if parent_type is not None:
648
+ body["parentType"] = parent_type
649
+ if site_id is not None:
650
+ body["siteId"] = site_id
651
+ if created_time is not None:
652
+ body["createdTime"] = created_time
653
+ if last_updated_time is not None:
654
+ body["lastUpdatedTime"] = last_updated_time
655
+ _missing = [f for f in ['name', 'parentType'] if f not in body or body[f] is None]
656
+ if _missing:
657
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
658
+ raise typer.Exit(1)
659
+ try:
660
+ result = api.session.rest_post(url, json=body)
661
+ except WebexError as e:
662
+ handle_rest_error(e)
663
+ if output == "json":
664
+ print_json(result)
665
+ elif isinstance(result, dict) and "id" in result:
666
+ typer.echo(f"Created: {result['id']}")
667
+ elif not result or result == {}:
668
+ typer.echo("Created.")
669
+ else:
670
+ print_json(result)
671
+
672
+
673
+
674
+ @app.command("show-address-book-v3")
675
+ def show_address_book_v3(
676
+ id: str = typer.Argument(help="id"),
677
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
678
+ debug: bool = typer.Option(False, "--debug"),
679
+ ):
680
+ """Get specific Address Book by ID."""
681
+ api = get_api(debug=debug)
682
+ cc_base_url = get_cc_base_url()
683
+ orgid = get_cc_org_id(api.session)
684
+ url = f"{cc_base_url}/organization/{orgid}/v3/address-book/{id}"
685
+ try:
686
+ result = api.session.rest_get(url)
687
+ except WebexError as e:
688
+ handle_rest_error(e)
689
+ if output == "json":
690
+ print_json(result)
691
+ else:
692
+ if isinstance(result, dict):
693
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
694
+ elif isinstance(result, list):
695
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
696
+ else:
697
+ print_json(result)
698
+
699
+
700
+
701
+ @app.command("update-address-book-v3")
702
+ def update_address_book_v3(
703
+ id: str = typer.Argument(help="id"),
704
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. It is required to def"),
705
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
706
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
707
+ name: str = typer.Option(None, "--name", help="A name for the address book."),
708
+ description: str = typer.Option(None, "--description", help="A short description indicating the context of the address bo"),
709
+ parent_type: str = typer.Option(None, "--parent-type", help="Choices: ORGANIZATION, SITE"),
710
+ site_id: str = typer.Option(None, "--site-id", help="The specific site id where the address book is accessible."),
711
+ created_time: str = typer.Option(None, "--created-time", help="Creation time(in epoch millis) of this resource."),
712
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="Time(in epoch millis) when this resource was last updated."),
713
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
714
+ debug: bool = typer.Option(False, "--debug"),
715
+ ):
716
+ """Update specific Address Book by ID."""
717
+ api = get_api(debug=debug)
718
+ cc_base_url = get_cc_base_url()
719
+ orgid = get_cc_org_id(api.session)
720
+ url = f"{cc_base_url}/organization/{orgid}/v3/address-book/{id}"
721
+ if json_body:
722
+ body = json.loads(json_body)
723
+ else:
724
+ body = {}
725
+ if organization_id is not None:
726
+ body["organizationId"] = organization_id
727
+ if id_param is not None:
728
+ body["id"] = id_param
729
+ if version is not None:
730
+ body["version"] = version
731
+ if name is not None:
732
+ body["name"] = name
733
+ if description is not None:
734
+ body["description"] = description
735
+ if parent_type is not None:
736
+ body["parentType"] = parent_type
737
+ if site_id is not None:
738
+ body["siteId"] = site_id
739
+ if created_time is not None:
740
+ body["createdTime"] = created_time
741
+ if last_updated_time is not None:
742
+ body["lastUpdatedTime"] = last_updated_time
743
+ try:
744
+ result = api.session.rest_put(url, json=body)
745
+ except WebexError as e:
746
+ handle_rest_error(e)
747
+ typer.echo(f"Updated.")
748
+
749
+
750
+
751
+ @app.command("delete-address-book-v3")
752
+ def delete_address_book_v3(
753
+ id: str = typer.Argument(help="id"),
754
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
755
+ debug: bool = typer.Option(False, "--debug"),
756
+ ):
757
+ """Delete specific Address Book by ID."""
758
+ if not force:
759
+ typer.confirm(f"Delete {id}?", abort=True)
760
+ api = get_api(debug=debug)
761
+ cc_base_url = get_cc_base_url()
762
+ orgid = get_cc_org_id(api.session)
763
+ url = f"{cc_base_url}/organization/{orgid}/v3/address-book/{id}"
764
+ try:
765
+ api.session.rest_delete(url)
766
+ except WebexError as e:
767
+ handle_rest_error(e)
768
+ typer.echo(f"Deleted: {id}")
769
+
770
+