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.
- wxcli/__init__.py +4 -0
- wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
- wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
- wxcli/_playbook/.claude/rules/cleanup.md +29 -0
- wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
- wxcli/_playbook/.claude/rules/org-health.md +14 -0
- wxcli/_playbook/.claude/settings.json +8 -0
- wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
- wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
- wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
- wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
- wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
- wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
- wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
- wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
- wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
- wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
- wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
- wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
- wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
- wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
- wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
- wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
- wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
- wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
- wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
- wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
- wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
- wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
- wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
- wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
- wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
- wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
- wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
- wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
- wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
- wxcli/_playbook/CLAUDE.md +373 -0
- wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
- wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
- wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
- wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
- wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
- wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
- wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
- wxcli/_playbook/docs/reference/admin-partner.md +357 -0
- wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
- wxcli/_playbook/docs/reference/authentication.md +965 -0
- wxcli/_playbook/docs/reference/call-control.md +1205 -0
- wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
- wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
- wxcli/_playbook/docs/reference/call-routing.md +2304 -0
- wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
- wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
- wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
- wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
- wxcli/_playbook/docs/reference/devices-core.md +1869 -0
- wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
- wxcli/_playbook/docs/reference/devices-platform.md +467 -0
- wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
- wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
- wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
- wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
- wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
- wxcli/_playbook/docs/reference/meetings-content.md +473 -0
- wxcli/_playbook/docs/reference/meetings-core.md +903 -0
- wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
- wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
- wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
- wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
- wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
- wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
- wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
- wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
- wxcli/_playbook/docs/reference/provisioning.md +1366 -0
- wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
- wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
- wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
- wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
- wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
- wxcli/_version.py +24 -0
- wxcli/auth.py +137 -0
- wxcli/commands/__init__.py +0 -0
- wxcli/commands/_registry.py +181 -0
- wxcli/commands/activation_email.py +103 -0
- wxcli/commands/admin_recordings.py +585 -0
- wxcli/commands/analytics.py +105 -0
- wxcli/commands/announcement_playlists.py +219 -0
- wxcli/commands/announcements.py +519 -0
- wxcli/commands/archive_users.py +36 -0
- wxcli/commands/attachment_actions.py +60 -0
- wxcli/commands/audit_events.py +83 -0
- wxcli/commands/authorizations.py +113 -0
- wxcli/commands/auto_attendant.py +642 -0
- wxcli/commands/broadworks_billing_reports.py +126 -0
- wxcli/commands/broadworks_enterprises.py +160 -0
- wxcli/commands/broadworks_subscribers.py +319 -0
- wxcli/commands/broadworks_workspaces.py +108 -0
- wxcli/commands/call_controls.py +1304 -0
- wxcli/commands/call_park.py +494 -0
- wxcli/commands/call_pickup.py +229 -0
- wxcli/commands/call_queue.py +1878 -0
- wxcli/commands/call_recording.py +707 -0
- wxcli/commands/call_routing.py +1610 -0
- wxcli/commands/call_settings_for_me_phase_5.py +212 -0
- wxcli/commands/caller_reputation.py +169 -0
- wxcli/commands/calling_service.py +305 -0
- wxcli/commands/cc_address_book.py +770 -0
- wxcli/commands/cc_agent_greetings.py +242 -0
- wxcli/commands/cc_agent_summaries.py +39 -0
- wxcli/commands/cc_agent_wellbeing.py +216 -0
- wxcli/commands/cc_agents.py +425 -0
- wxcli/commands/cc_ai_assistant.py +55 -0
- wxcli/commands/cc_ai_feature.py +294 -0
- wxcli/commands/cc_audio_files.py +149 -0
- wxcli/commands/cc_auto_csat.py +311 -0
- wxcli/commands/cc_aux_code.py +458 -0
- wxcli/commands/cc_business_hour.py +353 -0
- wxcli/commands/cc_call_monitoring.py +228 -0
- wxcli/commands/cc_callbacks.py +194 -0
- wxcli/commands/cc_campaign.py +212 -0
- wxcli/commands/cc_captures.py +39 -0
- wxcli/commands/cc_contact_list.py +169 -0
- wxcli/commands/cc_contact_number.py +295 -0
- wxcli/commands/cc_data_sources.py +235 -0
- wxcli/commands/cc_desktop_layout.py +380 -0
- wxcli/commands/cc_desktop_profile.py +322 -0
- wxcli/commands/cc_dial_number.py +511 -0
- wxcli/commands/cc_dial_plan.py +347 -0
- wxcli/commands/cc_dnc.py +101 -0
- wxcli/commands/cc_entry_point.py +545 -0
- wxcli/commands/cc_ewt.py +51 -0
- wxcli/commands/cc_flow.py +477 -0
- wxcli/commands/cc_global_vars.py +430 -0
- wxcli/commands/cc_holiday_list.py +335 -0
- wxcli/commands/cc_journey.py +1261 -0
- wxcli/commands/cc_legacy_flows.py +49 -0
- wxcli/commands/cc_multimedia_profile.py +436 -0
- wxcli/commands/cc_notification.py +51 -0
- wxcli/commands/cc_outdial_ani.py +604 -0
- wxcli/commands/cc_overrides.py +341 -0
- wxcli/commands/cc_queue.py +1083 -0
- wxcli/commands/cc_queue_stats.py +55 -0
- wxcli/commands/cc_realtime.py +51 -0
- wxcli/commands/cc_resource_collection.py +312 -0
- wxcli/commands/cc_search.py +46 -0
- wxcli/commands/cc_site.py +400 -0
- wxcli/commands/cc_skill.py +350 -0
- wxcli/commands/cc_skill_profile.py +289 -0
- wxcli/commands/cc_subscriptions.py +426 -0
- wxcli/commands/cc_summaries.py +130 -0
- wxcli/commands/cc_tasks.py +844 -0
- wxcli/commands/cc_team.py +325 -0
- wxcli/commands/cc_user_profiles.py +349 -0
- wxcli/commands/cc_users.py +701 -0
- wxcli/commands/cc_work_types.py +363 -0
- wxcli/commands/cdr.py +89 -0
- wxcli/commands/classifications.py +38 -0
- wxcli/commands/cleanup.py +1427 -0
- wxcli/commands/client_settings.py +72 -0
- wxcli/commands/conference.py +328 -0
- wxcli/commands/configure.py +72 -0
- wxcli/commands/converged_recordings.py +347 -0
- wxcli/commands/converged_recordings_export.py +310 -0
- wxcli/commands/cq_playlists.py +42 -0
- wxcli/commands/cucm.py +2794 -0
- wxcli/commands/cucm_config.py +129 -0
- wxcli/commands/customer_assist.py +373 -0
- wxcli/commands/data_sources.py +227 -0
- wxcli/commands/dect_devices.py +787 -0
- wxcli/commands/device_configurations.py +77 -0
- wxcli/commands/device_dynamic_settings.py +320 -0
- wxcli/commands/device_settings.py +1489 -0
- wxcli/commands/devices.py +280 -0
- wxcli/commands/domains.py +142 -0
- wxcli/commands/ecm.py +178 -0
- wxcli/commands/emergency_services.py +827 -0
- wxcli/commands/events.py +83 -0
- wxcli/commands/external_voicemail.py +52 -0
- wxcli/commands/groups.py +206 -0
- wxcli/commands/guest_management.py +76 -0
- wxcli/commands/hds.py +340 -0
- wxcli/commands/hot_desk.py +67 -0
- wxcli/commands/hot_desking_members.py +118 -0
- wxcli/commands/hot_desking_portal.py +124 -0
- wxcli/commands/hunt_group.py +577 -0
- wxcli/commands/hybrid_clusters.py +71 -0
- wxcli/commands/hybrid_connectors.py +67 -0
- wxcli/commands/identity_org.py +159 -0
- wxcli/commands/init_playbook.py +155 -0
- wxcli/commands/licenses.py +106 -0
- wxcli/commands/live_monitoring.py +40 -0
- wxcli/commands/location_call_handling.py +577 -0
- wxcli/commands/location_schedules.py +341 -0
- wxcli/commands/location_settings.py +1297 -0
- wxcli/commands/location_voicemail.py +494 -0
- wxcli/commands/locations.py +336 -0
- wxcli/commands/meeting_captions.py +110 -0
- wxcli/commands/meeting_chats.py +63 -0
- wxcli/commands/meeting_invitees.py +234 -0
- wxcli/commands/meeting_messages.py +28 -0
- wxcli/commands/meeting_participants.py +278 -0
- wxcli/commands/meeting_polls.py +111 -0
- wxcli/commands/meeting_preferences.py +515 -0
- wxcli/commands/meeting_qa.py +78 -0
- wxcli/commands/meeting_qualities.py +43 -0
- wxcli/commands/meeting_reports.py +101 -0
- wxcli/commands/meeting_session_types.py +105 -0
- wxcli/commands/meeting_site.py +57 -0
- wxcli/commands/meeting_slido.py +44 -0
- wxcli/commands/meeting_summaries.py +92 -0
- wxcli/commands/meeting_tracking_codes.py +233 -0
- wxcli/commands/meeting_transcripts.py +230 -0
- wxcli/commands/meetings.py +1997 -0
- wxcli/commands/memberships.py +164 -0
- wxcli/commands/messages.py +213 -0
- wxcli/commands/mode_management.py +244 -0
- wxcli/commands/my_call_settings.py +3577 -0
- wxcli/commands/numbers.py +405 -0
- wxcli/commands/operating_modes.py +410 -0
- wxcli/commands/org_contacts.py +284 -0
- wxcli/commands/org_health_cli.py +55 -0
- wxcli/commands/org_settings.py +71 -0
- wxcli/commands/organizations.py +83 -0
- wxcli/commands/paging_group.py +257 -0
- wxcli/commands/partner_admins.py +141 -0
- wxcli/commands/partner_reports.py +188 -0
- wxcli/commands/partner_tags.py +216 -0
- wxcli/commands/people.py +279 -0
- wxcli/commands/person_call_settings.py +71 -0
- wxcli/commands/pstn.py +280 -0
- wxcli/commands/recording_report.py +154 -0
- wxcli/commands/report_templates.py +38 -0
- wxcli/commands/reports.py +144 -0
- wxcli/commands/resource_group_memberships.py +160 -0
- wxcli/commands/resource_groups.py +67 -0
- wxcli/commands/roles.py +63 -0
- wxcli/commands/room_tabs.py +160 -0
- wxcli/commands/rooms.py +225 -0
- wxcli/commands/scim_bulk.py +46 -0
- wxcli/commands/scim_groups.py +246 -0
- wxcli/commands/scim_schemas.py +82 -0
- wxcli/commands/scim_users.py +283 -0
- wxcli/commands/security_audit.py +54 -0
- wxcli/commands/service_apps.py +51 -0
- wxcli/commands/single_number_reach.py +209 -0
- wxcli/commands/team_memberships.py +155 -0
- wxcli/commands/teams.py +153 -0
- wxcli/commands/ucm_profile.py +42 -0
- wxcli/commands/update.py +219 -0
- wxcli/commands/user_settings.py +5116 -0
- wxcli/commands/video_mesh.py +1090 -0
- wxcli/commands/virtual_extensions.py +502 -0
- wxcli/commands/virtual_line_settings.py +2072 -0
- wxcli/commands/webhooks.py +176 -0
- wxcli/commands/wholesale_billing_reports.py +147 -0
- wxcli/commands/wholesale_provisioning.py +523 -0
- wxcli/commands/workspace_locations.py +339 -0
- wxcli/commands/workspace_metrics.py +103 -0
- wxcli/commands/workspace_personalization.py +70 -0
- wxcli/commands/workspace_settings.py +3347 -0
- wxcli/commands/workspaces.py +279 -0
- wxcli/commands/xapi.py +114 -0
- wxcli/config.py +139 -0
- wxcli/errors.py +77 -0
- wxcli/main.py +210 -0
- wxcli/migration/CLAUDE.md +106 -0
- wxcli/migration/__init__.py +1 -0
- wxcli/migration/advisory/CLAUDE.md +196 -0
- wxcli/migration/advisory/__init__.py +46 -0
- wxcli/migration/advisory/advisor.py +107 -0
- wxcli/migration/advisory/advisory_patterns.py +2552 -0
- wxcli/migration/advisory/recommendation_rules.py +835 -0
- wxcli/migration/cucm/CLAUDE.md +74 -0
- wxcli/migration/cucm/__init__.py +5 -0
- wxcli/migration/cucm/connection.py +265 -0
- wxcli/migration/cucm/discovery.py +225 -0
- wxcli/migration/cucm/extractors/__init__.py +1 -0
- wxcli/migration/cucm/extractors/announcements.py +92 -0
- wxcli/migration/cucm/extractors/base.py +90 -0
- wxcli/migration/cucm/extractors/device_profiles.py +98 -0
- wxcli/migration/cucm/extractors/devices.py +193 -0
- wxcli/migration/cucm/extractors/e911.py +103 -0
- wxcli/migration/cucm/extractors/features.py +309 -0
- wxcli/migration/cucm/extractors/helpers.py +73 -0
- wxcli/migration/cucm/extractors/informational.py +295 -0
- wxcli/migration/cucm/extractors/locations.py +221 -0
- wxcli/migration/cucm/extractors/moh.py +100 -0
- wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
- wxcli/migration/cucm/extractors/routing.py +493 -0
- wxcli/migration/cucm/extractors/shared_lines.py +146 -0
- wxcli/migration/cucm/extractors/templates.py +229 -0
- wxcli/migration/cucm/extractors/tier4.py +173 -0
- wxcli/migration/cucm/extractors/users.py +240 -0
- wxcli/migration/cucm/extractors/voicemail.py +243 -0
- wxcli/migration/cucm/extractors/workspaces.py +88 -0
- wxcli/migration/cucm/unity_connection.py +304 -0
- wxcli/migration/execute/CLAUDE.md +372 -0
- wxcli/migration/execute/__init__.py +303 -0
- wxcli/migration/execute/batch.py +277 -0
- wxcli/migration/execute/dependency.py +483 -0
- wxcli/migration/execute/engine.py +964 -0
- wxcli/migration/execute/handlers.py +2232 -0
- wxcli/migration/execute/planner.py +1939 -0
- wxcli/migration/execute/runtime.py +571 -0
- wxcli/migration/export/CLAUDE.md +49 -0
- wxcli/migration/export/__init__.py +8 -0
- wxcli/migration/export/csv_export.py +126 -0
- wxcli/migration/export/deployment_plan.py +479 -0
- wxcli/migration/export/json_export.py +60 -0
- wxcli/migration/models.py +941 -0
- wxcli/migration/phone_models.py +50 -0
- wxcli/migration/preflight/CLAUDE.md +52 -0
- wxcli/migration/preflight/__init__.py +89 -0
- wxcli/migration/preflight/checks.py +911 -0
- wxcli/migration/preflight/runner.py +293 -0
- wxcli/migration/rate_limiter.py +144 -0
- wxcli/migration/report/CLAUDE.md +245 -0
- wxcli/migration/report/__init__.py +7 -0
- wxcli/migration/report/appendix.py +2437 -0
- wxcli/migration/report/assembler.py +183 -0
- wxcli/migration/report/charts.py +263 -0
- wxcli/migration/report/executive.py +776 -0
- wxcli/migration/report/explainer.py +704 -0
- wxcli/migration/report/helpers.py +74 -0
- wxcli/migration/report/ingest.py +152 -0
- wxcli/migration/report/notice_templates.py +192 -0
- wxcli/migration/report/score.py +375 -0
- wxcli/migration/report/styles.py +1052 -0
- wxcli/migration/report/user_diff.py +1052 -0
- wxcli/migration/report/user_notice.py +425 -0
- wxcli/migration/state.py +139 -0
- wxcli/migration/store.py +860 -0
- wxcli/migration/transform/CLAUDE.md +107 -0
- wxcli/migration/transform/__init__.py +12 -0
- wxcli/migration/transform/analysis_pipeline.py +453 -0
- wxcli/migration/transform/analyzers/__init__.py +142 -0
- wxcli/migration/transform/analyzers/css_permission.py +189 -0
- wxcli/migration/transform/analyzers/css_routing.py +335 -0
- wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
- wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
- wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
- wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
- wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
- wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
- wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
- wxcli/migration/transform/analyzers/missing_data.py +300 -0
- wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
- wxcli/migration/transform/analyzers/shared_line.py +170 -0
- wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
- wxcli/migration/transform/analyzers/workspace_license.py +212 -0
- wxcli/migration/transform/cross_reference.py +1136 -0
- wxcli/migration/transform/cucm_pattern.py +246 -0
- wxcli/migration/transform/decisions.py +301 -0
- wxcli/migration/transform/e164.py +145 -0
- wxcli/migration/transform/engine.py +256 -0
- wxcli/migration/transform/mappers/CLAUDE.md +123 -0
- wxcli/migration/transform/mappers/__init__.py +76 -0
- wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
- wxcli/migration/transform/mappers/base.py +190 -0
- wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
- wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
- wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
- wxcli/migration/transform/mappers/css_mapper.py +868 -0
- wxcli/migration/transform/mappers/dect_mapper.py +367 -0
- wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
- wxcli/migration/transform/mappers/device_mapper.py +227 -0
- wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
- wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
- wxcli/migration/transform/mappers/e911_mapper.py +129 -0
- wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
- wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
- wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
- wxcli/migration/transform/mappers/line_mapper.py +310 -0
- wxcli/migration/transform/mappers/location_mapper.py +235 -0
- wxcli/migration/transform/mappers/moh_mapper.py +114 -0
- wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
- wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
- wxcli/migration/transform/mappers/routing_mapper.py +821 -0
- wxcli/migration/transform/mappers/snr_mapper.py +201 -0
- wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
- wxcli/migration/transform/mappers/user_mapper.py +264 -0
- wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
- wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
- wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
- wxcli/migration/transform/normalizers.py +2008 -0
- wxcli/migration/transform/pattern_converter.py +106 -0
- wxcli/migration/transform/pipeline.py +271 -0
- wxcli/migration/transform/rules.py +255 -0
- wxcli/org_health/CLAUDE.md +63 -0
- wxcli/org_health/__init__.py +7 -0
- wxcli/org_health/analyze.py +93 -0
- wxcli/org_health/checks.py +458 -0
- wxcli/org_health/collector.py +62 -0
- wxcli/org_health/models.py +78 -0
- wxcli/org_health/report.py +300 -0
- wxcli/output.py +101 -0
- wxcli-1.2.0.dist-info/METADATA +505 -0
- wxcli-1.2.0.dist-info/RECORD +413 -0
- wxcli-1.2.0.dist-info/WHEEL +5 -0
- wxcli-1.2.0.dist-info/entry_points.txt +2 -0
- wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
- wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
- wxcli-1.2.0.dist-info/scm_version.json +8 -0
- wxcli-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,257 @@
|
|
|
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 get_org_id
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Calling paging-group.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def cmd_list(
|
|
14
|
+
location_id: str = typer.Option(None, "--location-id", help="Return only paging groups with matching location ID. Default"),
|
|
15
|
+
name: str = typer.Option(None, "--name", help="Return only paging groups with the matching name."),
|
|
16
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Return only paging groups with matching primary phone number"),
|
|
17
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
18
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
19
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
20
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
21
|
+
):
|
|
22
|
+
"""Read the List of Paging Groups."""
|
|
23
|
+
api = get_api(debug=debug)
|
|
24
|
+
url = f"https://webexapis.com/v1/telephony/config/paging"
|
|
25
|
+
params = {}
|
|
26
|
+
if location_id is not None:
|
|
27
|
+
params["locationId"] = location_id
|
|
28
|
+
if name is not None:
|
|
29
|
+
params["name"] = name
|
|
30
|
+
if phone_number is not None:
|
|
31
|
+
params["phoneNumber"] = phone_number
|
|
32
|
+
if limit > 0:
|
|
33
|
+
params["max"] = limit
|
|
34
|
+
if offset > 0:
|
|
35
|
+
params["start"] = offset
|
|
36
|
+
org_id = get_org_id()
|
|
37
|
+
if org_id is not None:
|
|
38
|
+
params["orgId"] = org_id
|
|
39
|
+
try:
|
|
40
|
+
if limit > 0:
|
|
41
|
+
result = api.session.rest_get(url, params=params)
|
|
42
|
+
result = result or {}
|
|
43
|
+
items = result.get("locationPaging", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
44
|
+
else:
|
|
45
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="locationPaging"))
|
|
46
|
+
except WebexError as e:
|
|
47
|
+
handle_rest_error(e)
|
|
48
|
+
if output == "json":
|
|
49
|
+
print_json(items)
|
|
50
|
+
else:
|
|
51
|
+
print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@app.command("create")
|
|
56
|
+
def create(
|
|
57
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
58
|
+
name: str = typer.Option(None, "--name", help="(required) Unique name for the paging group. Minimum length is 1. Maxim"),
|
|
59
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Paging group phone number. Minimum length is 1. Maximum leng"),
|
|
60
|
+
extension: str = typer.Option(None, "--extension", help="Paging group extension. Minimum length is 2. Maximum length"),
|
|
61
|
+
language_code: str = typer.Option(None, "--language-code", help="Language code."),
|
|
62
|
+
first_name: str = typer.Option(None, "--first-name", help="First name that displays when a group page is performed. Min"),
|
|
63
|
+
last_name: str = typer.Option(None, "--last-name", help="Last name that displays when a group page is performed. Mini"),
|
|
64
|
+
originator_caller_id_enabled: bool = typer.Option(None, "--originator-caller-id-enabled/--no-originator-caller-id-enabled", help="Determines what is shown on target users caller ID when a gr"),
|
|
65
|
+
dial_by_name: str = typer.Option(None, "--dial-by-name", help="The name to be used for dial by name functions. Characters"),
|
|
66
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
67
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
68
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
69
|
+
):
|
|
70
|
+
"""Create a new Paging Group\n\nExample --json-body:\n '{"name":"...","phoneNumber":"...","extension":"...","languageCode":"...","firstName":"...","lastName":"...","originatorCallerIdEnabled":true,"originators":["..."]}'."""
|
|
71
|
+
api = get_api(debug=debug)
|
|
72
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/paging"
|
|
73
|
+
params = {}
|
|
74
|
+
org_id = get_org_id()
|
|
75
|
+
if org_id is not None:
|
|
76
|
+
params["orgId"] = org_id
|
|
77
|
+
if json_body:
|
|
78
|
+
body = json.loads(json_body)
|
|
79
|
+
else:
|
|
80
|
+
body = {}
|
|
81
|
+
if name is not None:
|
|
82
|
+
body["name"] = name
|
|
83
|
+
if phone_number is not None:
|
|
84
|
+
body["phoneNumber"] = phone_number
|
|
85
|
+
if extension is not None:
|
|
86
|
+
body["extension"] = extension
|
|
87
|
+
if language_code is not None:
|
|
88
|
+
body["languageCode"] = language_code
|
|
89
|
+
if first_name is not None:
|
|
90
|
+
body["firstName"] = first_name
|
|
91
|
+
if last_name is not None:
|
|
92
|
+
body["lastName"] = last_name
|
|
93
|
+
if originator_caller_id_enabled is not None:
|
|
94
|
+
body["originatorCallerIdEnabled"] = originator_caller_id_enabled
|
|
95
|
+
if dial_by_name is not None:
|
|
96
|
+
body["dialByName"] = dial_by_name
|
|
97
|
+
_missing = [f for f in ['name'] if f not in body or body[f] is None]
|
|
98
|
+
if _missing:
|
|
99
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
100
|
+
raise typer.Exit(1)
|
|
101
|
+
try:
|
|
102
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
103
|
+
except WebexError as e:
|
|
104
|
+
handle_rest_error(e)
|
|
105
|
+
if output == "json":
|
|
106
|
+
print_json(result)
|
|
107
|
+
elif isinstance(result, dict) and "id" in result:
|
|
108
|
+
typer.echo(f"Created: {result['id']}")
|
|
109
|
+
elif not result or result == {}:
|
|
110
|
+
typer.echo("Created.")
|
|
111
|
+
else:
|
|
112
|
+
print_json(result)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@app.command("show")
|
|
117
|
+
def show(
|
|
118
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
119
|
+
paging_id: str = typer.Argument(help="pagingId"),
|
|
120
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
121
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
122
|
+
):
|
|
123
|
+
"""Get Details for a Paging Group."""
|
|
124
|
+
api = get_api(debug=debug)
|
|
125
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/paging/{paging_id}"
|
|
126
|
+
params = {}
|
|
127
|
+
org_id = get_org_id()
|
|
128
|
+
if org_id is not None:
|
|
129
|
+
params["orgId"] = org_id
|
|
130
|
+
try:
|
|
131
|
+
result = api.session.rest_get(url, params=params)
|
|
132
|
+
except WebexError as e:
|
|
133
|
+
handle_rest_error(e)
|
|
134
|
+
if output == "json":
|
|
135
|
+
print_json(result)
|
|
136
|
+
else:
|
|
137
|
+
if isinstance(result, dict):
|
|
138
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
139
|
+
elif isinstance(result, list):
|
|
140
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
141
|
+
else:
|
|
142
|
+
print_json(result)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@app.command("update")
|
|
147
|
+
def update(
|
|
148
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
149
|
+
paging_id: str = typer.Argument(help="pagingId"),
|
|
150
|
+
enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Whether or not the paging group is enabled."),
|
|
151
|
+
name: str = typer.Option(None, "--name", help="Unique name for the paging group. Minimum length is 1. Maxim"),
|
|
152
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Paging group phone number. Minimum length is 1. Maximum leng"),
|
|
153
|
+
extension: str = typer.Option(None, "--extension", help="Paging group extension. Minimum length is 2. Maximum length"),
|
|
154
|
+
language_code: str = typer.Option(None, "--language-code", help="Language code."),
|
|
155
|
+
first_name: str = typer.Option(None, "--first-name", help="First name to be shown when calls are forwarded out of this"),
|
|
156
|
+
last_name: str = typer.Option(None, "--last-name", help="Last name to be shown when calls are forwarded out of this p"),
|
|
157
|
+
originator_caller_id_enabled: bool = typer.Option(None, "--originator-caller-id-enabled/--no-originator-caller-id-enabled", help="Determines what is shown on target users caller ID when a gr"),
|
|
158
|
+
dial_by_name: str = typer.Option(None, "--dial-by-name", help="Sets or clears the name to be used for dial by name function"),
|
|
159
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
160
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
161
|
+
):
|
|
162
|
+
"""Update a Paging Group\n\nExample --json-body:\n '{"enabled":true,"name":"...","phoneNumber":"...","extension":"...","languageCode":"...","firstName":"...","lastName":"...","originatorCallerIdEnabled":true}'."""
|
|
163
|
+
api = get_api(debug=debug)
|
|
164
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/paging/{paging_id}"
|
|
165
|
+
params = {}
|
|
166
|
+
org_id = get_org_id()
|
|
167
|
+
if org_id is not None:
|
|
168
|
+
params["orgId"] = org_id
|
|
169
|
+
if json_body:
|
|
170
|
+
body = json.loads(json_body)
|
|
171
|
+
else:
|
|
172
|
+
body = {}
|
|
173
|
+
if enabled is not None:
|
|
174
|
+
body["enabled"] = enabled
|
|
175
|
+
if name is not None:
|
|
176
|
+
body["name"] = name
|
|
177
|
+
if phone_number is not None:
|
|
178
|
+
body["phoneNumber"] = phone_number
|
|
179
|
+
if extension is not None:
|
|
180
|
+
body["extension"] = extension
|
|
181
|
+
if language_code is not None:
|
|
182
|
+
body["languageCode"] = language_code
|
|
183
|
+
if first_name is not None:
|
|
184
|
+
body["firstName"] = first_name
|
|
185
|
+
if last_name is not None:
|
|
186
|
+
body["lastName"] = last_name
|
|
187
|
+
if originator_caller_id_enabled is not None:
|
|
188
|
+
body["originatorCallerIdEnabled"] = originator_caller_id_enabled
|
|
189
|
+
if dial_by_name is not None:
|
|
190
|
+
body["dialByName"] = dial_by_name
|
|
191
|
+
try:
|
|
192
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
193
|
+
except WebexError as e:
|
|
194
|
+
handle_rest_error(e)
|
|
195
|
+
typer.echo(f"Updated.")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@app.command("delete")
|
|
200
|
+
def delete(
|
|
201
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
202
|
+
paging_id: str = typer.Argument(help="pagingId"),
|
|
203
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
204
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
205
|
+
):
|
|
206
|
+
"""Delete a Paging Group."""
|
|
207
|
+
if not force:
|
|
208
|
+
typer.confirm(f"Delete {paging_id}?", abort=True)
|
|
209
|
+
api = get_api(debug=debug)
|
|
210
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/paging/{paging_id}"
|
|
211
|
+
params = {}
|
|
212
|
+
org_id = get_org_id()
|
|
213
|
+
if org_id is not None:
|
|
214
|
+
params["orgId"] = org_id
|
|
215
|
+
try:
|
|
216
|
+
api.session.rest_delete(url, params=params)
|
|
217
|
+
except WebexError as e:
|
|
218
|
+
handle_rest_error(e)
|
|
219
|
+
typer.echo(f"Deleted: {paging_id}")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@app.command("list-available-numbers")
|
|
224
|
+
def list_available_numbers(
|
|
225
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
226
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Filter phone numbers based on the comma-separated list provi"),
|
|
227
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
228
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
229
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
230
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
231
|
+
):
|
|
232
|
+
"""Get Paging Group Primary Available Phone Numbers."""
|
|
233
|
+
api = get_api(debug=debug)
|
|
234
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/paging/availableNumbers"
|
|
235
|
+
params = {}
|
|
236
|
+
if phone_number is not None:
|
|
237
|
+
params["phoneNumber"] = phone_number
|
|
238
|
+
if limit > 0:
|
|
239
|
+
params["max"] = limit
|
|
240
|
+
if offset > 0:
|
|
241
|
+
params["start"] = offset
|
|
242
|
+
org_id = get_org_id()
|
|
243
|
+
if org_id is not None:
|
|
244
|
+
params["orgId"] = org_id
|
|
245
|
+
result = None
|
|
246
|
+
try:
|
|
247
|
+
result = api.session.rest_get(url, params=params)
|
|
248
|
+
except WebexError as e:
|
|
249
|
+
handle_rest_error(e)
|
|
250
|
+
result = result or []
|
|
251
|
+
items = result.get("phoneNumbers", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
252
|
+
if output == "json":
|
|
253
|
+
print_json(items)
|
|
254
|
+
else:
|
|
255
|
+
print_table(items, columns=[('ID', 'id'), ('Name', 'name'), ('Extension', 'extension'), ('Location', 'locationName'), ('Enabled', 'enabled')], limit=limit)
|
|
256
|
+
|
|
257
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Calling partner-admins.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def cmd_list(
|
|
14
|
+
managed_by: str = typer.Option(..., "--managed-by", help="List customer orgs associated with this person ID."),
|
|
15
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
16
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
17
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
18
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
19
|
+
):
|
|
20
|
+
"""Get all customers managed by a partner admin."""
|
|
21
|
+
api = get_api(debug=debug)
|
|
22
|
+
url = f"https://webexapis.com/v1/partner/organizations"
|
|
23
|
+
params = {}
|
|
24
|
+
if managed_by is not None:
|
|
25
|
+
params["managedBy"] = managed_by
|
|
26
|
+
if limit > 0:
|
|
27
|
+
params["max"] = limit
|
|
28
|
+
if offset > 0:
|
|
29
|
+
params["start"] = offset
|
|
30
|
+
result = None
|
|
31
|
+
try:
|
|
32
|
+
result = api.session.rest_get(url, params=params)
|
|
33
|
+
except WebexError as e:
|
|
34
|
+
handle_rest_error(e)
|
|
35
|
+
result = result or []
|
|
36
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
37
|
+
if output == "json":
|
|
38
|
+
print_json(items)
|
|
39
|
+
else:
|
|
40
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.command("list-partner-admins")
|
|
45
|
+
def list_partner_admins(
|
|
46
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
47
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
48
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
49
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
50
|
+
):
|
|
51
|
+
"""Get all partner admins assigned to a customer."""
|
|
52
|
+
api = get_api(debug=debug)
|
|
53
|
+
org_id = resolve_org_id(api.session)
|
|
54
|
+
url = f"https://webexapis.com/v1/partner/organizations/{org_id}/partnerAdmins"
|
|
55
|
+
params = {}
|
|
56
|
+
if limit > 0:
|
|
57
|
+
params["max"] = limit
|
|
58
|
+
if offset > 0:
|
|
59
|
+
params["start"] = offset
|
|
60
|
+
result = None
|
|
61
|
+
try:
|
|
62
|
+
result = api.session.rest_get(url, params=params)
|
|
63
|
+
except WebexError as e:
|
|
64
|
+
handle_rest_error(e)
|
|
65
|
+
result = result or []
|
|
66
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
67
|
+
if output == "json":
|
|
68
|
+
print_json(items)
|
|
69
|
+
else:
|
|
70
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@app.command("create")
|
|
75
|
+
def create(
|
|
76
|
+
person_id: str = typer.Argument(help="personId"),
|
|
77
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
78
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
79
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
80
|
+
):
|
|
81
|
+
"""Assign partner admin to a customer."""
|
|
82
|
+
api = get_api(debug=debug)
|
|
83
|
+
org_id = resolve_org_id(api.session)
|
|
84
|
+
url = f"https://webexapis.com/v1/partner/organizations/{org_id}/partnerAdmin/{person_id}/assign"
|
|
85
|
+
if json_body:
|
|
86
|
+
body = json.loads(json_body)
|
|
87
|
+
else:
|
|
88
|
+
body = {}
|
|
89
|
+
try:
|
|
90
|
+
result = api.session.rest_post(url, json=body)
|
|
91
|
+
except WebexError as e:
|
|
92
|
+
handle_rest_error(e)
|
|
93
|
+
if output == "json":
|
|
94
|
+
print_json(result)
|
|
95
|
+
elif isinstance(result, dict) and "id" in result:
|
|
96
|
+
typer.echo(f"Created: {result['id']}")
|
|
97
|
+
elif not result or result == {}:
|
|
98
|
+
typer.echo("Created.")
|
|
99
|
+
else:
|
|
100
|
+
print_json(result)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@app.command("delete")
|
|
105
|
+
def delete(
|
|
106
|
+
person_id: str = typer.Argument(help="personId"),
|
|
107
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
108
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
109
|
+
):
|
|
110
|
+
"""Unassign partner admin from a customer."""
|
|
111
|
+
if not force:
|
|
112
|
+
typer.confirm(f"Delete {person_id}?", abort=True)
|
|
113
|
+
api = get_api(debug=debug)
|
|
114
|
+
org_id = resolve_org_id(api.session)
|
|
115
|
+
url = f"https://webexapis.com/v1/partner/organizations/{org_id}/partnerAdmin/{person_id}/unassign"
|
|
116
|
+
try:
|
|
117
|
+
api.session.rest_delete(url)
|
|
118
|
+
except WebexError as e:
|
|
119
|
+
handle_rest_error(e)
|
|
120
|
+
typer.echo(f"Deleted: {person_id}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@app.command("delete-partner-admin")
|
|
125
|
+
def delete_partner_admin(
|
|
126
|
+
person_id: str = typer.Argument(help="personId"),
|
|
127
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
128
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
129
|
+
):
|
|
130
|
+
"""Revoke all partner admin roles for a given person ID."""
|
|
131
|
+
if not force:
|
|
132
|
+
typer.confirm(f"Delete {person_id}?", abort=True)
|
|
133
|
+
api = get_api(debug=debug)
|
|
134
|
+
url = f"https://webexapis.com/v1/partner/organizations/partnerAdmin/{person_id}"
|
|
135
|
+
try:
|
|
136
|
+
api.session.rest_delete(url)
|
|
137
|
+
except WebexError as e:
|
|
138
|
+
handle_rest_error(e)
|
|
139
|
+
typer.echo(f"Deleted: {person_id}")
|
|
140
|
+
|
|
141
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
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 partner-reports.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("list")
|
|
12
|
+
def cmd_list(
|
|
13
|
+
service: str = typer.Option(None, "--service", help="List reports which use this service."),
|
|
14
|
+
template_id: str = typer.Option(None, "--template-id", help="List reports with this report template ID."),
|
|
15
|
+
from_param: str = typer.Option(None, "--from", help="List reports that were created on or after this date."),
|
|
16
|
+
to: str = typer.Option(None, "--to", help="List reports that were created before this date."),
|
|
17
|
+
region_id: str = typer.Option(None, "--region-id", help="Data in the report will be from organizations in this region"),
|
|
18
|
+
on_behalf_of_sub_partner_org_id: str = typer.Option(None, "--on-behalf-of-sub-partner-org-id", help="The encoded organization ID for the sub partner."),
|
|
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 Reports."""
|
|
25
|
+
api = get_api(debug=debug)
|
|
26
|
+
url = f"https://webexapis.com/v1/partner/reports"
|
|
27
|
+
params = {}
|
|
28
|
+
if service is not None:
|
|
29
|
+
params["service"] = service
|
|
30
|
+
if template_id is not None:
|
|
31
|
+
params["templateId"] = template_id
|
|
32
|
+
if from_param is not None:
|
|
33
|
+
params["from"] = from_param
|
|
34
|
+
if to is not None:
|
|
35
|
+
params["to"] = to
|
|
36
|
+
if region_id is not None:
|
|
37
|
+
params["regionId"] = region_id
|
|
38
|
+
if on_behalf_of_sub_partner_org_id is not None:
|
|
39
|
+
params["onBehalfOfSubPartnerOrgId"] = on_behalf_of_sub_partner_org_id
|
|
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("Report Attributes", 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
|
+
on_behalf_of_sub_partner_org_id: str = typer.Option(None, "--on-behalf-of-sub-partner-org-id", help="The encoded organization ID for the sub partner."),
|
|
61
|
+
template_id: str = typer.Option(None, "--template-id", help="(required) Unique ID representing valid report templates."),
|
|
62
|
+
start_date: str = typer.Option(None, "--start-date", help="(required) Data in the report will be from this date onwards."),
|
|
63
|
+
end_date: str = typer.Option(None, "--end-date", help="(required) Data in the report will be until this date."),
|
|
64
|
+
region_id: str = typer.Option(None, "--region-id", help="Data in the report will be from organizations in this region"),
|
|
65
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
66
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
67
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
68
|
+
):
|
|
69
|
+
"""Create a Report."""
|
|
70
|
+
api = get_api(debug=debug)
|
|
71
|
+
url = f"https://webexapis.com/v1/partner/reports"
|
|
72
|
+
params = {}
|
|
73
|
+
if on_behalf_of_sub_partner_org_id is not None:
|
|
74
|
+
params["onBehalfOfSubPartnerOrgId"] = on_behalf_of_sub_partner_org_id
|
|
75
|
+
if json_body:
|
|
76
|
+
body = json.loads(json_body)
|
|
77
|
+
else:
|
|
78
|
+
body = {}
|
|
79
|
+
if template_id is not None:
|
|
80
|
+
body["templateId"] = template_id
|
|
81
|
+
if start_date is not None:
|
|
82
|
+
body["startDate"] = start_date
|
|
83
|
+
if end_date is not None:
|
|
84
|
+
body["endDate"] = end_date
|
|
85
|
+
if region_id is not None:
|
|
86
|
+
body["regionId"] = region_id
|
|
87
|
+
_missing = [f for f in ['templateId', 'startDate', 'endDate'] if f not in body or body[f] is None]
|
|
88
|
+
if _missing:
|
|
89
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
90
|
+
raise typer.Exit(1)
|
|
91
|
+
try:
|
|
92
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
93
|
+
except WebexError as e:
|
|
94
|
+
handle_rest_error(e)
|
|
95
|
+
if output == "json":
|
|
96
|
+
print_json(result)
|
|
97
|
+
elif isinstance(result, dict) and "id" in result:
|
|
98
|
+
typer.echo(f"Created: {result['id']}")
|
|
99
|
+
elif not result or result == {}:
|
|
100
|
+
typer.echo("Created.")
|
|
101
|
+
else:
|
|
102
|
+
print_json(result)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@app.command("show")
|
|
107
|
+
def show(
|
|
108
|
+
report_id: str = typer.Argument(help="reportId"),
|
|
109
|
+
on_behalf_of_sub_partner_org_id: str = typer.Option(None, "--on-behalf-of-sub-partner-org-id", help="The encoded organization ID for the sub partner."),
|
|
110
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
111
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
112
|
+
):
|
|
113
|
+
"""Get Report Details."""
|
|
114
|
+
api = get_api(debug=debug)
|
|
115
|
+
url = f"https://webexapis.com/v1/partner/reports/{report_id}"
|
|
116
|
+
params = {}
|
|
117
|
+
if on_behalf_of_sub_partner_org_id is not None:
|
|
118
|
+
params["onBehalfOfSubPartnerOrgId"] = on_behalf_of_sub_partner_org_id
|
|
119
|
+
try:
|
|
120
|
+
result = api.session.rest_get(url, params=params)
|
|
121
|
+
except WebexError as e:
|
|
122
|
+
handle_rest_error(e)
|
|
123
|
+
if output == "json":
|
|
124
|
+
print_json(result)
|
|
125
|
+
else:
|
|
126
|
+
if isinstance(result, dict):
|
|
127
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
128
|
+
elif isinstance(result, list):
|
|
129
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
130
|
+
else:
|
|
131
|
+
print_json(result)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@app.command("delete")
|
|
136
|
+
def delete(
|
|
137
|
+
report_id: str = typer.Argument(help="reportId"),
|
|
138
|
+
on_behalf_of_sub_partner_org_id: str = typer.Option(None, "--on-behalf-of-sub-partner-org-id", help="The encoded organization ID for the sub partner."),
|
|
139
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
140
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
141
|
+
):
|
|
142
|
+
"""Delete a Report."""
|
|
143
|
+
if not force:
|
|
144
|
+
typer.confirm(f"Delete {report_id}?", abort=True)
|
|
145
|
+
api = get_api(debug=debug)
|
|
146
|
+
url = f"https://webexapis.com/v1/partner/reports/{report_id}"
|
|
147
|
+
params = {}
|
|
148
|
+
if on_behalf_of_sub_partner_org_id is not None:
|
|
149
|
+
params["onBehalfOfSubPartnerOrgId"] = on_behalf_of_sub_partner_org_id
|
|
150
|
+
try:
|
|
151
|
+
api.session.rest_delete(url, params=params)
|
|
152
|
+
except WebexError as e:
|
|
153
|
+
handle_rest_error(e)
|
|
154
|
+
typer.echo(f"Deleted: {report_id}")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@app.command("list-templates")
|
|
159
|
+
def list_templates(
|
|
160
|
+
on_behalf_of_sub_partner_org_id: str = typer.Option(None, "--on-behalf-of-sub-partner-org-id", help="The encoded organization ID for the sub partner."),
|
|
161
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
162
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
163
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
164
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
165
|
+
):
|
|
166
|
+
"""List Report Templates."""
|
|
167
|
+
api = get_api(debug=debug)
|
|
168
|
+
url = f"https://webexapis.com/v1/partner/reports/templates"
|
|
169
|
+
params = {}
|
|
170
|
+
if on_behalf_of_sub_partner_org_id is not None:
|
|
171
|
+
params["onBehalfOfSubPartnerOrgId"] = on_behalf_of_sub_partner_org_id
|
|
172
|
+
if limit > 0:
|
|
173
|
+
params["max"] = limit
|
|
174
|
+
if offset > 0:
|
|
175
|
+
params["start"] = offset
|
|
176
|
+
result = None
|
|
177
|
+
try:
|
|
178
|
+
result = api.session.rest_get(url, params=params)
|
|
179
|
+
except WebexError as e:
|
|
180
|
+
handle_rest_error(e)
|
|
181
|
+
result = result or []
|
|
182
|
+
items = result.get("Template Collection", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
183
|
+
if output == "json":
|
|
184
|
+
print_json(items)
|
|
185
|
+
else:
|
|
186
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
187
|
+
|
|
188
|
+
|