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,585 @@
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 admin-recordings.")
9
+
10
+
11
+ @app.command("list")
12
+ def cmd_list(
13
+ from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recordings to return,"),
14
+ to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for List recordings to retu"),
15
+ meeting_id: str = typer.Option(None, "--meeting-id", help="Unique identifier for the parent meeting series, scheduled m"),
16
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This parameter is only u"),
17
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site from which the API lists recordings. I"),
18
+ integration_tag: str = typer.Option(None, "--integration-tag", help="External key of the parent meeting created by an integration"),
19
+ topic: str = typer.Option(None, "--topic", help="Recording's topic. If specified, the API filters recordings"),
20
+ format_param: str = typer.Option(None, "--format", help="Choices: MP4, ARF"),
21
+ service_type: str = typer.Option(None, "--service-type", help="Choices: MeetingCenter, EventCenter, SupportCenter, TrainingCenter"),
22
+ status: str = typer.Option(None, "--status", help="Choices: available, deleted, purged"),
23
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
24
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
25
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
26
+ debug: bool = typer.Option(False, "--debug"),
27
+ ):
28
+ """List Recordings."""
29
+ api = get_api(debug=debug)
30
+ url = f"https://webexapis.com/v1/recordings"
31
+ params = {}
32
+ if from_param is not None:
33
+ params["from"] = from_param
34
+ if to is not None:
35
+ params["to"] = to
36
+ if meeting_id is not None:
37
+ params["meetingId"] = meeting_id
38
+ if host_email is not None:
39
+ params["hostEmail"] = host_email
40
+ if site_url is not None:
41
+ params["siteUrl"] = site_url
42
+ if integration_tag is not None:
43
+ params["integrationTag"] = integration_tag
44
+ if topic is not None:
45
+ params["topic"] = topic
46
+ if format_param is not None:
47
+ params["format"] = format_param
48
+ if service_type is not None:
49
+ params["serviceType"] = service_type
50
+ if status is not None:
51
+ params["status"] = status
52
+ if limit > 0:
53
+ params["max"] = limit
54
+ if offset > 0:
55
+ params["start"] = offset
56
+ try:
57
+ if limit > 0:
58
+ result = api.session.rest_get(url, params=params)
59
+ result = result or {}
60
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
61
+ else:
62
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
63
+ except WebexError as e:
64
+ handle_rest_error(e)
65
+ if output == "json":
66
+ print_json(items)
67
+ else:
68
+ print_table(items, columns=[('ID', 'id'), ('Topic', 'topic'), ('Format', 'format'), ('Created', 'timeRecorded')], limit=limit)
69
+
70
+
71
+
72
+ @app.command("create")
73
+ def create(
74
+ max: str = typer.Option(None, "--max", help="Maximum number of recordings to return in a single page. `ma"),
75
+ from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recordings to return,"),
76
+ to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for query recordings to ret"),
77
+ meeting_id: str = typer.Option(None, "--meeting-id", help="Unique identifier for the parent meeting series, scheduled m"),
78
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site from which the API lists recordings. I"),
79
+ integration_tag: str = typer.Option(None, "--integration-tag", help="External key of the parent meeting created by an integration"),
80
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This property is only us"),
81
+ topic: str = typer.Option(None, "--topic", help="Recording's topic. If specified, the API filters recordings"),
82
+ format_param: str = typer.Option(None, "--format", help="Choices: MP4, ARF"),
83
+ service_type: str = typer.Option(None, "--service-type", help="Choices: MeetingCenter, EventCenter, SupportCenter, TrainingCenter"),
84
+ status: str = typer.Option(None, "--status", help="Choices: available, deleted, purged"),
85
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
86
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
87
+ debug: bool = typer.Option(False, "--debug"),
88
+ ):
89
+ """Query Recordings."""
90
+ api = get_api(debug=debug)
91
+ url = f"https://webexapis.com/v1/recordings/query"
92
+ if json_body:
93
+ body = json.loads(json_body)
94
+ else:
95
+ body = {}
96
+ if max is not None:
97
+ body["max"] = max
98
+ if from_param is not None:
99
+ body["from"] = from_param
100
+ if to is not None:
101
+ body["to"] = to
102
+ if meeting_id is not None:
103
+ body["meetingId"] = meeting_id
104
+ if site_url is not None:
105
+ body["siteUrl"] = site_url
106
+ if integration_tag is not None:
107
+ body["integrationTag"] = integration_tag
108
+ if host_email is not None:
109
+ body["hostEmail"] = host_email
110
+ if topic is not None:
111
+ body["topic"] = topic
112
+ if format_param is not None:
113
+ body["format"] = format_param
114
+ if service_type is not None:
115
+ body["serviceType"] = service_type
116
+ if status is not None:
117
+ body["status"] = status
118
+ try:
119
+ result = api.session.rest_post(url, json=body)
120
+ except WebexError as e:
121
+ handle_rest_error(e)
122
+ if output == "json":
123
+ print_json(result)
124
+ elif isinstance(result, dict) and "id" in result:
125
+ typer.echo(f"Created: {result['id']}")
126
+ elif not result or result == {}:
127
+ typer.echo("Created.")
128
+ else:
129
+ print_json(result)
130
+
131
+
132
+
133
+ @app.command("list-recordings-admin")
134
+ def list_recordings_admin(
135
+ from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recordings to return,"),
136
+ to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for List recordings to retu"),
137
+ meeting_id: str = typer.Option(None, "--meeting-id", help="Unique identifier for the parent meeting series, scheduled m"),
138
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site which the API lists recordings from. I"),
139
+ integration_tag: str = typer.Option(None, "--integration-tag", help="External key of the parent meeting created by an integration"),
140
+ topic: str = typer.Option(None, "--topic", help="Recording topic. If specified, the API filters recordings by"),
141
+ format_param: str = typer.Option(None, "--format", help="Choices: MP4, ARF"),
142
+ service_type: str = typer.Option(None, "--service-type", help="Choices: MeetingCenter, EventCenter, SupportCenter, TrainingCenter"),
143
+ status: str = typer.Option(None, "--status", help="Choices: available, deleted, purged"),
144
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
145
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
146
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
147
+ debug: bool = typer.Option(False, "--debug"),
148
+ ):
149
+ """List Recordings For an Admin or Compliance Officer."""
150
+ api = get_api(debug=debug)
151
+ url = f"https://webexapis.com/v1/admin/recordings"
152
+ params = {}
153
+ if from_param is not None:
154
+ params["from"] = from_param
155
+ if to is not None:
156
+ params["to"] = to
157
+ if meeting_id is not None:
158
+ params["meetingId"] = meeting_id
159
+ if site_url is not None:
160
+ params["siteUrl"] = site_url
161
+ if integration_tag is not None:
162
+ params["integrationTag"] = integration_tag
163
+ if topic is not None:
164
+ params["topic"] = topic
165
+ if format_param is not None:
166
+ params["format"] = format_param
167
+ if service_type is not None:
168
+ params["serviceType"] = service_type
169
+ if status is not None:
170
+ params["status"] = status
171
+ if limit > 0:
172
+ params["max"] = limit
173
+ if offset > 0:
174
+ params["start"] = offset
175
+ try:
176
+ if limit > 0:
177
+ result = api.session.rest_get(url, params=params)
178
+ result = result or {}
179
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
180
+ else:
181
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
182
+ except WebexError as e:
183
+ handle_rest_error(e)
184
+ if output == "json":
185
+ print_json(items)
186
+ else:
187
+ print_table(items, columns=[('ID', 'id'), ('Topic', 'topic'), ('Format', 'format'), ('Created', 'timeRecorded')], limit=limit)
188
+
189
+
190
+
191
+ @app.command("create-query")
192
+ def create_query(
193
+ max: str = typer.Option(None, "--max", help="Maximum number of recordings to return in a single page. `ma"),
194
+ from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recordings to return,"),
195
+ to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for query recordings to ret"),
196
+ meeting_id: str = typer.Option(None, "--meeting-id", help="Unique identifier for the parent meeting series, scheduled m"),
197
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site which the API lists recordings from. I"),
198
+ integration_tag: str = typer.Option(None, "--integration-tag", help="External key of the parent meeting created by an integration"),
199
+ topic: str = typer.Option(None, "--topic", help="Recording topic. If specified, the API filters recordings by"),
200
+ format_param: str = typer.Option(None, "--format", help="Choices: MP4, ARF"),
201
+ service_type: str = typer.Option(None, "--service-type", help="Choices: MeetingCenter, EventCenter, SupportCenter, TrainingCenter"),
202
+ status: str = typer.Option(None, "--status", help="Choices: available, deleted, purged"),
203
+ timezone: str = typer.Option(None, "--timezone", help="Optional timezone override for the request (if not provided,"),
204
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
205
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
206
+ debug: bool = typer.Option(False, "--debug"),
207
+ ):
208
+ """Query Recordings For an Admin or Compliance Officer."""
209
+ api = get_api(debug=debug)
210
+ url = f"https://webexapis.com/v1/admin/recordings/query"
211
+ if json_body:
212
+ body = json.loads(json_body)
213
+ else:
214
+ body = {}
215
+ if max is not None:
216
+ body["max"] = max
217
+ if from_param is not None:
218
+ body["from"] = from_param
219
+ if to is not None:
220
+ body["to"] = to
221
+ if meeting_id is not None:
222
+ body["meetingId"] = meeting_id
223
+ if site_url is not None:
224
+ body["siteUrl"] = site_url
225
+ if integration_tag is not None:
226
+ body["integrationTag"] = integration_tag
227
+ if topic is not None:
228
+ body["topic"] = topic
229
+ if format_param is not None:
230
+ body["format"] = format_param
231
+ if service_type is not None:
232
+ body["serviceType"] = service_type
233
+ if status is not None:
234
+ body["status"] = status
235
+ if timezone is not None:
236
+ body["timezone"] = timezone
237
+ try:
238
+ result = api.session.rest_post(url, json=body)
239
+ except WebexError as e:
240
+ handle_rest_error(e)
241
+ if output == "json":
242
+ print_json(result)
243
+ elif isinstance(result, dict) and "id" in result:
244
+ typer.echo(f"Created: {result['id']}")
245
+ elif not result or result == {}:
246
+ typer.echo("Created.")
247
+ else:
248
+ print_json(result)
249
+
250
+
251
+
252
+ @app.command("delete")
253
+ def delete(
254
+ recording_id: str = typer.Argument(help="recordingId"),
255
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
256
+ debug: bool = typer.Option(False, "--debug"),
257
+ ):
258
+ """Delete a Recording By an Admin."""
259
+ if not force:
260
+ typer.confirm(f"Delete {recording_id}?", abort=True)
261
+ api = get_api(debug=debug)
262
+ url = f"https://webexapis.com/v1/admin/recordings/{recording_id}"
263
+ try:
264
+ api.session.rest_delete(url)
265
+ except WebexError as e:
266
+ handle_rest_error(e)
267
+ typer.echo(f"Deleted: {recording_id}")
268
+
269
+
270
+
271
+ @app.command("show")
272
+ def show(
273
+ recording_id: str = typer.Argument(help="recordingId"),
274
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. Only used if the user or"),
275
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
276
+ debug: bool = typer.Option(False, "--debug"),
277
+ ):
278
+ """Get Recording Details."""
279
+ api = get_api(debug=debug)
280
+ url = f"https://webexapis.com/v1/recordings/{recording_id}"
281
+ params = {}
282
+ if host_email is not None:
283
+ params["hostEmail"] = host_email
284
+ try:
285
+ result = api.session.rest_get(url, params=params)
286
+ except WebexError as e:
287
+ handle_rest_error(e)
288
+ if output == "json":
289
+ print_json(result)
290
+ else:
291
+ if isinstance(result, dict):
292
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
293
+ elif isinstance(result, list):
294
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
295
+ else:
296
+ print_json(result)
297
+
298
+
299
+
300
+ @app.command("delete-recordings")
301
+ def delete_recordings(
302
+ recording_id: str = typer.Argument(help="recordingId"),
303
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. Only used if the user or"),
304
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
305
+ debug: bool = typer.Option(False, "--debug"),
306
+ ):
307
+ """Delete a Recording."""
308
+ if not force:
309
+ typer.confirm(f"Delete {recording_id}?", abort=True)
310
+ api = get_api(debug=debug)
311
+ url = f"https://webexapis.com/v1/recordings/{recording_id}"
312
+ params = {}
313
+ if host_email is not None:
314
+ params["hostEmail"] = host_email
315
+ try:
316
+ api.session.rest_delete(url, params=params)
317
+ except WebexError as e:
318
+ handle_rest_error(e)
319
+ typer.echo(f"Deleted: {recording_id}")
320
+
321
+
322
+
323
+ @app.command("create-soft-delete")
324
+ def create_soft_delete(
325
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. Only used if the user or"),
326
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site from which the API deletes recordings."),
327
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
328
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
329
+ debug: bool = typer.Option(False, "--debug"),
330
+ ):
331
+ """Move Recordings into the Recycle Bin\n\nExample --json-body:\n '{"recordingIds":["..."],"siteUrl":"..."}'."""
332
+ api = get_api(debug=debug)
333
+ url = f"https://webexapis.com/v1/recordings/softDelete"
334
+ params = {}
335
+ if host_email is not None:
336
+ params["hostEmail"] = host_email
337
+ if json_body:
338
+ body = json.loads(json_body)
339
+ else:
340
+ body = {}
341
+ if site_url is not None:
342
+ body["siteUrl"] = site_url
343
+ try:
344
+ result = api.session.rest_post(url, json=body, params=params)
345
+ except WebexError as e:
346
+ handle_rest_error(e)
347
+ if output == "json":
348
+ print_json(result)
349
+ elif isinstance(result, dict) and "id" in result:
350
+ typer.echo(f"Created: {result['id']}")
351
+ elif not result or result == {}:
352
+ typer.echo("Created.")
353
+ else:
354
+ print_json(result)
355
+
356
+
357
+
358
+ @app.command("create-restore")
359
+ def create_restore(
360
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This parameter is only u"),
361
+ restore_all: bool = typer.Option(None, "--restore-all/--no-restore-all", help="If not specified or `false`, restores the recordings specifi"),
362
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site from which the API restores recordings"),
363
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
364
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
365
+ debug: bool = typer.Option(False, "--debug"),
366
+ ):
367
+ """Restore Recordings from Recycle Bin\n\nExample --json-body:\n '{"restoreAll":true,"recordingIds":["..."],"siteUrl":"..."}'."""
368
+ api = get_api(debug=debug)
369
+ url = f"https://webexapis.com/v1/recordings/restore"
370
+ params = {}
371
+ if host_email is not None:
372
+ params["hostEmail"] = host_email
373
+ if json_body:
374
+ body = json.loads(json_body)
375
+ else:
376
+ body = {}
377
+ if restore_all is not None:
378
+ body["restoreAll"] = restore_all
379
+ if site_url is not None:
380
+ body["siteUrl"] = site_url
381
+ try:
382
+ result = api.session.rest_post(url, json=body, params=params)
383
+ except WebexError as e:
384
+ handle_rest_error(e)
385
+ if output == "json":
386
+ print_json(result)
387
+ elif isinstance(result, dict) and "id" in result:
388
+ typer.echo(f"Created: {result['id']}")
389
+ elif not result or result == {}:
390
+ typer.echo("Created.")
391
+ else:
392
+ print_json(result)
393
+
394
+
395
+
396
+ @app.command("create-purge")
397
+ def create_purge(
398
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. Only used if the user or"),
399
+ purge_all: bool = typer.Option(None, "--purge-all/--no-purge-all", help="If not specified or `false`, purges the recordings specified"),
400
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site from which the API purges recordings."),
401
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
402
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
403
+ debug: bool = typer.Option(False, "--debug"),
404
+ ):
405
+ """Purge Recordings from Recycle Bin\n\nExample --json-body:\n '{"purgeAll":true,"recordingIds":["..."],"siteUrl":"..."}'."""
406
+ api = get_api(debug=debug)
407
+ url = f"https://webexapis.com/v1/recordings/purge"
408
+ params = {}
409
+ if host_email is not None:
410
+ params["hostEmail"] = host_email
411
+ if json_body:
412
+ body = json.loads(json_body)
413
+ else:
414
+ body = {}
415
+ if purge_all is not None:
416
+ body["purgeAll"] = purge_all
417
+ if site_url is not None:
418
+ body["siteUrl"] = site_url
419
+ try:
420
+ result = api.session.rest_post(url, json=body, params=params)
421
+ except WebexError as e:
422
+ handle_rest_error(e)
423
+ if output == "json":
424
+ print_json(result)
425
+ elif isinstance(result, dict) and "id" in result:
426
+ typer.echo(f"Created: {result['id']}")
427
+ elif not result or result == {}:
428
+ typer.echo("Created.")
429
+ else:
430
+ print_json(result)
431
+
432
+
433
+
434
+ @app.command("create-access-list-recordings")
435
+ def create_access_list_recordings(
436
+ recording_id: str = typer.Argument(help="recordingId"),
437
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This attribute should on"),
438
+ send_email: bool = typer.Option(None, "--send-email/--no-send-email", help="Whether to send email notifications to the users being share"),
439
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
440
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
441
+ debug: bool = typer.Option(False, "--debug"),
442
+ ):
443
+ """Share a Recording\n\nExample --json-body:\n '{"hostEmail":"...","addEmails":["..."],"removeEmails":["..."],"sendEmail":true}'."""
444
+ api = get_api(debug=debug)
445
+ url = f"https://webexapis.com/v1/recordings/{recording_id}/accessList"
446
+ if json_body:
447
+ body = json.loads(json_body)
448
+ else:
449
+ body = {}
450
+ if host_email is not None:
451
+ body["hostEmail"] = host_email
452
+ if send_email is not None:
453
+ body["sendEmail"] = send_email
454
+ try:
455
+ result = api.session.rest_post(url, json=body)
456
+ except WebexError as e:
457
+ handle_rest_error(e)
458
+ if output == "json":
459
+ print_json(result)
460
+ elif isinstance(result, dict) and "id" in result:
461
+ typer.echo(f"Created: {result['id']}")
462
+ elif not result or result == {}:
463
+ typer.echo("Created.")
464
+ else:
465
+ print_json(result)
466
+
467
+
468
+
469
+ @app.command("create-access-list-recordings-1")
470
+ def create_access_list_recordings_1(
471
+ host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This attribute should on"),
472
+ web_share_link: str = typer.Option(None, "--web-share-link", help="The link for the recording to be shared or unshared."),
473
+ send_email: bool = typer.Option(None, "--send-email/--no-send-email", help="Whether to send email notifications to the users being share"),
474
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
475
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
476
+ debug: bool = typer.Option(False, "--debug"),
477
+ ):
478
+ """Share a Recording Link\n\nExample --json-body:\n '{"hostEmail":"...","webShareLink":"...","addEmails":["..."],"removeEmails":["..."],"sendEmail":true}'."""
479
+ api = get_api(debug=debug)
480
+ url = f"https://webexapis.com/v1/recordings/accessList"
481
+ if json_body:
482
+ body = json.loads(json_body)
483
+ else:
484
+ body = {}
485
+ if host_email is not None:
486
+ body["hostEmail"] = host_email
487
+ if web_share_link is not None:
488
+ body["webShareLink"] = web_share_link
489
+ if send_email is not None:
490
+ body["sendEmail"] = send_email
491
+ try:
492
+ result = api.session.rest_post(url, json=body)
493
+ except WebexError as e:
494
+ handle_rest_error(e)
495
+ if output == "json":
496
+ print_json(result)
497
+ elif isinstance(result, dict) and "id" in result:
498
+ typer.echo(f"Created: {result['id']}")
499
+ elif not result or result == {}:
500
+ typer.echo("Created.")
501
+ else:
502
+ print_json(result)
503
+
504
+
505
+
506
+ @app.command("list-recordings-group")
507
+ def list_recordings_group(
508
+ person_id: str = typer.Option(None, "--person-id", help="Person ID of the user whose recordings will be retrieved. Th"),
509
+ from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recordings to return,"),
510
+ to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for List recordings to retu"),
511
+ site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site which the API lists recordings from. I"),
512
+ integration_tag: str = typer.Option(None, "--integration-tag", help="External key of the parent meeting created by an integration"),
513
+ format_param: str = typer.Option(None, "--format", help="Choices: MP4, ARF"),
514
+ service_type: str = typer.Option(None, "--service-type", help="Choices: MeetingCenter, EventCenter, SupportCenter, TrainingCenter"),
515
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
516
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
517
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
518
+ debug: bool = typer.Option(False, "--debug"),
519
+ ):
520
+ """List Group Recordings."""
521
+ api = get_api(debug=debug)
522
+ url = f"https://webexapis.com/v1/group/recordings"
523
+ params = {}
524
+ if person_id is not None:
525
+ params["personId"] = person_id
526
+ if from_param is not None:
527
+ params["from"] = from_param
528
+ if to is not None:
529
+ params["to"] = to
530
+ if site_url is not None:
531
+ params["siteUrl"] = site_url
532
+ if integration_tag is not None:
533
+ params["integrationTag"] = integration_tag
534
+ if format_param is not None:
535
+ params["format"] = format_param
536
+ if service_type is not None:
537
+ params["serviceType"] = service_type
538
+ if limit > 0:
539
+ params["max"] = limit
540
+ if offset > 0:
541
+ params["start"] = offset
542
+ try:
543
+ if limit > 0:
544
+ result = api.session.rest_get(url, params=params)
545
+ result = result or {}
546
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
547
+ else:
548
+ items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
549
+ except WebexError as e:
550
+ handle_rest_error(e)
551
+ if output == "json":
552
+ print_json(items)
553
+ else:
554
+ print_table(items, columns=[('ID', 'id'), ('Topic', 'topic'), ('Format', 'format'), ('Created', 'timeRecorded')], limit=limit)
555
+
556
+
557
+
558
+ @app.command("show-recordings")
559
+ def show_recordings(
560
+ recording_id: str = typer.Argument(help="recordingId"),
561
+ person_id: str = typer.Option(None, "--person-id", help="Person ID of the user whose recordings will be retrieved. Th"),
562
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
563
+ debug: bool = typer.Option(False, "--debug"),
564
+ ):
565
+ """Get Group Recording Details."""
566
+ api = get_api(debug=debug)
567
+ url = f"https://webexapis.com/v1/group/recordings/{recording_id}"
568
+ params = {}
569
+ if person_id is not None:
570
+ params["personId"] = person_id
571
+ try:
572
+ result = api.session.rest_get(url, params=params)
573
+ except WebexError as e:
574
+ handle_rest_error(e)
575
+ if output == "json":
576
+ print_json(result)
577
+ else:
578
+ if isinstance(result, dict):
579
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
580
+ elif isinstance(result, list):
581
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
582
+ else:
583
+ print_json(result)
584
+
585
+