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,515 @@
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 Meetings meeting-preferences.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
14
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
15
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
16
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
17
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
18
+ debug: bool = typer.Option(False, "--debug"),
19
+ ):
20
+ """Get Meeting Preference Details."""
21
+ api = get_api(debug=debug)
22
+ url = f"https://webexapis.com/v1/meetingPreferences"
23
+ params = {}
24
+ if user_email is not None:
25
+ params["userEmail"] = user_email
26
+ if site_url is not None:
27
+ params["siteUrl"] = site_url
28
+ if limit > 0:
29
+ params["max"] = limit
30
+ if offset > 0:
31
+ params["start"] = offset
32
+ result = None
33
+ try:
34
+ result = api.session.rest_get(url, params=params)
35
+ except WebexError as e:
36
+ handle_rest_error(e)
37
+ result = result or []
38
+ items = result.get("sites", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
39
+ if output == "json":
40
+ print_json(items)
41
+ else:
42
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
43
+
44
+
45
+
46
+ @app.command("list-personal-meeting-room")
47
+ def list_personal_meeting_room(
48
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
49
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
50
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
51
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
52
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
53
+ debug: bool = typer.Option(False, "--debug"),
54
+ ):
55
+ """Get Personal Meeting Room Options."""
56
+ api = get_api(debug=debug)
57
+ url = f"https://webexapis.com/v1/meetingPreferences/personalMeetingRoom"
58
+ params = {}
59
+ if user_email is not None:
60
+ params["userEmail"] = user_email
61
+ if site_url is not None:
62
+ params["siteUrl"] = site_url
63
+ if limit > 0:
64
+ params["max"] = limit
65
+ if offset > 0:
66
+ params["start"] = offset
67
+ result = None
68
+ try:
69
+ result = api.session.rest_get(url, params=params)
70
+ except WebexError as e:
71
+ handle_rest_error(e)
72
+ result = result or []
73
+ items = result.get("coHosts", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
74
+ if output == "json":
75
+ print_json(items)
76
+ else:
77
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
78
+
79
+
80
+
81
+ @app.command("update")
82
+ def update(
83
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
84
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
85
+ topic: str = typer.Option(None, "--topic", help="Personal Meeting Room topic to be updated."),
86
+ host_pin: str = typer.Option(None, "--host-pin", help="Updated PIN for joining the room as host. The host PIN must"),
87
+ enabled_auto_lock: bool = typer.Option(None, "--enabled-auto-lock/--no-enabled-auto-lock", help="Update for option to automatically lock the Personal Room a"),
88
+ auto_lock_minutes: str = typer.Option(None, "--auto-lock-minutes", help="Updated number of minutes after which the Personal Room is l"),
89
+ enabled_notify_host: bool = typer.Option(None, "--enabled-notify-host/--no-enabled-notify-host", help="Update for flag to enable notifying the owner of a Personal"),
90
+ support_co_host: bool = typer.Option(None, "--support-co-host/--no-support-co-host", help="Update for flag allowing other invitees to host a meetingCoH"),
91
+ support_anyone_as_co_host: bool = typer.Option(None, "--support-anyone-as-co-host/--no-support-anyone-as-co-host", help="Whether or not to allow any attendee with a host account on"),
92
+ allow_first_user_to_be_co_host: bool = typer.Option(None, "--allow-first-user-to-be-co-host/--no-allow-first-user-to-be-co-host", help="Whether or not to allow the first attendee with a host accou"),
93
+ allow_authenticated_devices: bool = typer.Option(None, "--allow-authenticated-devices/--no-allow-authenticated-devices", help="Whether or not to allow authenticated video devices in the u"),
94
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
95
+ debug: bool = typer.Option(False, "--debug"),
96
+ ):
97
+ """Update Personal Meeting Room Options\n\nExample --json-body:\n '{"topic":"...","hostPin":"...","enabledAutoLock":true,"autoLockMinutes":0,"enabledNotifyHost":true,"supportCoHost":true,"coHosts":[{"email":"...","displayName":"..."}],"supportAnyoneAsCoHost":true}'."""
98
+ api = get_api(debug=debug)
99
+ url = f"https://webexapis.com/v1/meetingPreferences/personalMeetingRoom"
100
+ params = {}
101
+ if user_email is not None:
102
+ params["userEmail"] = user_email
103
+ if site_url is not None:
104
+ params["siteUrl"] = site_url
105
+ if json_body:
106
+ body = json.loads(json_body)
107
+ else:
108
+ body = {}
109
+ if topic is not None:
110
+ body["topic"] = topic
111
+ if host_pin is not None:
112
+ body["hostPin"] = host_pin
113
+ if enabled_auto_lock is not None:
114
+ body["enabledAutoLock"] = enabled_auto_lock
115
+ if auto_lock_minutes is not None:
116
+ body["autoLockMinutes"] = auto_lock_minutes
117
+ if enabled_notify_host is not None:
118
+ body["enabledNotifyHost"] = enabled_notify_host
119
+ if support_co_host is not None:
120
+ body["supportCoHost"] = support_co_host
121
+ if support_anyone_as_co_host is not None:
122
+ body["supportAnyoneAsCoHost"] = support_anyone_as_co_host
123
+ if allow_first_user_to_be_co_host is not None:
124
+ body["allowFirstUserToBeCoHost"] = allow_first_user_to_be_co_host
125
+ if allow_authenticated_devices is not None:
126
+ body["allowAuthenticatedDevices"] = allow_authenticated_devices
127
+ try:
128
+ result = api.session.rest_put(url, json=body, params=params)
129
+ except WebexError as e:
130
+ handle_rest_error(e)
131
+ typer.echo(f"Updated.")
132
+
133
+
134
+
135
+ @app.command("show")
136
+ def show(
137
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
138
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
139
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
140
+ debug: bool = typer.Option(False, "--debug"),
141
+ ):
142
+ """Get Audio Options."""
143
+ api = get_api(debug=debug)
144
+ url = f"https://webexapis.com/v1/meetingPreferences/audio"
145
+ params = {}
146
+ if user_email is not None:
147
+ params["userEmail"] = user_email
148
+ if site_url is not None:
149
+ params["siteUrl"] = site_url
150
+ try:
151
+ result = api.session.rest_get(url, params=params)
152
+ except WebexError as e:
153
+ handle_rest_error(e)
154
+ if output == "json":
155
+ print_json(result)
156
+ else:
157
+ if isinstance(result, dict):
158
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
159
+ elif isinstance(result, list):
160
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
161
+ else:
162
+ print_json(result)
163
+
164
+
165
+
166
+ @app.command("update-audio")
167
+ def update_audio(
168
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
169
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
170
+ default_audio_type: str = typer.Option(None, "--default-audio-type", help="Choices: webexAudio, voipOnly, otherTeleconferenceService, none"),
171
+ other_teleconference_description: str = typer.Option(None, "--other-teleconference-description", help="Phone number and other information for the teleconference pr"),
172
+ enabled_global_call_in: bool = typer.Option(None, "--enabled-global-call-in/--no-enabled-global-call-in", help="Flag to enable/disable global call ins. ***Note***: If the s"),
173
+ enabled_toll_free: bool = typer.Option(None, "--enabled-toll-free/--no-enabled-toll-free", help="Flag to enable/disable call-ins from toll-free numbers. ***"),
174
+ enabled_auto_connection: bool = typer.Option(None, "--enabled-auto-connection/--no-enabled-auto-connection", help="Flag to enable/disable automatically connecting to audio usi"),
175
+ audio_pin: str = typer.Option(None, "--audio-pin", help="PIN to provide a secondary level of authentication for calls"),
176
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
177
+ debug: bool = typer.Option(False, "--debug"),
178
+ ):
179
+ """Update Audio Options\n\nExample --json-body:\n '{"defaultAudioType":"webexAudio","otherTeleconferenceDescription":"...","enabledGlobalCallIn":true,"enabledTollFree":true,"enabledAutoConnection":true,"officeNumber":{"countryCode":"...","number":"...","enabledCallInAuthentication":true,"enabledCallMe":true},"mobileNumber":{"countryCode":"...","number":"...","enabledCallInAuthentication":true,"enabledCallMe":true},"audioPin":"..."}'."""
180
+ api = get_api(debug=debug)
181
+ url = f"https://webexapis.com/v1/meetingPreferences/audio"
182
+ params = {}
183
+ if user_email is not None:
184
+ params["userEmail"] = user_email
185
+ if site_url is not None:
186
+ params["siteUrl"] = site_url
187
+ if json_body:
188
+ body = json.loads(json_body)
189
+ else:
190
+ body = {}
191
+ if default_audio_type is not None:
192
+ body["defaultAudioType"] = default_audio_type
193
+ if other_teleconference_description is not None:
194
+ body["otherTeleconferenceDescription"] = other_teleconference_description
195
+ if enabled_global_call_in is not None:
196
+ body["enabledGlobalCallIn"] = enabled_global_call_in
197
+ if enabled_toll_free is not None:
198
+ body["enabledTollFree"] = enabled_toll_free
199
+ if enabled_auto_connection is not None:
200
+ body["enabledAutoConnection"] = enabled_auto_connection
201
+ if audio_pin is not None:
202
+ body["audioPin"] = audio_pin
203
+ try:
204
+ result = api.session.rest_put(url, json=body, params=params)
205
+ except WebexError as e:
206
+ handle_rest_error(e)
207
+ typer.echo(f"Updated.")
208
+
209
+
210
+
211
+ @app.command("list-video")
212
+ def list_video(
213
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
214
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
215
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
216
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
217
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
218
+ debug: bool = typer.Option(False, "--debug"),
219
+ ):
220
+ """Get Video Options."""
221
+ api = get_api(debug=debug)
222
+ url = f"https://webexapis.com/v1/meetingPreferences/video"
223
+ params = {}
224
+ if user_email is not None:
225
+ params["userEmail"] = user_email
226
+ if site_url is not None:
227
+ params["siteUrl"] = site_url
228
+ if limit > 0:
229
+ params["max"] = limit
230
+ if offset > 0:
231
+ params["start"] = offset
232
+ result = None
233
+ try:
234
+ result = api.session.rest_get(url, params=params)
235
+ except WebexError as e:
236
+ handle_rest_error(e)
237
+ result = result or []
238
+ items = result.get("videoDevices", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
239
+ if output == "json":
240
+ print_json(items)
241
+ else:
242
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
243
+
244
+
245
+
246
+ @app.command("update-video")
247
+ def update_video(
248
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
249
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
250
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
251
+ debug: bool = typer.Option(False, "--debug"),
252
+ ):
253
+ """Update Video Options\n\nExample --json-body:\n '{"videoDevices":[{"deviceName":"...","deviceAddress":"...","isDefault":"..."}]}'."""
254
+ api = get_api(debug=debug)
255
+ url = f"https://webexapis.com/v1/meetingPreferences/video"
256
+ params = {}
257
+ if user_email is not None:
258
+ params["userEmail"] = user_email
259
+ if site_url is not None:
260
+ params["siteUrl"] = site_url
261
+ if json_body:
262
+ body = json.loads(json_body)
263
+ else:
264
+ body = {}
265
+ try:
266
+ result = api.session.rest_put(url, json=body, params=params)
267
+ except WebexError as e:
268
+ handle_rest_error(e)
269
+ typer.echo(f"Updated.")
270
+
271
+
272
+
273
+ @app.command("list-scheduling-options")
274
+ def list_scheduling_options(
275
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
276
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
277
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
278
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
279
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
280
+ debug: bool = typer.Option(False, "--debug"),
281
+ ):
282
+ """Get Scheduling Options."""
283
+ api = get_api(debug=debug)
284
+ url = f"https://webexapis.com/v1/meetingPreferences/schedulingOptions"
285
+ params = {}
286
+ if user_email is not None:
287
+ params["userEmail"] = user_email
288
+ if site_url is not None:
289
+ params["siteUrl"] = site_url
290
+ if limit > 0:
291
+ params["max"] = limit
292
+ if offset > 0:
293
+ params["start"] = offset
294
+ result = None
295
+ try:
296
+ result = api.session.rest_get(url, params=params)
297
+ except WebexError as e:
298
+ handle_rest_error(e)
299
+ result = result or []
300
+ items = result.get("delegateEmails", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
301
+ if output == "json":
302
+ print_json(items)
303
+ else:
304
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
305
+
306
+
307
+
308
+ @app.command("update-scheduling-options")
309
+ def update_scheduling_options(
310
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
311
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
312
+ enabled_join_before_host: bool = typer.Option(None, "--enabled-join-before-host/--no-enabled-join-before-host", help="Flag to enable/disable ***Join Before Host***. The period du"),
313
+ join_before_host_minutes: str = typer.Option(None, "--join-before-host-minutes", help="Number of minutes before the start time that an invitee can"),
314
+ enabled_auto_share_recording: bool = typer.Option(None, "--enabled-auto-share-recording/--no-enabled-auto-share-recording", help="Flag to enable/disable the automatic sharing of the meeting"),
315
+ enabled_webex_assistant_by_default: bool = typer.Option(None, "--enabled-webex-assistant-by-default/--no-enabled-webex-assistant-by-default", help="Flag to automatically enable Webex Assistant whenever you st"),
316
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
317
+ debug: bool = typer.Option(False, "--debug"),
318
+ ):
319
+ """Update Scheduling Options\n\nExample --json-body:\n '{"enabledJoinBeforeHost":true,"joinBeforeHostMinutes":0,"enabledAutoShareRecording":true,"enabledWebexAssistantByDefault":true,"delegateEmails":["..."]}'."""
320
+ api = get_api(debug=debug)
321
+ url = f"https://webexapis.com/v1/meetingPreferences/schedulingOptions"
322
+ params = {}
323
+ if user_email is not None:
324
+ params["userEmail"] = user_email
325
+ if site_url is not None:
326
+ params["siteUrl"] = site_url
327
+ if json_body:
328
+ body = json.loads(json_body)
329
+ else:
330
+ body = {}
331
+ if enabled_join_before_host is not None:
332
+ body["enabledJoinBeforeHost"] = enabled_join_before_host
333
+ if join_before_host_minutes is not None:
334
+ body["joinBeforeHostMinutes"] = join_before_host_minutes
335
+ if enabled_auto_share_recording is not None:
336
+ body["enabledAutoShareRecording"] = enabled_auto_share_recording
337
+ if enabled_webex_assistant_by_default is not None:
338
+ body["enabledWebexAssistantByDefault"] = enabled_webex_assistant_by_default
339
+ try:
340
+ result = api.session.rest_put(url, json=body, params=params)
341
+ except WebexError as e:
342
+ handle_rest_error(e)
343
+ typer.echo(f"Updated.")
344
+
345
+
346
+
347
+ @app.command("create")
348
+ def create(
349
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
350
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
351
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
352
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
353
+ debug: bool = typer.Option(False, "--debug"),
354
+ ):
355
+ """Insert Delegate Emails\n\nExample --json-body:\n '{"emails":["..."]}'."""
356
+ api = get_api(debug=debug)
357
+ url = f"https://webexapis.com/v1/meetingPreferences/schedulingOptions/delegateEmails/insert"
358
+ params = {}
359
+ if user_email is not None:
360
+ params["userEmail"] = user_email
361
+ if site_url is not None:
362
+ params["siteUrl"] = site_url
363
+ if json_body:
364
+ body = json.loads(json_body)
365
+ else:
366
+ body = {}
367
+ try:
368
+ result = api.session.rest_post(url, json=body, params=params)
369
+ except WebexError as e:
370
+ handle_rest_error(e)
371
+ if output == "json":
372
+ print_json(result)
373
+ elif isinstance(result, dict) and "id" in result:
374
+ typer.echo(f"Created: {result['id']}")
375
+ elif not result or result == {}:
376
+ typer.echo("Created.")
377
+ else:
378
+ print_json(result)
379
+
380
+
381
+
382
+ @app.command("create-delete")
383
+ def create_delete(
384
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
385
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. For individual use, if `site"),
386
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
387
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
388
+ debug: bool = typer.Option(False, "--debug"),
389
+ ):
390
+ """Delete Delegate Emails\n\nExample --json-body:\n '{"emails":["..."]}'."""
391
+ api = get_api(debug=debug)
392
+ url = f"https://webexapis.com/v1/meetingPreferences/schedulingOptions/delegateEmails/delete"
393
+ params = {}
394
+ if user_email is not None:
395
+ params["userEmail"] = user_email
396
+ if site_url is not None:
397
+ params["siteUrl"] = site_url
398
+ if json_body:
399
+ body = json.loads(json_body)
400
+ else:
401
+ body = {}
402
+ try:
403
+ result = api.session.rest_post(url, json=body, params=params)
404
+ except WebexError as e:
405
+ handle_rest_error(e)
406
+ if output == "json":
407
+ print_json(result)
408
+ elif isinstance(result, dict) and "id" in result:
409
+ typer.echo(f"Created: {result['id']}")
410
+ elif not result or result == {}:
411
+ typer.echo("Created.")
412
+ else:
413
+ print_json(result)
414
+
415
+
416
+
417
+ @app.command("list-sites")
418
+ def list_sites(
419
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
420
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site to query. If `siteUrl` is not specifie"),
421
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
422
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
423
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
424
+ debug: bool = typer.Option(False, "--debug"),
425
+ ):
426
+ """Get Site List."""
427
+ api = get_api(debug=debug)
428
+ url = f"https://webexapis.com/v1/meetingPreferences/sites"
429
+ params = {}
430
+ if user_email is not None:
431
+ params["userEmail"] = user_email
432
+ if site_url is not None:
433
+ params["siteUrl"] = site_url
434
+ if limit > 0:
435
+ params["max"] = limit
436
+ if offset > 0:
437
+ params["start"] = offset
438
+ result = None
439
+ try:
440
+ result = api.session.rest_get(url, params=params)
441
+ except WebexError as e:
442
+ handle_rest_error(e)
443
+ result = result or []
444
+ items = result.get("sites", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
445
+ if output == "json":
446
+ print_json(items)
447
+ else:
448
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
449
+
450
+
451
+
452
+ @app.command("update-sites")
453
+ def update_sites(
454
+ default_site: str = typer.Option(..., "--default-site", help="Whether or not to change user's default site. ***Note***: `d"),
455
+ user_email: str = typer.Option(None, "--user-email", help="Email address for the user. This parameter is only used if t"),
456
+ site_url: str = typer.Option(None, "--site-url", help="Access URL for the site."),
457
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
458
+ debug: bool = typer.Option(False, "--debug"),
459
+ ):
460
+ """Update Default Site."""
461
+ api = get_api(debug=debug)
462
+ url = f"https://webexapis.com/v1/meetingPreferences/sites"
463
+ params = {}
464
+ if default_site is not None:
465
+ params["defaultSite"] = default_site
466
+ if user_email is not None:
467
+ params["userEmail"] = user_email
468
+ if json_body:
469
+ body = json.loads(json_body)
470
+ else:
471
+ body = {}
472
+ if site_url is not None:
473
+ body["siteUrl"] = site_url
474
+ try:
475
+ result = api.session.rest_put(url, json=body, params=params)
476
+ except WebexError as e:
477
+ handle_rest_error(e)
478
+ typer.echo(f"Updated.")
479
+
480
+
481
+
482
+ @app.command("create-refresh-id")
483
+ def create_refresh_id(
484
+ site_url: str = typer.Option(None, "--site-url", help="(required) Site URL to refresh the personal room IDs."),
485
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
486
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
487
+ debug: bool = typer.Option(False, "--debug"),
488
+ ):
489
+ """Batch Refresh Personal Meeting Room ID\n\nExample --json-body:\n '{"siteUrl":"...","personalMeetingRoomIds":[{"email":"...","personId":"...","systemGenerated":"...","personalMeetingRoomId":"..."}]}'."""
490
+ api = get_api(debug=debug)
491
+ url = f"https://webexapis.com/v1/admin/meetingPreferences/personalMeetingRoom/refreshId"
492
+ if json_body:
493
+ body = json.loads(json_body)
494
+ else:
495
+ body = {}
496
+ if site_url is not None:
497
+ body["siteUrl"] = site_url
498
+ _missing = [f for f in ['siteUrl'] if f not in body or body[f] is None]
499
+ if _missing:
500
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
501
+ raise typer.Exit(1)
502
+ try:
503
+ result = api.session.rest_post(url, json=body)
504
+ except WebexError as e:
505
+ handle_rest_error(e)
506
+ if output == "json":
507
+ print_json(result)
508
+ elif isinstance(result, dict) and "id" in result:
509
+ typer.echo(f"Created: {result['id']}")
510
+ elif not result or result == {}:
511
+ typer.echo("Created.")
512
+ else:
513
+ print_json(result)
514
+
515
+
@@ -0,0 +1,78 @@
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 Meetings meeting-qa.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ meeting_id: str = typer.Option(..., "--meeting-id", help="A unique identifier for the [meeting instance](/docs/meeting"),
14
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
15
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
16
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
17
+ debug: bool = typer.Option(False, "--debug"),
18
+ ):
19
+ """List Meeting Q and A."""
20
+ api = get_api(debug=debug)
21
+ url = f"https://webexapis.com/v1/meetings/q_and_a"
22
+ params = {}
23
+ if meeting_id is not None:
24
+ params["meetingId"] = meeting_id
25
+ if limit > 0:
26
+ params["max"] = limit
27
+ if offset > 0:
28
+ params["start"] = offset
29
+ try:
30
+ if limit > 0:
31
+ result = api.session.rest_get(url, params=params)
32
+ result = result or {}
33
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
34
+ else:
35
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
36
+ except WebexError as e:
37
+ handle_rest_error(e)
38
+ if output == "json":
39
+ print_json(items)
40
+ else:
41
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
42
+
43
+
44
+
45
+ @app.command("list-answers")
46
+ def list_answers(
47
+ question_id: str = typer.Argument(help="questionId"),
48
+ meeting_id: str = typer.Option(..., "--meeting-id", help="A unique identifier for the [meeting instance](/docs/meeting"),
49
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
50
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
51
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
52
+ debug: bool = typer.Option(False, "--debug"),
53
+ ):
54
+ """List Answers of a Question."""
55
+ api = get_api(debug=debug)
56
+ url = f"https://webexapis.com/v1/meetings/q_and_a/{question_id}/answers"
57
+ params = {}
58
+ if meeting_id is not None:
59
+ params["meetingId"] = meeting_id
60
+ if limit > 0:
61
+ params["max"] = limit
62
+ if offset > 0:
63
+ params["start"] = offset
64
+ try:
65
+ if limit > 0:
66
+ result = api.session.rest_get(url, params=params)
67
+ result = result or {}
68
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
69
+ else:
70
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
71
+ except WebexError as e:
72
+ handle_rest_error(e)
73
+ if output == "json":
74
+ print_json(items)
75
+ else:
76
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
77
+
78
+
@@ -0,0 +1,43 @@
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 Meetings meeting-qualities.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ meeting_id: str = typer.Option(..., "--meeting-id", help="Unique identifier for the specific meeting instance. **Note:"),
14
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
15
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
16
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
17
+ debug: bool = typer.Option(False, "--debug"),
18
+ ):
19
+ """Get Meeting Qualities."""
20
+ api = get_api(debug=debug)
21
+ url = f"https://webexapis.com/v1/meeting/qualities"
22
+ params = {}
23
+ if meeting_id is not None:
24
+ params["meetingId"] = meeting_id
25
+ if limit > 0:
26
+ params["max"] = limit
27
+ if offset > 0:
28
+ params["offset"] = offset
29
+ try:
30
+ if limit > 0:
31
+ result = api.session.rest_get(url, params=params)
32
+ result = result or {}
33
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
34
+ else:
35
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
36
+ except WebexError as e:
37
+ handle_rest_error(e)
38
+ if output == "json":
39
+ print_json(items)
40
+ else:
41
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
42
+
43
+