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
wxcli/commands/pstn.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
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 pstn.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def cmd_list(
|
|
14
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
15
|
+
service_types: str = typer.Option(None, "--service-types", help="Use the `serviceTypes` parameter to fetch connections for th"),
|
|
16
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
17
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
18
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
19
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
20
|
+
):
|
|
21
|
+
"""Retrieve PSTN Connection Options for a Location."""
|
|
22
|
+
api = get_api(debug=debug)
|
|
23
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/connectionOptions"
|
|
24
|
+
params = {}
|
|
25
|
+
if service_types is not None:
|
|
26
|
+
params["serviceTypes"] = service_types
|
|
27
|
+
if limit > 0:
|
|
28
|
+
params["max"] = limit
|
|
29
|
+
if offset > 0:
|
|
30
|
+
params["start"] = offset
|
|
31
|
+
org_id = get_org_id()
|
|
32
|
+
if org_id is not None:
|
|
33
|
+
params["orgId"] = org_id
|
|
34
|
+
result = None
|
|
35
|
+
try:
|
|
36
|
+
result = api.session.rest_get(url, params=params)
|
|
37
|
+
except WebexError as e:
|
|
38
|
+
handle_rest_error(e)
|
|
39
|
+
result = result or []
|
|
40
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
41
|
+
if output == "json":
|
|
42
|
+
print_json(items)
|
|
43
|
+
else:
|
|
44
|
+
print_table(items, columns=[('ID', 'id'), ('Name', 'displayName'), ('PSTN Services', 'pstnServices')], limit=limit)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@app.command("list-connection")
|
|
49
|
+
def list_connection(
|
|
50
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
51
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
52
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
53
|
+
):
|
|
54
|
+
"""Retrieve PSTN Connection for a Location."""
|
|
55
|
+
api = get_api(debug=debug)
|
|
56
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/connection"
|
|
57
|
+
params = {}
|
|
58
|
+
org_id = get_org_id()
|
|
59
|
+
if org_id is not None:
|
|
60
|
+
params["orgId"] = org_id
|
|
61
|
+
try:
|
|
62
|
+
result = api.session.rest_get(url, params=params)
|
|
63
|
+
except WebexError as e:
|
|
64
|
+
handle_rest_error(e)
|
|
65
|
+
if output == "json":
|
|
66
|
+
print_json(result)
|
|
67
|
+
else:
|
|
68
|
+
if isinstance(result, dict):
|
|
69
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
70
|
+
elif isinstance(result, list):
|
|
71
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
72
|
+
else:
|
|
73
|
+
print_json(result)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@app.command("update")
|
|
78
|
+
def update(
|
|
79
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
80
|
+
id_param: str = typer.Option(None, "--id", help="A unique identifier for the connection. This is required for"),
|
|
81
|
+
premise_route_type: str = typer.Option(None, "--premise-route-type", help="Premise route type. The possible types are TRUNK and ROUTE_G"),
|
|
82
|
+
premise_route_id: str = typer.Option(None, "--premise-route-id", help="Premise route ID. This refers to either a Trunk ID or a Rout"),
|
|
83
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
84
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
85
|
+
):
|
|
86
|
+
"""Setup PSTN Connection for a Location."""
|
|
87
|
+
api = get_api(debug=debug)
|
|
88
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/connection"
|
|
89
|
+
params = {}
|
|
90
|
+
org_id = get_org_id()
|
|
91
|
+
if org_id is not None:
|
|
92
|
+
params["orgId"] = org_id
|
|
93
|
+
if json_body:
|
|
94
|
+
body = json.loads(json_body)
|
|
95
|
+
else:
|
|
96
|
+
body = {}
|
|
97
|
+
if id_param is not None:
|
|
98
|
+
body["id"] = id_param
|
|
99
|
+
if premise_route_type is not None:
|
|
100
|
+
body["premiseRouteType"] = premise_route_type
|
|
101
|
+
if premise_route_id is not None:
|
|
102
|
+
body["premiseRouteId"] = premise_route_id
|
|
103
|
+
try:
|
|
104
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
105
|
+
except WebexError as e:
|
|
106
|
+
handle_rest_error(e)
|
|
107
|
+
typer.echo(f"Updated.")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@app.command("update-emergency-address")
|
|
112
|
+
def update_emergency_address(
|
|
113
|
+
phone_number: str = typer.Argument(help="phoneNumber"),
|
|
114
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
115
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
116
|
+
):
|
|
117
|
+
"""Update the Emergency Address for a Phone Number\n\nExample --json-body:\n '{"emergencyAddress":{"address1":"...","address2":"...","city":"...","state":"...","postalCode":"...","country":"..."}}'."""
|
|
118
|
+
api = get_api(debug=debug)
|
|
119
|
+
url = f"https://webexapis.com/v1/telephony/pstn/numbers/{phone_number}/emergencyAddress"
|
|
120
|
+
params = {}
|
|
121
|
+
org_id = get_org_id()
|
|
122
|
+
if org_id is not None:
|
|
123
|
+
params["orgId"] = org_id
|
|
124
|
+
if json_body:
|
|
125
|
+
body = json.loads(json_body)
|
|
126
|
+
else:
|
|
127
|
+
body = {}
|
|
128
|
+
try:
|
|
129
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
130
|
+
except WebexError as e:
|
|
131
|
+
handle_rest_error(e)
|
|
132
|
+
typer.echo(f"Updated.")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@app.command("create")
|
|
137
|
+
def create(
|
|
138
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
139
|
+
address1: str = typer.Option(None, "--address1", help="Primary street information for the emergency address."),
|
|
140
|
+
address2: str = typer.Option(None, "--address2", help="Apartment number or any other secondary information for the"),
|
|
141
|
+
city: str = typer.Option(None, "--city", help="City for the emergency address."),
|
|
142
|
+
state: str = typer.Option(None, "--state", help="State or Province or Region for the emergency address."),
|
|
143
|
+
postal_code: str = typer.Option(None, "--postal-code", help="Postal code for the emergency address."),
|
|
144
|
+
country: str = typer.Option(None, "--country", help="Country for the emergency address."),
|
|
145
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
146
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
147
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
148
|
+
):
|
|
149
|
+
"""Emergency Address Lookup to Verify if Address is Valid."""
|
|
150
|
+
api = get_api(debug=debug)
|
|
151
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/emergencyAddress/lookup"
|
|
152
|
+
params = {}
|
|
153
|
+
org_id = get_org_id()
|
|
154
|
+
if org_id is not None:
|
|
155
|
+
params["orgId"] = org_id
|
|
156
|
+
if json_body:
|
|
157
|
+
body = json.loads(json_body)
|
|
158
|
+
else:
|
|
159
|
+
body = {}
|
|
160
|
+
if address1 is not None:
|
|
161
|
+
body["address1"] = address1
|
|
162
|
+
if address2 is not None:
|
|
163
|
+
body["address2"] = address2
|
|
164
|
+
if city is not None:
|
|
165
|
+
body["city"] = city
|
|
166
|
+
if state is not None:
|
|
167
|
+
body["state"] = state
|
|
168
|
+
if postal_code is not None:
|
|
169
|
+
body["postalCode"] = postal_code
|
|
170
|
+
if country is not None:
|
|
171
|
+
body["country"] = country
|
|
172
|
+
try:
|
|
173
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
174
|
+
except WebexError as e:
|
|
175
|
+
handle_rest_error(e)
|
|
176
|
+
if output == "json":
|
|
177
|
+
print_json(result)
|
|
178
|
+
elif isinstance(result, dict) and "id" in result:
|
|
179
|
+
typer.echo(f"Created: {result['id']}")
|
|
180
|
+
elif not result or result == {}:
|
|
181
|
+
typer.echo("Created.")
|
|
182
|
+
else:
|
|
183
|
+
print_json(result)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@app.command("create-emergency-address")
|
|
188
|
+
def create_emergency_address(
|
|
189
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
190
|
+
address1: str = typer.Option(None, "--address1", help="Primary street information for the emergency address."),
|
|
191
|
+
address2: str = typer.Option(None, "--address2", help="Apartment number or any other secondary information for the"),
|
|
192
|
+
city: str = typer.Option(None, "--city", help="City for the emergency address."),
|
|
193
|
+
state: str = typer.Option(None, "--state", help="State or Province or Region for the emergency address."),
|
|
194
|
+
postal_code: str = typer.Option(None, "--postal-code", help="Postal code for the emergency address."),
|
|
195
|
+
country: str = typer.Option(None, "--country", help="Country for the emergency address."),
|
|
196
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
197
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
198
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
199
|
+
):
|
|
200
|
+
"""Add an Emergency Address to a Location."""
|
|
201
|
+
api = get_api(debug=debug)
|
|
202
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/emergencyAddress"
|
|
203
|
+
params = {}
|
|
204
|
+
org_id = get_org_id()
|
|
205
|
+
if org_id is not None:
|
|
206
|
+
params["orgId"] = org_id
|
|
207
|
+
if json_body:
|
|
208
|
+
body = json.loads(json_body)
|
|
209
|
+
else:
|
|
210
|
+
body = {}
|
|
211
|
+
if address1 is not None:
|
|
212
|
+
body["address1"] = address1
|
|
213
|
+
if address2 is not None:
|
|
214
|
+
body["address2"] = address2
|
|
215
|
+
if city is not None:
|
|
216
|
+
body["city"] = city
|
|
217
|
+
if state is not None:
|
|
218
|
+
body["state"] = state
|
|
219
|
+
if postal_code is not None:
|
|
220
|
+
body["postalCode"] = postal_code
|
|
221
|
+
if country is not None:
|
|
222
|
+
body["country"] = country
|
|
223
|
+
try:
|
|
224
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
225
|
+
except WebexError as e:
|
|
226
|
+
handle_rest_error(e)
|
|
227
|
+
if output == "json":
|
|
228
|
+
print_json(result)
|
|
229
|
+
elif isinstance(result, dict) and "id" in result:
|
|
230
|
+
typer.echo(f"Created: {result['id']}")
|
|
231
|
+
elif not result or result == {}:
|
|
232
|
+
typer.echo("Created.")
|
|
233
|
+
else:
|
|
234
|
+
print_json(result)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@app.command("update-emergency-addresses")
|
|
239
|
+
def update_emergency_addresses(
|
|
240
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
241
|
+
address_id: str = typer.Argument(help="addressId"),
|
|
242
|
+
address1: str = typer.Option(None, "--address1", help="Primary street information for the emergency address."),
|
|
243
|
+
address2: str = typer.Option(None, "--address2", help="Apartment number or any other secondary information for the"),
|
|
244
|
+
city: str = typer.Option(None, "--city", help="City for the emergency address."),
|
|
245
|
+
state: str = typer.Option(None, "--state", help="State or Province or Region for the emergency address."),
|
|
246
|
+
postal_code: str = typer.Option(None, "--postal-code", help="Postal code for the emergency address."),
|
|
247
|
+
country: str = typer.Option(None, "--country", help="Country for the emergency address."),
|
|
248
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
249
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
250
|
+
):
|
|
251
|
+
"""Update the Emergency Address of a Location."""
|
|
252
|
+
api = get_api(debug=debug)
|
|
253
|
+
url = f"https://webexapis.com/v1/telephony/pstn/locations/{location_id}/emergencyAddresses/{address_id}"
|
|
254
|
+
params = {}
|
|
255
|
+
org_id = get_org_id()
|
|
256
|
+
if org_id is not None:
|
|
257
|
+
params["orgId"] = org_id
|
|
258
|
+
if json_body:
|
|
259
|
+
body = json.loads(json_body)
|
|
260
|
+
else:
|
|
261
|
+
body = {}
|
|
262
|
+
if address1 is not None:
|
|
263
|
+
body["address1"] = address1
|
|
264
|
+
if address2 is not None:
|
|
265
|
+
body["address2"] = address2
|
|
266
|
+
if city is not None:
|
|
267
|
+
body["city"] = city
|
|
268
|
+
if state is not None:
|
|
269
|
+
body["state"] = state
|
|
270
|
+
if postal_code is not None:
|
|
271
|
+
body["postalCode"] = postal_code
|
|
272
|
+
if country is not None:
|
|
273
|
+
body["country"] = country
|
|
274
|
+
try:
|
|
275
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
276
|
+
except WebexError as e:
|
|
277
|
+
handle_rest_error(e)
|
|
278
|
+
typer.echo(f"Updated.")
|
|
279
|
+
|
|
280
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
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 recording-report.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("list")
|
|
12
|
+
def cmd_list(
|
|
13
|
+
from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for recording audit repor"),
|
|
14
|
+
to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for recording audit report"),
|
|
15
|
+
host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This parameter is only u"),
|
|
16
|
+
site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site which the API lists recording audit re"),
|
|
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
|
+
"""List of Recording Audit Report Summaries."""
|
|
23
|
+
api = get_api(debug=debug)
|
|
24
|
+
url = f"https://webexapis.com/v1/recordingReport/accessSummary"
|
|
25
|
+
params = {}
|
|
26
|
+
if from_param is not None:
|
|
27
|
+
params["from"] = from_param
|
|
28
|
+
if to is not None:
|
|
29
|
+
params["to"] = to
|
|
30
|
+
if host_email is not None:
|
|
31
|
+
params["hostEmail"] = host_email
|
|
32
|
+
if site_url is not None:
|
|
33
|
+
params["siteUrl"] = site_url
|
|
34
|
+
if limit > 0:
|
|
35
|
+
params["max"] = limit
|
|
36
|
+
if offset > 0:
|
|
37
|
+
params["start"] = offset
|
|
38
|
+
try:
|
|
39
|
+
if limit > 0:
|
|
40
|
+
result = api.session.rest_get(url, params=params)
|
|
41
|
+
result = result or {}
|
|
42
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
43
|
+
else:
|
|
44
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
|
|
45
|
+
except WebexError as e:
|
|
46
|
+
handle_rest_error(e)
|
|
47
|
+
if output == "json":
|
|
48
|
+
print_json(items)
|
|
49
|
+
else:
|
|
50
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@app.command("list-access-detail")
|
|
55
|
+
def list_access_detail(
|
|
56
|
+
recording_id: str = typer.Option(..., "--recording-id", help="A unique identifier for the recording."),
|
|
57
|
+
host_email: str = typer.Option(None, "--host-email", help="Email address for the meeting host. This parameter is only u"),
|
|
58
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
59
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
60
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
61
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
62
|
+
):
|
|
63
|
+
"""Get Recording Audit Report Details."""
|
|
64
|
+
api = get_api(debug=debug)
|
|
65
|
+
url = f"https://webexapis.com/v1/recordingReport/accessDetail"
|
|
66
|
+
params = {}
|
|
67
|
+
if recording_id is not None:
|
|
68
|
+
params["recordingId"] = recording_id
|
|
69
|
+
if host_email is not None:
|
|
70
|
+
params["hostEmail"] = host_email
|
|
71
|
+
if limit > 0:
|
|
72
|
+
params["max"] = limit
|
|
73
|
+
if offset > 0:
|
|
74
|
+
params["start"] = offset
|
|
75
|
+
try:
|
|
76
|
+
if limit > 0:
|
|
77
|
+
result = api.session.rest_get(url, params=params)
|
|
78
|
+
result = result or {}
|
|
79
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
80
|
+
else:
|
|
81
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
|
|
82
|
+
except WebexError as e:
|
|
83
|
+
handle_rest_error(e)
|
|
84
|
+
if output == "json":
|
|
85
|
+
print_json(items)
|
|
86
|
+
else:
|
|
87
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@app.command("list-meeting-archive-summaries")
|
|
92
|
+
def list_meeting_archive_summaries(
|
|
93
|
+
from_param: str = typer.Option(None, "--from", help="Starting date and time (inclusive) for meeting archive summa"),
|
|
94
|
+
to: str = typer.Option(None, "--to", help="Ending date and time (exclusive) for meeting archive summari"),
|
|
95
|
+
site_url: str = typer.Option(None, "--site-url", help="URL of the Webex site which the API lists meeting archive su"),
|
|
96
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
97
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
98
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
99
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
100
|
+
):
|
|
101
|
+
"""List Meeting Archive Summaries."""
|
|
102
|
+
api = get_api(debug=debug)
|
|
103
|
+
url = f"https://webexapis.com/v1/recordingReport/meetingArchiveSummaries"
|
|
104
|
+
params = {}
|
|
105
|
+
if from_param is not None:
|
|
106
|
+
params["from"] = from_param
|
|
107
|
+
if to is not None:
|
|
108
|
+
params["to"] = to
|
|
109
|
+
if site_url is not None:
|
|
110
|
+
params["siteUrl"] = site_url
|
|
111
|
+
if limit > 0:
|
|
112
|
+
params["max"] = limit
|
|
113
|
+
if offset > 0:
|
|
114
|
+
params["start"] = offset
|
|
115
|
+
try:
|
|
116
|
+
if limit > 0:
|
|
117
|
+
result = api.session.rest_get(url, params=params)
|
|
118
|
+
result = result or {}
|
|
119
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
120
|
+
else:
|
|
121
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
|
|
122
|
+
except WebexError as e:
|
|
123
|
+
handle_rest_error(e)
|
|
124
|
+
if output == "json":
|
|
125
|
+
print_json(items)
|
|
126
|
+
else:
|
|
127
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@app.command("show")
|
|
132
|
+
def show(
|
|
133
|
+
archive_id: str = typer.Argument(help="archiveId"),
|
|
134
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
135
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
136
|
+
):
|
|
137
|
+
"""Get Meeting Archive Details."""
|
|
138
|
+
api = get_api(debug=debug)
|
|
139
|
+
url = f"https://webexapis.com/v1/recordingReport/meetingArchives/{archive_id}"
|
|
140
|
+
try:
|
|
141
|
+
result = api.session.rest_get(url)
|
|
142
|
+
except WebexError as e:
|
|
143
|
+
handle_rest_error(e)
|
|
144
|
+
if output == "json":
|
|
145
|
+
print_json(result)
|
|
146
|
+
else:
|
|
147
|
+
if isinstance(result, dict):
|
|
148
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
149
|
+
elif isinstance(result, list):
|
|
150
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
151
|
+
else:
|
|
152
|
+
print_json(result)
|
|
153
|
+
|
|
154
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
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 report-templates.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("list")
|
|
12
|
+
def cmd_list(
|
|
13
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
14
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
15
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
16
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
17
|
+
):
|
|
18
|
+
"""List Report Templates."""
|
|
19
|
+
api = get_api(debug=debug)
|
|
20
|
+
url = f"https://webexapis.com/v1/report/templates"
|
|
21
|
+
params = {}
|
|
22
|
+
if limit > 0:
|
|
23
|
+
params["max"] = limit
|
|
24
|
+
if offset > 0:
|
|
25
|
+
params["start"] = offset
|
|
26
|
+
result = None
|
|
27
|
+
try:
|
|
28
|
+
result = api.session.rest_get(url, params=params)
|
|
29
|
+
except WebexError as e:
|
|
30
|
+
handle_rest_error(e)
|
|
31
|
+
result = result or []
|
|
32
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
33
|
+
if output == "json":
|
|
34
|
+
print_json(items)
|
|
35
|
+
else:
|
|
36
|
+
print_table(items, columns=[('ID', 'Id'), ('Title', 'title'), ('Service', 'service'), ('Max Days', 'maxDays')], limit=limit)
|
|
37
|
+
|
|
38
|
+
|
|
@@ -0,0 +1,144 @@
|
|
|
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 reports.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("list")
|
|
12
|
+
def cmd_list(
|
|
13
|
+
report_id: str = typer.Option(None, "--report-id", help="List reports by ID."),
|
|
14
|
+
service: str = typer.Option(None, "--service", help="List reports which use this service."),
|
|
15
|
+
template_id: str = typer.Option(None, "--template-id", help="List reports with this report template ID."),
|
|
16
|
+
from_param: str = typer.Option(None, "--from", help="List reports that were created on or after this date."),
|
|
17
|
+
to: str = typer.Option(None, "--to", help="List reports that were created before this date."),
|
|
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 Reports."""
|
|
24
|
+
api = get_api(debug=debug)
|
|
25
|
+
url = f"https://webexapis.com/v1/reports"
|
|
26
|
+
params = {}
|
|
27
|
+
if report_id is not None:
|
|
28
|
+
params["reportId"] = report_id
|
|
29
|
+
if service is not None:
|
|
30
|
+
params["service"] = service
|
|
31
|
+
if template_id is not None:
|
|
32
|
+
params["templateId"] = template_id
|
|
33
|
+
if from_param is not None:
|
|
34
|
+
params["from"] = from_param
|
|
35
|
+
if to is not None:
|
|
36
|
+
params["to"] = to
|
|
37
|
+
if limit > 0:
|
|
38
|
+
params["max"] = limit
|
|
39
|
+
if offset > 0:
|
|
40
|
+
params["start"] = offset
|
|
41
|
+
result = None
|
|
42
|
+
try:
|
|
43
|
+
result = api.session.rest_get(url, params=params)
|
|
44
|
+
except WebexError as e:
|
|
45
|
+
handle_rest_error(e)
|
|
46
|
+
result = result or []
|
|
47
|
+
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 [])
|
|
48
|
+
if output == "json":
|
|
49
|
+
print_json(items)
|
|
50
|
+
else:
|
|
51
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@app.command("create")
|
|
56
|
+
def create(
|
|
57
|
+
template_id: str = typer.Option(None, "--template-id", help="(required) Unique ID representing valid report templates."),
|
|
58
|
+
start_date: str = typer.Option(None, "--start-date", help="Data in the report will be from this date onwards."),
|
|
59
|
+
end_date: str = typer.Option(None, "--end-date", help="Data in the report will be until this date."),
|
|
60
|
+
site_list: str = typer.Option(None, "--site-list", help="Sites belonging to user's organization. This attribute is ne"),
|
|
61
|
+
time_zone: str = typer.Option(None, "--time-zone", help="Time zone used for report date and time values. Use an IANA"),
|
|
62
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
63
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
64
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
65
|
+
):
|
|
66
|
+
"""Create a Report."""
|
|
67
|
+
api = get_api(debug=debug)
|
|
68
|
+
url = f"https://webexapis.com/v1/reports"
|
|
69
|
+
if json_body:
|
|
70
|
+
body = json.loads(json_body)
|
|
71
|
+
else:
|
|
72
|
+
body = {}
|
|
73
|
+
if template_id is not None:
|
|
74
|
+
body["templateId"] = template_id
|
|
75
|
+
if start_date is not None:
|
|
76
|
+
body["startDate"] = start_date
|
|
77
|
+
if end_date is not None:
|
|
78
|
+
body["endDate"] = end_date
|
|
79
|
+
if site_list is not None:
|
|
80
|
+
body["siteList"] = site_list
|
|
81
|
+
if time_zone is not None:
|
|
82
|
+
body["timeZone"] = time_zone
|
|
83
|
+
_missing = [f for f in ['templateId'] if f not in body or body[f] is None]
|
|
84
|
+
if _missing:
|
|
85
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
86
|
+
raise typer.Exit(1)
|
|
87
|
+
try:
|
|
88
|
+
result = api.session.rest_post(url, json=body)
|
|
89
|
+
except WebexError as e:
|
|
90
|
+
handle_rest_error(e)
|
|
91
|
+
if output == "json":
|
|
92
|
+
print_json(result)
|
|
93
|
+
elif isinstance(result, dict) and "id" in result:
|
|
94
|
+
typer.echo(f"Created: {result['id']}")
|
|
95
|
+
elif not result or result == {}:
|
|
96
|
+
typer.echo("Created.")
|
|
97
|
+
else:
|
|
98
|
+
print_json(result)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@app.command("show")
|
|
103
|
+
def show(
|
|
104
|
+
report_id: str = typer.Argument(help="reportId"),
|
|
105
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
106
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
107
|
+
):
|
|
108
|
+
"""Get Report Details."""
|
|
109
|
+
api = get_api(debug=debug)
|
|
110
|
+
url = f"https://webexapis.com/v1/reports/{report_id}"
|
|
111
|
+
try:
|
|
112
|
+
result = api.session.rest_get(url)
|
|
113
|
+
except WebexError as e:
|
|
114
|
+
handle_rest_error(e)
|
|
115
|
+
if output == "json":
|
|
116
|
+
print_json(result)
|
|
117
|
+
else:
|
|
118
|
+
if isinstance(result, dict):
|
|
119
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
120
|
+
elif isinstance(result, list):
|
|
121
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
122
|
+
else:
|
|
123
|
+
print_json(result)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@app.command("delete")
|
|
128
|
+
def delete(
|
|
129
|
+
report_id: str = typer.Argument(help="reportId"),
|
|
130
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
131
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
132
|
+
):
|
|
133
|
+
"""Delete a Report."""
|
|
134
|
+
if not force:
|
|
135
|
+
typer.confirm(f"Delete {report_id}?", abort=True)
|
|
136
|
+
api = get_api(debug=debug)
|
|
137
|
+
url = f"https://webexapis.com/v1/reports/{report_id}"
|
|
138
|
+
try:
|
|
139
|
+
api.session.rest_delete(url)
|
|
140
|
+
except WebexError as e:
|
|
141
|
+
handle_rest_error(e)
|
|
142
|
+
typer.echo(f"Deleted: {report_id}")
|
|
143
|
+
|
|
144
|
+
|