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,126 @@
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 broadworks-billing-reports.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ before: str = typer.Option(None, "--before", help="Only include billing reports created before this date."),
14
+ after: str = typer.Option(None, "--after", help="Only include billing reports created after this date."),
15
+ sort_by: str = typer.Option(None, "--sort-by", help="Sort the reports. + Members: + id + status + bi"),
16
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
17
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
18
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
19
+ debug: bool = typer.Option(False, "--debug"),
20
+ ):
21
+ """List BroadWorks Billing Reports."""
22
+ api = get_api(debug=debug)
23
+ url = f"https://webexapis.com/v1/broadworks/billing/reports"
24
+ params = {}
25
+ if before is not None:
26
+ params["before"] = before
27
+ if after is not None:
28
+ params["after"] = after
29
+ if sort_by is not None:
30
+ params["sortBy"] = sort_by
31
+ if limit > 0:
32
+ params["max"] = limit
33
+ if offset > 0:
34
+ params["start"] = offset
35
+ result = None
36
+ try:
37
+ result = api.session.rest_get(url, params=params)
38
+ except WebexError as e:
39
+ handle_rest_error(e)
40
+ result = result or []
41
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
42
+ if output == "json":
43
+ print_json(items)
44
+ else:
45
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
46
+
47
+
48
+
49
+ @app.command("create")
50
+ def create(
51
+ billing_period: str = typer.Option(None, "--billing-period", help="(required) The year and month (`YYYY-MM`) for which the billing report"),
52
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
53
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
54
+ debug: bool = typer.Option(False, "--debug"),
55
+ ):
56
+ """Create a BroadWorks Billing Report."""
57
+ api = get_api(debug=debug)
58
+ url = f"https://webexapis.com/v1/broadworks/billing/reports"
59
+ if json_body:
60
+ body = json.loads(json_body)
61
+ else:
62
+ body = {}
63
+ if billing_period is not None:
64
+ body["billingPeriod"] = billing_period
65
+ _missing = [f for f in ['billingPeriod'] if f not in body or body[f] is None]
66
+ if _missing:
67
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
68
+ raise typer.Exit(1)
69
+ try:
70
+ result = api.session.rest_post(url, json=body)
71
+ except WebexError as e:
72
+ handle_rest_error(e)
73
+ if output == "json":
74
+ print_json(result)
75
+ elif isinstance(result, dict) and "id" in result:
76
+ typer.echo(f"Created: {result['id']}")
77
+ elif not result or result == {}:
78
+ typer.echo("Created.")
79
+ else:
80
+ print_json(result)
81
+
82
+
83
+
84
+ @app.command("show")
85
+ def show(
86
+ id: str = typer.Argument(help="id"),
87
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
88
+ debug: bool = typer.Option(False, "--debug"),
89
+ ):
90
+ """Get a BroadWorks Billing Report."""
91
+ api = get_api(debug=debug)
92
+ url = f"https://webexapis.com/v1/broadworks/billing/reports/{id}"
93
+ try:
94
+ result = api.session.rest_get(url)
95
+ except WebexError as e:
96
+ handle_rest_error(e)
97
+ if output == "json":
98
+ print_json(result)
99
+ else:
100
+ if isinstance(result, dict):
101
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
102
+ elif isinstance(result, list):
103
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
104
+ else:
105
+ print_json(result)
106
+
107
+
108
+
109
+ @app.command("delete")
110
+ def delete(
111
+ id: str = typer.Argument(help="id"),
112
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
113
+ debug: bool = typer.Option(False, "--debug"),
114
+ ):
115
+ """Delete a BroadWorks Billing Report."""
116
+ if not force:
117
+ typer.confirm(f"Delete {id}?", abort=True)
118
+ api = get_api(debug=debug)
119
+ url = f"https://webexapis.com/v1/broadworks/billing/reports/{id}"
120
+ try:
121
+ api.session.rest_delete(url)
122
+ except WebexError as e:
123
+ handle_rest_error(e)
124
+ typer.echo(f"Deleted: {id}")
125
+
126
+
@@ -0,0 +1,160 @@
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 broadworks-enterprises.")
9
+
10
+
11
+ @app.command("show")
12
+ def show(
13
+ sp_enterprise_id: str = typer.Option(None, "--sp-enterprise-id", help="The Service Provider supplied unique identifier for the subs"),
14
+ starts_with: str = typer.Option(None, "--starts-with", help="The starting string of the enterprise identifiers to match a"),
15
+ max: str = typer.Option(None, "--max", help="Limit the number of enterprises returned in the search, up t"),
16
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
17
+ debug: bool = typer.Option(False, "--debug"),
18
+ ):
19
+ """List BroadWorks Enterprises."""
20
+ api = get_api(debug=debug)
21
+ url = f"https://webexapis.com/v1/broadworks/enterprises"
22
+ params = {}
23
+ if sp_enterprise_id is not None:
24
+ params["spEnterpriseId"] = sp_enterprise_id
25
+ if starts_with is not None:
26
+ params["startsWith"] = starts_with
27
+ if max is not None:
28
+ params["max"] = max
29
+ try:
30
+ result = api.session.rest_get(url, params=params)
31
+ except WebexError as e:
32
+ handle_rest_error(e)
33
+ if output == "json":
34
+ print_json(result)
35
+ else:
36
+ if isinstance(result, dict):
37
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
38
+ elif isinstance(result, list):
39
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
40
+ else:
41
+ print_json(result)
42
+
43
+
44
+
45
+ @app.command("show-broadworks-directory-sync")
46
+ def show_broadworks_directory_sync(
47
+ id: str = typer.Argument(help="id"),
48
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
49
+ debug: bool = typer.Option(False, "--debug"),
50
+ ):
51
+ """Get Directory Sync Status for an Enterprise."""
52
+ api = get_api(debug=debug)
53
+ url = f"https://webexapis.com/v1/broadworks/enterprises/{id}/broadworksDirectorySync"
54
+ try:
55
+ result = api.session.rest_get(url)
56
+ except WebexError as e:
57
+ handle_rest_error(e)
58
+ if output == "json":
59
+ print_json(result)
60
+ else:
61
+ if isinstance(result, dict):
62
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
63
+ elif isinstance(result, list):
64
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
65
+ else:
66
+ print_json(result)
67
+
68
+
69
+
70
+ @app.command("create")
71
+ def create(
72
+ id: str = typer.Argument(help="id"),
73
+ sync_status: str = typer.Option(None, "--sync-status", help="(required) At this time, the only value allowed for this attribute is `"),
74
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
75
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
76
+ debug: bool = typer.Option(False, "--debug"),
77
+ ):
78
+ """Trigger Directory Sync for an Enterprise."""
79
+ api = get_api(debug=debug)
80
+ url = f"https://webexapis.com/v1/broadworks/enterprises/{id}/broadworksDirectorySync"
81
+ if json_body:
82
+ body = json.loads(json_body)
83
+ else:
84
+ body = {}
85
+ if sync_status is not None:
86
+ body["syncStatus"] = sync_status
87
+ _missing = [f for f in ['syncStatus'] if f not in body or body[f] is None]
88
+ if _missing:
89
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
90
+ raise typer.Exit(1)
91
+ try:
92
+ result = api.session.rest_post(url, json=body)
93
+ except WebexError as e:
94
+ handle_rest_error(e)
95
+ if output == "json":
96
+ print_json(result)
97
+ elif isinstance(result, dict) and "id" in result:
98
+ typer.echo(f"Created: {result['id']}")
99
+ elif not result or result == {}:
100
+ typer.echo("Created.")
101
+ else:
102
+ print_json(result)
103
+
104
+
105
+
106
+ @app.command("update")
107
+ def update(
108
+ id: str = typer.Argument(help="id"),
109
+ enable_dir_sync: bool = typer.Option(None, "--enable-dir-sync/--no-enable-dir-sync", help="The toggle to enable/disable directory sync."),
110
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
111
+ debug: bool = typer.Option(False, "--debug"),
112
+ ):
113
+ """Update Directory Sync for a BroadWorks Enterprise."""
114
+ api = get_api(debug=debug)
115
+ url = f"https://webexapis.com/v1/broadworks/enterprises/{id}/broadworksDirectorySync"
116
+ if json_body:
117
+ body = json.loads(json_body)
118
+ else:
119
+ body = {}
120
+ if enable_dir_sync is not None:
121
+ body["enableDirSync"] = enable_dir_sync
122
+ try:
123
+ result = api.session.rest_put(url, json=body)
124
+ except WebexError as e:
125
+ handle_rest_error(e)
126
+ typer.echo(f"Updated.")
127
+
128
+
129
+
130
+ @app.command("create-external-user")
131
+ def create_external_user(
132
+ id: str = typer.Argument(help="id"),
133
+ user_id: str = typer.Option(None, "--user-id", help="The user ID of the Broadworks user to be synced (A non-webex"),
134
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
135
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
136
+ debug: bool = typer.Option(False, "--debug"),
137
+ ):
138
+ """Trigger Directory Sync for a User."""
139
+ api = get_api(debug=debug)
140
+ url = f"https://webexapis.com/v1/broadworks/enterprises/{id}/broadworksDirectorySync/externalUser"
141
+ if json_body:
142
+ body = json.loads(json_body)
143
+ else:
144
+ body = {}
145
+ if user_id is not None:
146
+ body["userId"] = user_id
147
+ try:
148
+ result = api.session.rest_post(url, json=body)
149
+ except WebexError as e:
150
+ handle_rest_error(e)
151
+ if output == "json":
152
+ print_json(result)
153
+ elif isinstance(result, dict) and "id" in result:
154
+ typer.echo(f"Created: {result['id']}")
155
+ elif not result or result == {}:
156
+ typer.echo("Created.")
157
+ else:
158
+ print_json(result)
159
+
160
+
@@ -0,0 +1,319 @@
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 broadworks-subscribers.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ user_id: str = typer.Option(None, "--user-id", help="The user ID of the subscriber on BroadWorks."),
14
+ person_id: str = typer.Option(None, "--person-id", help="The Person ID of the Webex subscriber."),
15
+ email: str = typer.Option(None, "--email", help="The email address of the subscriber."),
16
+ provisioning_id: str = typer.Option(None, "--provisioning-id", help="The Provisioning ID associated with this subscriber."),
17
+ sp_enterprise_id: str = typer.Option(None, "--sp-enterprise-id", help="The Service Provider supplied unique identifier for the subs"),
18
+ last_status_change: str = typer.Option(None, "--last-status-change", help="Only include subscribers with a provisioning status change a"),
19
+ status: str = typer.Option(None, "--status", help="Choices: pending_email_input, pending_email_validation, pending_user_migration, provisioning, provisioned, updating, error"),
20
+ after: str = typer.Option(None, "--after", help="Only include subscribers created after this date and time. E"),
21
+ self_activated: str = typer.Option(None, "--self-activated", help="Indicates if the subscriber was self activated, rather than"),
22
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
23
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
24
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
25
+ debug: bool = typer.Option(False, "--debug"),
26
+ ):
27
+ """List BroadWorks Subscribers."""
28
+ api = get_api(debug=debug)
29
+ url = f"https://webexapis.com/v1/broadworks/subscribers"
30
+ params = {}
31
+ if user_id is not None:
32
+ params["userId"] = user_id
33
+ if person_id is not None:
34
+ params["personId"] = person_id
35
+ if email is not None:
36
+ params["email"] = email
37
+ if provisioning_id is not None:
38
+ params["provisioningId"] = provisioning_id
39
+ if sp_enterprise_id is not None:
40
+ params["spEnterpriseId"] = sp_enterprise_id
41
+ if last_status_change is not None:
42
+ params["lastStatusChange"] = last_status_change
43
+ if status is not None:
44
+ params["status"] = status
45
+ if after is not None:
46
+ params["after"] = after
47
+ if self_activated is not None:
48
+ params["selfActivated"] = self_activated
49
+ if limit > 0:
50
+ params["max"] = limit
51
+ if offset > 0:
52
+ params["start"] = offset
53
+ result = None
54
+ try:
55
+ result = api.session.rest_get(url, params=params)
56
+ except WebexError as e:
57
+ handle_rest_error(e)
58
+ result = result or []
59
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
60
+ if output == "json":
61
+ print_json(items)
62
+ else:
63
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
64
+
65
+
66
+
67
+ @app.command("create")
68
+ def create(
69
+ provisioning_id: str = typer.Option(None, "--provisioning-id", help="(required) This Provisioning ID defines how this subscriber is to be pr"),
70
+ user_id: str = typer.Option(None, "--user-id", help="(required) The user ID of the subscriber on BroadWorks."),
71
+ sp_enterprise_id: str = typer.Option(None, "--sp-enterprise-id", help="(required) The Service Provider supplied unique identifier for the subs"),
72
+ first_name: str = typer.Option(None, "--first-name", help="(required) The first name of the subscriber."),
73
+ last_name: str = typer.Option(None, "--last-name", help="(required) The last name of the subscriber."),
74
+ package: str = typer.Option(None, "--package", help="(required) Choices: softphone, basic, standard, premium"),
75
+ primary_phone_number: str = typer.Option(None, "--primary-phone-number", help="The primary phone number configured against the subscriber o"),
76
+ mobile_phone_number: str = typer.Option(None, "--mobile-phone-number", help="The mobile phone number configured against the subscriber on"),
77
+ extension: str = typer.Option(None, "--extension", help="The extension number configured against the subscriber on Br"),
78
+ email: str = typer.Option(None, "--email", help="The email address of the subscriber (mandatory for the trust"),
79
+ language: str = typer.Option(None, "--language", help="The {ISO-639-1}_{ISO-3166} or {ISO-639-1} locale or language"),
80
+ timezone: str = typer.Option(None, "--timezone", help="The time zone associated with the subscriber. Refer to the ["),
81
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
82
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
83
+ debug: bool = typer.Option(False, "--debug"),
84
+ ):
85
+ """Provision a BroadWorks Subscriber."""
86
+ api = get_api(debug=debug)
87
+ url = f"https://webexapis.com/v1/broadworks/subscribers"
88
+ if json_body:
89
+ body = json.loads(json_body)
90
+ else:
91
+ body = {}
92
+ if provisioning_id is not None:
93
+ body["provisioningId"] = provisioning_id
94
+ if user_id is not None:
95
+ body["userId"] = user_id
96
+ if sp_enterprise_id is not None:
97
+ body["spEnterpriseId"] = sp_enterprise_id
98
+ if first_name is not None:
99
+ body["firstName"] = first_name
100
+ if last_name is not None:
101
+ body["lastName"] = last_name
102
+ if package is not None:
103
+ body["package"] = package
104
+ if primary_phone_number is not None:
105
+ body["primaryPhoneNumber"] = primary_phone_number
106
+ if mobile_phone_number is not None:
107
+ body["mobilePhoneNumber"] = mobile_phone_number
108
+ if extension is not None:
109
+ body["extension"] = extension
110
+ if email is not None:
111
+ body["email"] = email
112
+ if language is not None:
113
+ body["language"] = language
114
+ if timezone is not None:
115
+ body["timezone"] = timezone
116
+ _missing = [f for f in ['provisioningId', 'userId', 'spEnterpriseId', 'firstName', 'lastName', 'package'] if f not in body or body[f] is None]
117
+ if _missing:
118
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
119
+ raise typer.Exit(1)
120
+ try:
121
+ result = api.session.rest_post(url, json=body)
122
+ except WebexError as e:
123
+ handle_rest_error(e)
124
+ if output == "json":
125
+ print_json(result)
126
+ elif isinstance(result, dict) and "id" in result:
127
+ typer.echo(f"Created: {result['id']}")
128
+ elif not result or result == {}:
129
+ typer.echo("Created.")
130
+ else:
131
+ print_json(result)
132
+
133
+
134
+
135
+ @app.command("show")
136
+ def show(
137
+ subscriber_id: str = typer.Argument(help="subscriberId"),
138
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
139
+ debug: bool = typer.Option(False, "--debug"),
140
+ ):
141
+ """Get a BroadWorks Subscriber."""
142
+ api = get_api(debug=debug)
143
+ url = f"https://webexapis.com/v1/broadworks/subscribers/{subscriber_id}"
144
+ try:
145
+ result = api.session.rest_get(url)
146
+ except WebexError as e:
147
+ handle_rest_error(e)
148
+ if output == "json":
149
+ print_json(result)
150
+ else:
151
+ if isinstance(result, dict):
152
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
153
+ elif isinstance(result, list):
154
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
155
+ else:
156
+ print_json(result)
157
+
158
+
159
+
160
+ @app.command("update")
161
+ def update(
162
+ subscriber_id: str = typer.Argument(help="subscriberId"),
163
+ user_id: str = typer.Option(None, "--user-id", help="The user ID of the subscriber on BroadWorks."),
164
+ first_name: str = typer.Option(None, "--first-name", help="The first name of the subscriber."),
165
+ last_name: str = typer.Option(None, "--last-name", help="The last name of the subscriber."),
166
+ primary_phone_number: str = typer.Option(None, "--primary-phone-number", help="The primary phone number configured against the subscriber o"),
167
+ mobile_phone_number: str = typer.Option(None, "--mobile-phone-number", help="The mobile phone number configured against the subscriber on"),
168
+ extension: str = typer.Option(None, "--extension", help="The extension number configured against the subscriber on Br"),
169
+ timezone: str = typer.Option(None, "--timezone", help="The time zone associated with the subscriber. Refer to the ["),
170
+ package: str = typer.Option(None, "--package", help="The Webex for BroadWorks Package to be assigned to the subsc"),
171
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
172
+ debug: bool = typer.Option(False, "--debug"),
173
+ ):
174
+ """Update a BroadWorks Subscriber."""
175
+ api = get_api(debug=debug)
176
+ url = f"https://webexapis.com/v1/broadworks/subscribers/{subscriber_id}"
177
+ if json_body:
178
+ body = json.loads(json_body)
179
+ else:
180
+ body = {}
181
+ if user_id is not None:
182
+ body["userId"] = user_id
183
+ if first_name is not None:
184
+ body["firstName"] = first_name
185
+ if last_name is not None:
186
+ body["lastName"] = last_name
187
+ if primary_phone_number is not None:
188
+ body["primaryPhoneNumber"] = primary_phone_number
189
+ if mobile_phone_number is not None:
190
+ body["mobilePhoneNumber"] = mobile_phone_number
191
+ if extension is not None:
192
+ body["extension"] = extension
193
+ if timezone is not None:
194
+ body["timezone"] = timezone
195
+ if package is not None:
196
+ body["package"] = package
197
+ try:
198
+ result = api.session.rest_put(url, json=body)
199
+ except WebexError as e:
200
+ handle_rest_error(e)
201
+ typer.echo(f"Updated.")
202
+
203
+
204
+
205
+ @app.command("delete")
206
+ def delete(
207
+ subscriber_id: str = typer.Argument(help="subscriberId"),
208
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
209
+ debug: bool = typer.Option(False, "--debug"),
210
+ ):
211
+ """Remove a BroadWorks Subscriber."""
212
+ if not force:
213
+ typer.confirm(f"Delete {subscriber_id}?", abort=True)
214
+ api = get_api(debug=debug)
215
+ url = f"https://webexapis.com/v1/broadworks/subscribers/{subscriber_id}"
216
+ try:
217
+ api.session.rest_delete(url)
218
+ except WebexError as e:
219
+ handle_rest_error(e)
220
+ typer.echo(f"Deleted: {subscriber_id}")
221
+
222
+
223
+
224
+ @app.command("create-validate")
225
+ def create_validate(
226
+ provisioning_id: str = typer.Option(None, "--provisioning-id", help="Provisioning ID that defines how this subscriber is to be pr"),
227
+ user_id: str = typer.Option(None, "--user-id", help="The user ID of the Broadworks subscriber."),
228
+ sp_enterprise_id: str = typer.Option(None, "--sp-enterprise-id", help="The Service Provider supplied unique identifier for the subs"),
229
+ first_name: str = typer.Option(None, "--first-name", help="The first name of the subscriber."),
230
+ last_name: str = typer.Option(None, "--last-name", help="The last name of the subscriber."),
231
+ package: str = typer.Option(None, "--package", help="Choices: softphone, basic, standard, premium"),
232
+ primary_phone_number: str = typer.Option(None, "--primary-phone-number", help="The primary phone number configured for the subscriber on Br"),
233
+ mobile_phone_number: str = typer.Option(None, "--mobile-phone-number", help="The mobile phone number configured against the subscriber on"),
234
+ extension: str = typer.Option(None, "--extension", help="The extension number configured against the subscriber on Br"),
235
+ email: str = typer.Option(None, "--email", help="(required) The email address of the subscriber."),
236
+ language: str = typer.Option(None, "--language", help="The ISO 639-1 language code associated with the subscriber."),
237
+ timezone: str = typer.Option(None, "--timezone", help="The time zone associated with the subscriber. Refer to the ["),
238
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
239
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
240
+ debug: bool = typer.Option(False, "--debug"),
241
+ ):
242
+ """Precheck a Broadworks Subscriber Provisioning\n\nExample --json-body:\n '{"email":"...","provisioningId":"...","userId":"...","spEnterpriseId":"...","firstName":"...","lastName":"...","package":"softphone","primaryPhoneNumber":"..."}'."""
243
+ api = get_api(debug=debug)
244
+ url = f"https://webexapis.com/v1/broadworks/subscribers/validate"
245
+ if json_body:
246
+ body = json.loads(json_body)
247
+ else:
248
+ body = {}
249
+ if provisioning_id is not None:
250
+ body["provisioningId"] = provisioning_id
251
+ if user_id is not None:
252
+ body["userId"] = user_id
253
+ if sp_enterprise_id is not None:
254
+ body["spEnterpriseId"] = sp_enterprise_id
255
+ if first_name is not None:
256
+ body["firstName"] = first_name
257
+ if last_name is not None:
258
+ body["lastName"] = last_name
259
+ if package is not None:
260
+ body["package"] = package
261
+ if primary_phone_number is not None:
262
+ body["primaryPhoneNumber"] = primary_phone_number
263
+ if mobile_phone_number is not None:
264
+ body["mobilePhoneNumber"] = mobile_phone_number
265
+ if extension is not None:
266
+ body["extension"] = extension
267
+ if email is not None:
268
+ body["email"] = email
269
+ if language is not None:
270
+ body["language"] = language
271
+ if timezone is not None:
272
+ body["timezone"] = timezone
273
+ _missing = [f for f in ['email'] if f not in body or body[f] is None]
274
+ if _missing:
275
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
276
+ raise typer.Exit(1)
277
+ try:
278
+ result = api.session.rest_post(url, json=body)
279
+ except WebexError as e:
280
+ handle_rest_error(e)
281
+ if output == "json":
282
+ print_json(result)
283
+ elif isinstance(result, dict) and "id" in result:
284
+ typer.echo(f"Created: {result['id']}")
285
+ elif not result or result == {}:
286
+ typer.echo("Created.")
287
+ else:
288
+ print_json(result)
289
+
290
+
291
+
292
+ @app.command("create-consent-move")
293
+ def create_consent_move(
294
+ subscriber_id: str = typer.Argument(help="subscriberId"),
295
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
296
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
297
+ debug: bool = typer.Option(False, "--debug"),
298
+ ):
299
+ """Send Consent User Move Email to Pending Broadworks Subscribers."""
300
+ api = get_api(debug=debug)
301
+ url = f"https://webexapis.com/v1/subscribers/{subscriber_id}/emails/consentMove"
302
+ if json_body:
303
+ body = json.loads(json_body)
304
+ else:
305
+ body = {}
306
+ try:
307
+ result = api.session.rest_post(url, json=body)
308
+ except WebexError as e:
309
+ handle_rest_error(e)
310
+ if output == "json":
311
+ print_json(result)
312
+ elif isinstance(result, dict) and "id" in result:
313
+ typer.echo(f"Created: {result['id']}")
314
+ elif not result or result == {}:
315
+ typer.echo("Created.")
316
+ else:
317
+ print_json(result)
318
+
319
+