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,325 @@
1
+ import json
2
+ import typer
3
+ from wxcli.auth import get_api
4
+ from wxcli.errors import WebexError, handle_rest_error
5
+ from wxcli.output import print_table, print_json
6
+ from wxcli.config import resolve_org_id, get_cc_base_url, get_cc_org_id
7
+
8
+
9
+ app = typer.Typer(help="Manage Webex Contact Center cc-team.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
15
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned. By default, all attri"),
16
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
17
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
18
+ single_object_response: str = typer.Option(None, "--single-object-response", help="Specify whether to include array fields in the response. Thi"),
19
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
20
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
21
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
22
+ debug: bool = typer.Option(False, "--debug"),
23
+ ):
24
+ """List Teams."""
25
+ api = get_api(debug=debug)
26
+ cc_base_url = get_cc_base_url()
27
+ orgid = get_cc_org_id(api.session)
28
+ url = f"{cc_base_url}/organization/{orgid}/team"
29
+ params = {}
30
+ if filter_param is not None:
31
+ params["filter"] = filter_param
32
+ if attributes is not None:
33
+ params["attributes"] = attributes
34
+ if page is not None:
35
+ params["page"] = page
36
+ if page_size is not None:
37
+ params["pageSize"] = page_size
38
+ if single_object_response is not None:
39
+ params["singleObjectResponse"] = single_object_response
40
+ if limit > 0:
41
+ params["max"] = limit
42
+ if offset > 0:
43
+ params["start"] = offset
44
+ result = None
45
+ try:
46
+ result = api.session.rest_get(url, params=params)
47
+ except WebexError as e:
48
+ handle_rest_error(e)
49
+ result = result or []
50
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
51
+ if output == "json":
52
+ print_json(items)
53
+ else:
54
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
55
+
56
+
57
+
58
+ @app.command("create")
59
+ def create(
60
+ team_dto: str = typer.Option(..., "--team-dto", help=""),
61
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
62
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
63
+ debug: bool = typer.Option(False, "--debug"),
64
+ ):
65
+ """Create a new Team."""
66
+ api = get_api(debug=debug)
67
+ cc_base_url = get_cc_base_url()
68
+ orgid = get_cc_org_id(api.session)
69
+ url = f"{cc_base_url}/organization/{orgid}/team"
70
+ params = {}
71
+ if team_dto is not None:
72
+ params["teamDTO"] = team_dto
73
+ if json_body:
74
+ body = json.loads(json_body)
75
+ else:
76
+ body = {}
77
+ try:
78
+ result = api.session.rest_post(url, json=body, params=params)
79
+ except WebexError as e:
80
+ handle_rest_error(e)
81
+ if output == "json":
82
+ print_json(result)
83
+ elif isinstance(result, dict) and "id" in result:
84
+ typer.echo(f"Created: {result['id']}")
85
+ elif not result or result == {}:
86
+ typer.echo("Created.")
87
+ else:
88
+ print_json(result)
89
+
90
+
91
+
92
+ @app.command("create-bulk")
93
+ def create_bulk(
94
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
95
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
96
+ debug: bool = typer.Option(False, "--debug"),
97
+ ):
98
+ """Bulk save Teams\n\nExample --json-body:\n '{"items":[{"itemIdentifier":"...","item":"...","requestAction":"..."}]}'."""
99
+ api = get_api(debug=debug)
100
+ cc_base_url = get_cc_base_url()
101
+ orgid = get_cc_org_id(api.session)
102
+ url = f"{cc_base_url}/organization/{orgid}/team/bulk"
103
+ if json_body:
104
+ body = json.loads(json_body)
105
+ else:
106
+ body = {}
107
+ try:
108
+ result = api.session.rest_post(url, json=body)
109
+ except WebexError as e:
110
+ handle_rest_error(e)
111
+ if output == "json":
112
+ print_json(result)
113
+ elif isinstance(result, dict) and "id" in result:
114
+ typer.echo(f"Created: {result['id']}")
115
+ elif not result or result == {}:
116
+ typer.echo("Created.")
117
+ else:
118
+ print_json(result)
119
+
120
+
121
+
122
+ @app.command("create-purge-inactive-entities")
123
+ def create_purge_inactive_entities(
124
+ next_start_id: str = typer.Option(None, "--next-start-id", help="This is the entity ID from which items for the next purge ba"),
125
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
126
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
127
+ debug: bool = typer.Option(False, "--debug"),
128
+ ):
129
+ """Purge inactive Teams."""
130
+ api = get_api(debug=debug)
131
+ cc_base_url = get_cc_base_url()
132
+ orgid = get_cc_org_id(api.session)
133
+ url = f"{cc_base_url}/organization/{orgid}/team/purge-inactive-entities"
134
+ params = {}
135
+ if next_start_id is not None:
136
+ params["nextStartId"] = next_start_id
137
+ if json_body:
138
+ body = json.loads(json_body)
139
+ else:
140
+ body = {}
141
+ try:
142
+ result = api.session.rest_post(url, json=body, params=params)
143
+ except WebexError as e:
144
+ handle_rest_error(e)
145
+ if output == "json":
146
+ print_json(result)
147
+ elif isinstance(result, dict) and "id" in result:
148
+ typer.echo(f"Created: {result['id']}")
149
+ elif not result or result == {}:
150
+ typer.echo("Created.")
151
+ else:
152
+ print_json(result)
153
+
154
+
155
+
156
+ @app.command("show")
157
+ def show(
158
+ id: str = typer.Argument(help="id"),
159
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
160
+ debug: bool = typer.Option(False, "--debug"),
161
+ ):
162
+ """Get specific Team by ID."""
163
+ api = get_api(debug=debug)
164
+ cc_base_url = get_cc_base_url()
165
+ orgid = get_cc_org_id(api.session)
166
+ url = f"{cc_base_url}/organization/{orgid}/team/{id}"
167
+ try:
168
+ result = api.session.rest_get(url)
169
+ except WebexError as e:
170
+ handle_rest_error(e)
171
+ if output == "json":
172
+ print_json(result)
173
+ else:
174
+ if isinstance(result, dict):
175
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
176
+ elif isinstance(result, list):
177
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
178
+ else:
179
+ print_json(result)
180
+
181
+
182
+
183
+ @app.command("update")
184
+ def update(
185
+ id: str = typer.Argument(help="id"),
186
+ team_dto: str = typer.Option(..., "--team-dto", help=""),
187
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
188
+ debug: bool = typer.Option(False, "--debug"),
189
+ ):
190
+ """Update specific Team by ID."""
191
+ api = get_api(debug=debug)
192
+ cc_base_url = get_cc_base_url()
193
+ orgid = get_cc_org_id(api.session)
194
+ url = f"{cc_base_url}/organization/{orgid}/team/{id}"
195
+ params = {}
196
+ if team_dto is not None:
197
+ params["teamDTO"] = team_dto
198
+ if json_body:
199
+ body = json.loads(json_body)
200
+ else:
201
+ body = {}
202
+ try:
203
+ result = api.session.rest_put(url, json=body, params=params)
204
+ except WebexError as e:
205
+ handle_rest_error(e)
206
+ typer.echo(f"Updated.")
207
+
208
+
209
+
210
+ @app.command("delete")
211
+ def delete(
212
+ id: str = typer.Argument(help="id"),
213
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
214
+ debug: bool = typer.Option(False, "--debug"),
215
+ ):
216
+ """Delete specific Team by ID."""
217
+ if not force:
218
+ typer.confirm(f"Delete {id}?", abort=True)
219
+ api = get_api(debug=debug)
220
+ cc_base_url = get_cc_base_url()
221
+ orgid = get_cc_org_id(api.session)
222
+ url = f"{cc_base_url}/organization/{orgid}/team/{id}"
223
+ try:
224
+ api.session.rest_delete(url)
225
+ except WebexError as e:
226
+ handle_rest_error(e)
227
+ typer.echo(f"Deleted: {id}")
228
+
229
+
230
+
231
+ @app.command("list-incoming-references")
232
+ def list_incoming_references(
233
+ id: str = typer.Argument(help="id"),
234
+ type_param: str = typer.Option(None, "--type", help="Entity type of the other entity that has a reference to this"),
235
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
236
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
237
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
238
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
239
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
240
+ debug: bool = typer.Option(False, "--debug"),
241
+ ):
242
+ """List references for a specific Team."""
243
+ api = get_api(debug=debug)
244
+ cc_base_url = get_cc_base_url()
245
+ orgid = get_cc_org_id(api.session)
246
+ url = f"{cc_base_url}/organization/{orgid}/team/{id}/incoming-references"
247
+ params = {}
248
+ if type_param is not None:
249
+ params["type"] = type_param
250
+ if page is not None:
251
+ params["page"] = page
252
+ if page_size is not None:
253
+ params["pageSize"] = page_size
254
+ if limit > 0:
255
+ params["max"] = limit
256
+ if offset > 0:
257
+ params["start"] = offset
258
+ result = None
259
+ try:
260
+ result = api.session.rest_get(url, params=params)
261
+ except WebexError as e:
262
+ handle_rest_error(e)
263
+ result = result or []
264
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
265
+ if output == "json":
266
+ print_json(items)
267
+ else:
268
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
269
+
270
+
271
+
272
+ @app.command("list-team")
273
+ def list_team(
274
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
275
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned. By default, all attri"),
276
+ search: str = typer.Option(None, "--search", help="Filter data based on the search keyword.Supported search col"),
277
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
278
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
279
+ supervisor_view: str = typer.Option(None, "--supervisor-view", help="If set to true, the API will only return data that the user"),
280
+ provisioning_view: str = typer.Option(None, "--provisioning-view", help="If set to true, the API will only return data that the user"),
281
+ single_object_response: str = typer.Option(None, "--single-object-response", help="Specify whether to include array fields in the response. Thi"),
282
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
283
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
284
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
285
+ debug: bool = typer.Option(False, "--debug"),
286
+ ):
287
+ """List Teams."""
288
+ api = get_api(debug=debug)
289
+ cc_base_url = get_cc_base_url()
290
+ orgid = get_cc_org_id(api.session)
291
+ url = f"{cc_base_url}/organization/{orgid}/v2/team"
292
+ params = {}
293
+ if filter_param is not None:
294
+ params["filter"] = filter_param
295
+ if attributes is not None:
296
+ params["attributes"] = attributes
297
+ if search is not None:
298
+ params["search"] = search
299
+ if page is not None:
300
+ params["page"] = page
301
+ if page_size is not None:
302
+ params["pageSize"] = page_size
303
+ if supervisor_view is not None:
304
+ params["supervisorView"] = supervisor_view
305
+ if provisioning_view is not None:
306
+ params["provisioningView"] = provisioning_view
307
+ if single_object_response is not None:
308
+ params["singleObjectResponse"] = single_object_response
309
+ if limit > 0:
310
+ params["max"] = limit
311
+ if offset > 0:
312
+ params["start"] = offset
313
+ result = None
314
+ try:
315
+ result = api.session.rest_get(url, params=params)
316
+ except WebexError as e:
317
+ handle_rest_error(e)
318
+ result = result or []
319
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
320
+ if output == "json":
321
+ print_json(items)
322
+ else:
323
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
324
+
325
+
@@ -0,0 +1,349 @@
1
+ import json
2
+ import typer
3
+ from wxcli.auth import get_api
4
+ from wxcli.errors import WebexError, handle_rest_error
5
+ from wxcli.output import print_table, print_json
6
+ from wxcli.config import resolve_org_id, get_cc_base_url, get_cc_org_id
7
+
8
+
9
+ app = typer.Typer(help="Manage Webex Contact Center cc-user-profiles.")
10
+
11
+
12
+ @app.command("list")
13
+ def cmd_list(
14
+ id: str = typer.Argument(help="id"),
15
+ type_param: str = typer.Option(None, "--type", help="Entity type of the other entity that has a reference to this"),
16
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
17
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
18
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
19
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
20
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
21
+ debug: bool = typer.Option(False, "--debug"),
22
+ ):
23
+ """List references for a specific User Profile."""
24
+ api = get_api(debug=debug)
25
+ cc_base_url = get_cc_base_url()
26
+ orgid = get_cc_org_id(api.session)
27
+ url = f"{cc_base_url}/organization/{orgid}/user-profile/{id}/incoming-references"
28
+ params = {}
29
+ if type_param is not None:
30
+ params["type"] = type_param
31
+ if page is not None:
32
+ params["page"] = page
33
+ if page_size is not None:
34
+ params["pageSize"] = page_size
35
+ if limit > 0:
36
+ params["max"] = limit
37
+ if offset > 0:
38
+ params["start"] = offset
39
+ result = None
40
+ try:
41
+ result = api.session.rest_get(url, params=params)
42
+ except WebexError as e:
43
+ handle_rest_error(e)
44
+ result = result or []
45
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
46
+ if output == "json":
47
+ print_json(items)
48
+ else:
49
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
50
+
51
+
52
+
53
+ @app.command("list-user-profile")
54
+ def list_user_profile(
55
+ filter_param: str = typer.Option(None, "--filter", help="Specify a filter based on which the results will be fetched."),
56
+ attributes: str = typer.Option(None, "--attributes", help="Specify the attributes to be returned. By default, all attri"),
57
+ search: str = typer.Option(None, "--search", help="Filter data based on the search keyword.Supported search col"),
58
+ page: str = typer.Option(None, "--page", help="Defines the number of displayed page. The page number starts"),
59
+ page_size: str = typer.Option(None, "--page-size", help="Defines the number of items to be displayed on a page. If th"),
60
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
61
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
62
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
63
+ debug: bool = typer.Option(False, "--debug"),
64
+ ):
65
+ """List user profiles."""
66
+ api = get_api(debug=debug)
67
+ cc_base_url = get_cc_base_url()
68
+ orgid = get_cc_org_id(api.session)
69
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile"
70
+ params = {}
71
+ if filter_param is not None:
72
+ params["filter"] = filter_param
73
+ if attributes is not None:
74
+ params["attributes"] = attributes
75
+ if search is not None:
76
+ params["search"] = search
77
+ if page is not None:
78
+ params["page"] = page
79
+ if page_size is not None:
80
+ params["pageSize"] = page_size
81
+ if limit > 0:
82
+ params["max"] = limit
83
+ if offset > 0:
84
+ params["start"] = offset
85
+ result = None
86
+ try:
87
+ result = api.session.rest_get(url, params=params)
88
+ except WebexError as e:
89
+ handle_rest_error(e)
90
+ result = result or []
91
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
92
+ if output == "json":
93
+ print_json(items)
94
+ else:
95
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
96
+
97
+
98
+
99
+ @app.command("create")
100
+ def create(
101
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. This field is require"),
102
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
103
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
104
+ name: str = typer.Option(None, "--name", help="(required) The name of the user profile."),
105
+ description: str = typer.Option(None, "--description", help="An optional description of the profile."),
106
+ profile_type: str = typer.Option(None, "--profile-type", help="(required) Choices: ADMINISTRATOR, ADMINISTRATOR_ONLY, SUPERVISOR, PREMIUM_AGENT, STANDARD_AGENT, ANALYZER_ADMINISTRATOR, ANALYZER_SUPERVISOR, ANALYZER_USER"),
107
+ active: bool = typer.Option(None, "--active/--no-active", help="(required) Specify whether the User profile is active or not."),
108
+ permission_access_level: str = typer.Option(None, "--permission-access-level", help="(required) Choices: SPECIFIC, ALL, PROVISIONED_VALUE, NONE"),
109
+ resource_access_level: str = typer.Option(None, "--resource-access-level", help="(required) Choices: SPECIFIC, ALL, PROVISIONED_VALUE, NONE"),
110
+ system_default: bool = typer.Option(None, "--system-default/--no-system-default", help="Indicates whether the created resource is system created or"),
111
+ default_resource_collection_id: str = typer.Option(None, "--default-resource-collection-id", help="Specifies the default resource collection for this profile"),
112
+ created_time: str = typer.Option(None, "--created-time", help="This is the created time of the entity."),
113
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="This is the updated time of the entity."),
114
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
115
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
116
+ debug: bool = typer.Option(False, "--debug"),
117
+ ):
118
+ """Create a new User Profile\n\nExample --json-body:\n '{"name":"...","profileType":"ADMINISTRATOR","active":true,"permissionAccessLevel":"SPECIFIC","resourceAccessLevel":"SPECIFIC","organizationId":"...","id":"...","version":0}'."""
119
+ api = get_api(debug=debug)
120
+ cc_base_url = get_cc_base_url()
121
+ orgid = get_cc_org_id(api.session)
122
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile"
123
+ if json_body:
124
+ body = json.loads(json_body)
125
+ else:
126
+ body = {}
127
+ if organization_id is not None:
128
+ body["organizationId"] = organization_id
129
+ if id_param is not None:
130
+ body["id"] = id_param
131
+ if version is not None:
132
+ body["version"] = version
133
+ if name is not None:
134
+ body["name"] = name
135
+ if description is not None:
136
+ body["description"] = description
137
+ if profile_type is not None:
138
+ body["profileType"] = profile_type
139
+ if active is not None:
140
+ body["active"] = active
141
+ if permission_access_level is not None:
142
+ body["permissionAccessLevel"] = permission_access_level
143
+ if resource_access_level is not None:
144
+ body["resourceAccessLevel"] = resource_access_level
145
+ if system_default is not None:
146
+ body["systemDefault"] = system_default
147
+ if default_resource_collection_id is not None:
148
+ body["defaultResourceCollectionId"] = default_resource_collection_id
149
+ if created_time is not None:
150
+ body["createdTime"] = created_time
151
+ if last_updated_time is not None:
152
+ body["lastUpdatedTime"] = last_updated_time
153
+ _missing = [f for f in ['name', 'profileType', 'active', 'permissionAccessLevel', 'resourceAccessLevel'] if f not in body or body[f] is None]
154
+ if _missing:
155
+ typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
156
+ raise typer.Exit(1)
157
+ try:
158
+ result = api.session.rest_post(url, json=body)
159
+ except WebexError as e:
160
+ handle_rest_error(e)
161
+ if output == "json":
162
+ print_json(result)
163
+ elif isinstance(result, dict) and "id" in result:
164
+ typer.echo(f"Created: {result['id']}")
165
+ elif not result or result == {}:
166
+ typer.echo("Created.")
167
+ else:
168
+ print_json(result)
169
+
170
+
171
+
172
+ @app.command("create-bulk")
173
+ def create_bulk(
174
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
175
+ output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
176
+ debug: bool = typer.Option(False, "--debug"),
177
+ ):
178
+ """Bulk save User Profiles\n\nExample --json-body:\n '{"items":[{"itemIdentifier":"...","item":"...","requestAction":"..."}]}'."""
179
+ api = get_api(debug=debug)
180
+ cc_base_url = get_cc_base_url()
181
+ orgid = get_cc_org_id(api.session)
182
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile/bulk"
183
+ if json_body:
184
+ body = json.loads(json_body)
185
+ else:
186
+ body = {}
187
+ try:
188
+ result = api.session.rest_post(url, json=body)
189
+ except WebexError as e:
190
+ handle_rest_error(e)
191
+ if output == "json":
192
+ print_json(result)
193
+ elif isinstance(result, dict) and "id" in result:
194
+ typer.echo(f"Created: {result['id']}")
195
+ elif not result or result == {}:
196
+ typer.echo("Created.")
197
+ else:
198
+ print_json(result)
199
+
200
+
201
+
202
+ @app.command("show")
203
+ def show(
204
+ id: str = typer.Argument(help="id"),
205
+ include_names: str = typer.Option(None, "--include-names", help="Flag to include resource names in the response."),
206
+ output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
207
+ debug: bool = typer.Option(False, "--debug"),
208
+ ):
209
+ """Get specific User Profile by ID."""
210
+ api = get_api(debug=debug)
211
+ cc_base_url = get_cc_base_url()
212
+ orgid = get_cc_org_id(api.session)
213
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile/{id}"
214
+ params = {}
215
+ if include_names is not None:
216
+ params["includeNames"] = include_names
217
+ try:
218
+ result = api.session.rest_get(url, params=params)
219
+ except WebexError as e:
220
+ handle_rest_error(e)
221
+ if output == "json":
222
+ print_json(result)
223
+ else:
224
+ if isinstance(result, dict):
225
+ print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
226
+ elif isinstance(result, list):
227
+ print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
228
+ else:
229
+ print_json(result)
230
+
231
+
232
+
233
+ @app.command("update")
234
+ def update(
235
+ id: str = typer.Argument(help="id"),
236
+ organization_id: str = typer.Option(None, "--organization-id", help="ID of the contact center organization. This field is require"),
237
+ id_param: str = typer.Option(None, "--id", help="ID of this contact center resource. It should not be specifi"),
238
+ version: str = typer.Option(None, "--version", help="The version of this resource. For a newly created resource,"),
239
+ name: str = typer.Option(None, "--name", help="The name of the user profile."),
240
+ description: str = typer.Option(None, "--description", help="An optional description of the profile."),
241
+ profile_type: str = typer.Option(None, "--profile-type", help="Choices: ADMINISTRATOR, ADMINISTRATOR_ONLY, SUPERVISOR, PREMIUM_AGENT, STANDARD_AGENT, ANALYZER_ADMINISTRATOR, ANALYZER_SUPERVISOR, ANALYZER_USER"),
242
+ active: bool = typer.Option(None, "--active/--no-active", help="Specify whether the User profile is active or not."),
243
+ permission_access_level: str = typer.Option(None, "--permission-access-level", help="Choices: SPECIFIC, ALL, PROVISIONED_VALUE, NONE"),
244
+ resource_access_level: str = typer.Option(None, "--resource-access-level", help="Choices: SPECIFIC, ALL, PROVISIONED_VALUE, NONE"),
245
+ system_default: bool = typer.Option(None, "--system-default/--no-system-default", help="Indicates whether the created resource is system created or"),
246
+ default_resource_collection_id: str = typer.Option(None, "--default-resource-collection-id", help="Specifies the default resource collection for this profile"),
247
+ created_time: str = typer.Option(None, "--created-time", help="This is the created time of the entity."),
248
+ last_updated_time: str = typer.Option(None, "--last-updated-time", help="This is the updated time of the entity."),
249
+ json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
250
+ debug: bool = typer.Option(False, "--debug"),
251
+ ):
252
+ """Update specific User Profile by ID\n\nExample --json-body:\n '{"name":"...","profileType":"ADMINISTRATOR","active":true,"permissionAccessLevel":"SPECIFIC","resourceAccessLevel":"SPECIFIC","organizationId":"...","id":"...","version":0}'."""
253
+ api = get_api(debug=debug)
254
+ cc_base_url = get_cc_base_url()
255
+ orgid = get_cc_org_id(api.session)
256
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile/{id}"
257
+ if json_body:
258
+ body = json.loads(json_body)
259
+ else:
260
+ body = {}
261
+ if organization_id is not None:
262
+ body["organizationId"] = organization_id
263
+ if id_param is not None:
264
+ body["id"] = id_param
265
+ if version is not None:
266
+ body["version"] = version
267
+ if name is not None:
268
+ body["name"] = name
269
+ if description is not None:
270
+ body["description"] = description
271
+ if profile_type is not None:
272
+ body["profileType"] = profile_type
273
+ if active is not None:
274
+ body["active"] = active
275
+ if permission_access_level is not None:
276
+ body["permissionAccessLevel"] = permission_access_level
277
+ if resource_access_level is not None:
278
+ body["resourceAccessLevel"] = resource_access_level
279
+ if system_default is not None:
280
+ body["systemDefault"] = system_default
281
+ if default_resource_collection_id is not None:
282
+ body["defaultResourceCollectionId"] = default_resource_collection_id
283
+ if created_time is not None:
284
+ body["createdTime"] = created_time
285
+ if last_updated_time is not None:
286
+ body["lastUpdatedTime"] = last_updated_time
287
+ try:
288
+ result = api.session.rest_put(url, json=body)
289
+ except WebexError as e:
290
+ handle_rest_error(e)
291
+ typer.echo(f"Updated.")
292
+
293
+
294
+
295
+ @app.command("delete")
296
+ def delete(
297
+ id: str = typer.Argument(help="id"),
298
+ force: bool = typer.Option(False, "--force", help="Skip confirmation"),
299
+ debug: bool = typer.Option(False, "--debug"),
300
+ ):
301
+ """Delete specific User Profile by ID."""
302
+ if not force:
303
+ typer.confirm(f"Delete {id}?", abort=True)
304
+ api = get_api(debug=debug)
305
+ cc_base_url = get_cc_base_url()
306
+ orgid = get_cc_org_id(api.session)
307
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile/{id}"
308
+ try:
309
+ api.session.rest_delete(url)
310
+ except WebexError as e:
311
+ handle_rest_error(e)
312
+ typer.echo(f"Deleted: {id}")
313
+
314
+
315
+
316
+ @app.command("list-acl")
317
+ def list_acl(
318
+ id: str = typer.Argument(help="id"),
319
+ names: str = typer.Option(None, "--names", help="Default all resources are returned in the ACL. If yo"),
320
+ output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
321
+ limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
322
+ offset: int = typer.Option(0, "--offset", help="Start offset"),
323
+ debug: bool = typer.Option(False, "--debug"),
324
+ ):
325
+ """Get specific User Profile ACL by ID."""
326
+ api = get_api(debug=debug)
327
+ cc_base_url = get_cc_base_url()
328
+ orgid = get_cc_org_id(api.session)
329
+ url = f"{cc_base_url}/organization/{orgid}/v3/user-profile/{id}/acl"
330
+ params = {}
331
+ if names is not None:
332
+ params["names"] = names
333
+ if limit > 0:
334
+ params["max"] = limit
335
+ if offset > 0:
336
+ params["start"] = offset
337
+ result = None
338
+ try:
339
+ result = api.session.rest_get(url, params=params)
340
+ except WebexError as e:
341
+ handle_rest_error(e)
342
+ result = result or []
343
+ items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
344
+ if output == "json":
345
+ print_json(items)
346
+ else:
347
+ print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
348
+
349
+