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,1489 @@
|
|
|
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 device-settings.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def cmd_list(
|
|
14
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
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 Device Members."""
|
|
21
|
+
api = get_api(debug=debug)
|
|
22
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/members"
|
|
23
|
+
params = {}
|
|
24
|
+
if limit > 0:
|
|
25
|
+
params["max"] = limit
|
|
26
|
+
if offset > 0:
|
|
27
|
+
params["start"] = offset
|
|
28
|
+
org_id = get_org_id()
|
|
29
|
+
if org_id is not None:
|
|
30
|
+
params["orgId"] = org_id
|
|
31
|
+
result = None
|
|
32
|
+
try:
|
|
33
|
+
result = api.session.rest_get(url, params=params)
|
|
34
|
+
except WebexError as e:
|
|
35
|
+
handle_rest_error(e)
|
|
36
|
+
result = result or []
|
|
37
|
+
items = result.get("members", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
38
|
+
if output == "json":
|
|
39
|
+
print_json(items)
|
|
40
|
+
else:
|
|
41
|
+
print_table(items, columns=[('ID', 'id'), ('First Name', 'firstName'), ('Last Name', 'lastName'), ('Extension', 'extension'), ('Line Type', 'lineType')], limit=limit)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.command("update")
|
|
46
|
+
def update(
|
|
47
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
48
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
49
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
50
|
+
):
|
|
51
|
+
"""Update Members on the device\n\nExample --json-body:\n '{"members":[{"port":"...","id":"...","primaryOwner":"...","lineType":"...","lineWeight":"...","hotlineEnabled":"...","hotlineDestination":"...","allowCallDeclineEnabled":"..."}]}'."""
|
|
52
|
+
api = get_api(debug=debug)
|
|
53
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/members"
|
|
54
|
+
params = {}
|
|
55
|
+
org_id = get_org_id()
|
|
56
|
+
if org_id is not None:
|
|
57
|
+
params["orgId"] = org_id
|
|
58
|
+
if json_body:
|
|
59
|
+
body = json.loads(json_body)
|
|
60
|
+
else:
|
|
61
|
+
body = {}
|
|
62
|
+
try:
|
|
63
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
64
|
+
except WebexError as e:
|
|
65
|
+
handle_rest_error(e)
|
|
66
|
+
typer.echo(f"Updated.")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@app.command("list-available-members")
|
|
71
|
+
def list_available_members(
|
|
72
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
73
|
+
member_name: str = typer.Option(None, "--member-name", help="Search (Contains) numbers based on member name."),
|
|
74
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Search (Contains) based on number."),
|
|
75
|
+
location_id: str = typer.Option(None, "--location-id", help="Unique identifier for the location."),
|
|
76
|
+
extension: str = typer.Option(None, "--extension", help="Search (Contains) based on extension."),
|
|
77
|
+
usage_type: str = typer.Option(None, "--usage-type", help="Choices: DEVICE_OWNER, SHARED_LINE"),
|
|
78
|
+
order: str = typer.Option(None, "--order", help="Sort the list of available members on the device in ascendin"),
|
|
79
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
80
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
81
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
82
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
83
|
+
):
|
|
84
|
+
"""Search Members."""
|
|
85
|
+
api = get_api(debug=debug)
|
|
86
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/availableMembers"
|
|
87
|
+
params = {}
|
|
88
|
+
if member_name is not None:
|
|
89
|
+
params["memberName"] = member_name
|
|
90
|
+
if phone_number is not None:
|
|
91
|
+
params["phoneNumber"] = phone_number
|
|
92
|
+
if location_id is not None:
|
|
93
|
+
params["locationId"] = location_id
|
|
94
|
+
if extension is not None:
|
|
95
|
+
params["extension"] = extension
|
|
96
|
+
if usage_type is not None:
|
|
97
|
+
params["usageType"] = usage_type
|
|
98
|
+
if order is not None:
|
|
99
|
+
params["order"] = order
|
|
100
|
+
if limit > 0:
|
|
101
|
+
params["max"] = limit
|
|
102
|
+
if offset > 0:
|
|
103
|
+
params["start"] = offset
|
|
104
|
+
org_id = get_org_id()
|
|
105
|
+
if org_id is not None:
|
|
106
|
+
params["orgId"] = org_id
|
|
107
|
+
result = None
|
|
108
|
+
try:
|
|
109
|
+
result = api.session.rest_get(url, params=params)
|
|
110
|
+
except WebexError as e:
|
|
111
|
+
handle_rest_error(e)
|
|
112
|
+
result = result or []
|
|
113
|
+
items = result.get("members", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
114
|
+
if output == "json":
|
|
115
|
+
print_json(items)
|
|
116
|
+
else:
|
|
117
|
+
print_table(items, columns=[('ID', 'id'), ('First Name', 'firstName'), ('Last Name', 'lastName'), ('Phone Number', 'phoneNumber'), ('Member Type', 'memberType')], limit=limit)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@app.command("show")
|
|
122
|
+
def show(
|
|
123
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
124
|
+
member_name: str = typer.Option(None, "--member-name", help="Search (Contains) numbers based on member name."),
|
|
125
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Search (Contains) based on number."),
|
|
126
|
+
location_id: str = typer.Option(None, "--location-id", help="Unique identifier for the location."),
|
|
127
|
+
extension: str = typer.Option(None, "--extension", help="Search (Contains) based on extension."),
|
|
128
|
+
usage_type: str = typer.Option(None, "--usage-type", help="Choices: DEVICE_OWNER, SHARED_LINE"),
|
|
129
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
130
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
131
|
+
):
|
|
132
|
+
"""Get Count of Members."""
|
|
133
|
+
api = get_api(debug=debug)
|
|
134
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/availableMembers/count"
|
|
135
|
+
params = {}
|
|
136
|
+
if member_name is not None:
|
|
137
|
+
params["memberName"] = member_name
|
|
138
|
+
if phone_number is not None:
|
|
139
|
+
params["phoneNumber"] = phone_number
|
|
140
|
+
if location_id is not None:
|
|
141
|
+
params["locationId"] = location_id
|
|
142
|
+
if extension is not None:
|
|
143
|
+
params["extension"] = extension
|
|
144
|
+
if usage_type is not None:
|
|
145
|
+
params["usageType"] = usage_type
|
|
146
|
+
org_id = get_org_id()
|
|
147
|
+
if org_id is not None:
|
|
148
|
+
params["orgId"] = org_id
|
|
149
|
+
try:
|
|
150
|
+
result = api.session.rest_get(url, params=params)
|
|
151
|
+
except WebexError as e:
|
|
152
|
+
handle_rest_error(e)
|
|
153
|
+
if output == "json":
|
|
154
|
+
print_json(result)
|
|
155
|
+
else:
|
|
156
|
+
if isinstance(result, dict):
|
|
157
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
158
|
+
elif isinstance(result, list):
|
|
159
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
160
|
+
else:
|
|
161
|
+
print_json(result)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@app.command("show-count-available-members")
|
|
166
|
+
def show_count_available_members(
|
|
167
|
+
member_name: str = typer.Option(None, "--member-name", help="Search (Contains) numbers based on member name."),
|
|
168
|
+
phone_number: str = typer.Option(None, "--phone-number", help="Search (Contains) based on number."),
|
|
169
|
+
location_id: str = typer.Option(None, "--location-id", help="Unique identifier for the location."),
|
|
170
|
+
extension: str = typer.Option(None, "--extension", help="Search (Contains) based on extension."),
|
|
171
|
+
usage_type: str = typer.Option(None, "--usage-type", help="Choices: DEVICE_OWNER, SHARED_LINE"),
|
|
172
|
+
exclude_virtual_line: str = typer.Option(None, "--exclude-virtual-line", help="If true, filters out virtual lines from the available member"),
|
|
173
|
+
device_location_id: str = typer.Option(None, "--device-location-id", help="Unique identifier for the device's location. When specified,"),
|
|
174
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
175
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
176
|
+
):
|
|
177
|
+
"""Get Count of Available Members."""
|
|
178
|
+
api = get_api(debug=debug)
|
|
179
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/availableMembers/count"
|
|
180
|
+
params = {}
|
|
181
|
+
if member_name is not None:
|
|
182
|
+
params["memberName"] = member_name
|
|
183
|
+
if phone_number is not None:
|
|
184
|
+
params["phoneNumber"] = phone_number
|
|
185
|
+
if location_id is not None:
|
|
186
|
+
params["locationId"] = location_id
|
|
187
|
+
if extension is not None:
|
|
188
|
+
params["extension"] = extension
|
|
189
|
+
if usage_type is not None:
|
|
190
|
+
params["usageType"] = usage_type
|
|
191
|
+
if exclude_virtual_line is not None:
|
|
192
|
+
params["excludeVirtualLine"] = exclude_virtual_line
|
|
193
|
+
if device_location_id is not None:
|
|
194
|
+
params["deviceLocationId"] = device_location_id
|
|
195
|
+
org_id = get_org_id()
|
|
196
|
+
if org_id is not None:
|
|
197
|
+
params["orgId"] = org_id
|
|
198
|
+
try:
|
|
199
|
+
result = api.session.rest_get(url, params=params)
|
|
200
|
+
except WebexError as e:
|
|
201
|
+
handle_rest_error(e)
|
|
202
|
+
if output == "json":
|
|
203
|
+
print_json(result)
|
|
204
|
+
else:
|
|
205
|
+
if isinstance(result, dict):
|
|
206
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
207
|
+
elif isinstance(result, list):
|
|
208
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
209
|
+
else:
|
|
210
|
+
print_json(result)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@app.command("apply-changes-for")
|
|
215
|
+
def apply_changes_for(
|
|
216
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
217
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body"),
|
|
218
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
219
|
+
):
|
|
220
|
+
"""Apply Changes for a specific device."""
|
|
221
|
+
api = get_api(debug=debug)
|
|
222
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/actions/applyChanges/invoke"
|
|
223
|
+
params = {}
|
|
224
|
+
org_id = get_org_id()
|
|
225
|
+
if org_id is not None:
|
|
226
|
+
params["orgId"] = org_id
|
|
227
|
+
if json_body:
|
|
228
|
+
body = json.loads(json_body)
|
|
229
|
+
else:
|
|
230
|
+
body = {}
|
|
231
|
+
try:
|
|
232
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
233
|
+
except WebexError as e:
|
|
234
|
+
handle_rest_error(e)
|
|
235
|
+
print_json(result)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@app.command("show-settings-devices")
|
|
240
|
+
def show_settings_devices(
|
|
241
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
242
|
+
device_model: str = typer.Option(None, "--device-model", help="The model type of the device. The corresponding device model"),
|
|
243
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
244
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
245
|
+
):
|
|
246
|
+
"""Get Device Settings."""
|
|
247
|
+
api = get_api(debug=debug)
|
|
248
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/settings"
|
|
249
|
+
params = {}
|
|
250
|
+
if device_model is not None:
|
|
251
|
+
params["deviceModel"] = device_model
|
|
252
|
+
org_id = get_org_id()
|
|
253
|
+
if org_id is not None:
|
|
254
|
+
params["orgId"] = org_id
|
|
255
|
+
try:
|
|
256
|
+
result = api.session.rest_get(url, params=params)
|
|
257
|
+
except WebexError as e:
|
|
258
|
+
handle_rest_error(e)
|
|
259
|
+
if output == "json":
|
|
260
|
+
print_json(result)
|
|
261
|
+
else:
|
|
262
|
+
if isinstance(result, dict):
|
|
263
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
264
|
+
elif isinstance(result, list):
|
|
265
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
266
|
+
else:
|
|
267
|
+
print_json(result)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@app.command("update-settings-devices")
|
|
272
|
+
def update_settings_devices(
|
|
273
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
274
|
+
device_model: str = typer.Option(None, "--device-model", help="The model type of the device. The corresponding device model"),
|
|
275
|
+
custom_enabled: bool = typer.Option(None, "--custom-enabled/--no-custom-enabled", help="Indicates if customization is allowed at a device level. If"),
|
|
276
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
277
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
278
|
+
):
|
|
279
|
+
"""Update device settings\n\nExample --json-body:\n '{"customizations":{"ata":{"audioCodecPriority":"...","ataDtmfMode":"...","ataDtmfMethod":"...","cdpEnabled":"...","lldpEnabled":"...","qosEnabled":"...","vlan":"...","webAccessEnabled":"..."},"mpp":{"pnacEnabled":"...","audioCodecPriority":"...","backlightTimer":"...","background":"...","cdpEnabled":"...","defaultLoggingLevel":"...","dndServicesEnabled":"...","acd":"..."},"wifi":{"audioCodecPriority":"...","ldap":"...","webAccess":"...","phoneSecurityPwd":"..."}},"customEnabled":true}'."""
|
|
280
|
+
api = get_api(debug=debug)
|
|
281
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/settings"
|
|
282
|
+
params = {}
|
|
283
|
+
if device_model is not None:
|
|
284
|
+
params["deviceModel"] = device_model
|
|
285
|
+
org_id = get_org_id()
|
|
286
|
+
if org_id is not None:
|
|
287
|
+
params["orgId"] = org_id
|
|
288
|
+
if json_body:
|
|
289
|
+
body = json.loads(json_body)
|
|
290
|
+
else:
|
|
291
|
+
body = {}
|
|
292
|
+
if custom_enabled is not None:
|
|
293
|
+
body["customEnabled"] = custom_enabled
|
|
294
|
+
try:
|
|
295
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
296
|
+
except WebexError as e:
|
|
297
|
+
handle_rest_error(e)
|
|
298
|
+
typer.echo(f"Updated.")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@app.command("show-settings-devices-1")
|
|
303
|
+
def show_settings_devices_1(
|
|
304
|
+
location_id: str = typer.Argument(help="locationId"),
|
|
305
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
306
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
307
|
+
):
|
|
308
|
+
"""Get Location Device Settings."""
|
|
309
|
+
api = get_api(debug=debug)
|
|
310
|
+
url = f"https://webexapis.com/v1/telephony/config/locations/{location_id}/devices/settings"
|
|
311
|
+
params = {}
|
|
312
|
+
org_id = get_org_id()
|
|
313
|
+
if org_id is not None:
|
|
314
|
+
params["orgId"] = org_id
|
|
315
|
+
try:
|
|
316
|
+
result = api.session.rest_get(url, params=params)
|
|
317
|
+
except WebexError as e:
|
|
318
|
+
handle_rest_error(e)
|
|
319
|
+
if output == "json":
|
|
320
|
+
print_json(result)
|
|
321
|
+
else:
|
|
322
|
+
if isinstance(result, dict):
|
|
323
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
324
|
+
elif isinstance(result, list):
|
|
325
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
326
|
+
else:
|
|
327
|
+
print_json(result)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@app.command("show-devices")
|
|
332
|
+
def show_devices(
|
|
333
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
334
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
335
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
336
|
+
):
|
|
337
|
+
"""Get Webex Calling Device Details."""
|
|
338
|
+
api = get_api(debug=debug)
|
|
339
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}"
|
|
340
|
+
params = {}
|
|
341
|
+
org_id = get_org_id()
|
|
342
|
+
if org_id is not None:
|
|
343
|
+
params["orgId"] = org_id
|
|
344
|
+
try:
|
|
345
|
+
result = api.session.rest_get(url, params=params)
|
|
346
|
+
except WebexError as e:
|
|
347
|
+
handle_rest_error(e)
|
|
348
|
+
if output == "json":
|
|
349
|
+
print_json(result)
|
|
350
|
+
else:
|
|
351
|
+
if isinstance(result, dict):
|
|
352
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
353
|
+
elif isinstance(result, list):
|
|
354
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
355
|
+
else:
|
|
356
|
+
print_json(result)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@app.command("update-devices-config")
|
|
361
|
+
def update_devices_config(
|
|
362
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
363
|
+
sip_password: str = typer.Option(None, "--sip-password", help="Password to be updated."),
|
|
364
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
365
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
366
|
+
):
|
|
367
|
+
"""Update Third Party Device."""
|
|
368
|
+
api = get_api(debug=debug)
|
|
369
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}"
|
|
370
|
+
params = {}
|
|
371
|
+
org_id = get_org_id()
|
|
372
|
+
if org_id is not None:
|
|
373
|
+
params["orgId"] = org_id
|
|
374
|
+
if json_body:
|
|
375
|
+
body = json.loads(json_body)
|
|
376
|
+
else:
|
|
377
|
+
body = {}
|
|
378
|
+
if sip_password is not None:
|
|
379
|
+
body["sipPassword"] = sip_password
|
|
380
|
+
try:
|
|
381
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
382
|
+
except WebexError as e:
|
|
383
|
+
handle_rest_error(e)
|
|
384
|
+
typer.echo(f"Updated.")
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
@app.command("list-devices-people")
|
|
389
|
+
def list_devices_people(
|
|
390
|
+
person_id: str = typer.Argument(help="personId"),
|
|
391
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
392
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
393
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
394
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
395
|
+
):
|
|
396
|
+
"""Get Person Devices."""
|
|
397
|
+
api = get_api(debug=debug)
|
|
398
|
+
url = f"https://webexapis.com/v1/telephony/config/people/{person_id}/devices"
|
|
399
|
+
params = {}
|
|
400
|
+
if limit > 0:
|
|
401
|
+
params["max"] = limit
|
|
402
|
+
if offset > 0:
|
|
403
|
+
params["start"] = offset
|
|
404
|
+
org_id = get_org_id()
|
|
405
|
+
if org_id is not None:
|
|
406
|
+
params["orgId"] = org_id
|
|
407
|
+
result = None
|
|
408
|
+
try:
|
|
409
|
+
result = api.session.rest_get(url, params=params)
|
|
410
|
+
except WebexError as e:
|
|
411
|
+
handle_rest_error(e)
|
|
412
|
+
result = result or []
|
|
413
|
+
items = result.get("devices", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
414
|
+
if output == "json":
|
|
415
|
+
print_json(items)
|
|
416
|
+
else:
|
|
417
|
+
print_table(items, columns=[('ID', 'id'), ('Model', 'model'), ('MAC', 'mac'), ('Type', 'type')], limit=limit)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
@app.command("update-hoteling")
|
|
422
|
+
def update_hoteling(
|
|
423
|
+
person_id: str = typer.Argument(help="personId"),
|
|
424
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
425
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
426
|
+
):
|
|
427
|
+
"""Modify Hoteling Settings for a Person's Primary Devices\n\nExample --json-body:\n '{"hoteling":{"enabled":true,"limitGuestUse":true,"guestHoursLimit":0}}'."""
|
|
428
|
+
api = get_api(debug=debug)
|
|
429
|
+
url = f"https://webexapis.com/v1/telephony/config/people/{person_id}/devices/settings/hoteling"
|
|
430
|
+
params = {}
|
|
431
|
+
org_id = get_org_id()
|
|
432
|
+
if org_id is not None:
|
|
433
|
+
params["orgId"] = org_id
|
|
434
|
+
if json_body:
|
|
435
|
+
body = json.loads(json_body)
|
|
436
|
+
else:
|
|
437
|
+
body = {}
|
|
438
|
+
try:
|
|
439
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
440
|
+
except WebexError as e:
|
|
441
|
+
handle_rest_error(e)
|
|
442
|
+
typer.echo(f"Updated.")
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
@app.command("list-devices-workspaces")
|
|
447
|
+
def list_devices_workspaces(
|
|
448
|
+
workspace_id: str = typer.Argument(help="workspaceId"),
|
|
449
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
450
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
451
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
452
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
453
|
+
):
|
|
454
|
+
"""Get Workspace Devices."""
|
|
455
|
+
api = get_api(debug=debug)
|
|
456
|
+
url = f"https://webexapis.com/v1/telephony/config/workspaces/{workspace_id}/devices"
|
|
457
|
+
params = {}
|
|
458
|
+
if limit > 0:
|
|
459
|
+
params["max"] = limit
|
|
460
|
+
if offset > 0:
|
|
461
|
+
params["start"] = offset
|
|
462
|
+
org_id = get_org_id()
|
|
463
|
+
if org_id is not None:
|
|
464
|
+
params["orgId"] = org_id
|
|
465
|
+
result = None
|
|
466
|
+
try:
|
|
467
|
+
result = api.session.rest_get(url, params=params)
|
|
468
|
+
except WebexError as e:
|
|
469
|
+
handle_rest_error(e)
|
|
470
|
+
result = result or []
|
|
471
|
+
items = result.get("devices", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
472
|
+
if output == "json":
|
|
473
|
+
print_json(items)
|
|
474
|
+
else:
|
|
475
|
+
print_table(items, columns=[('ID', 'id'), ('Model', 'model'), ('MAC', 'mac'), ('Type', 'type')], limit=limit)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
@app.command("update-devices-workspaces")
|
|
480
|
+
def update_devices_workspaces(
|
|
481
|
+
workspace_id: str = typer.Argument(help="workspaceId"),
|
|
482
|
+
enabled: bool = typer.Option(None, "--enabled/--no-enabled", help="Enable/Disable hoteling Host. Enabling the device for hoteli"),
|
|
483
|
+
limit_guest_use: bool = typer.Option(None, "--limit-guest-use/--no-limit-guest-use", help="Enable limiting the time a guest can use the device. The tim"),
|
|
484
|
+
guest_hours_limit: str = typer.Option(None, "--guest-hours-limit", help="Time Limit in hours until hoteling is enabled. Mandatory if"),
|
|
485
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
486
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
487
|
+
):
|
|
488
|
+
"""Modify Workspace Devices."""
|
|
489
|
+
api = get_api(debug=debug)
|
|
490
|
+
url = f"https://webexapis.com/v1/telephony/config/workspaces/{workspace_id}/devices"
|
|
491
|
+
params = {}
|
|
492
|
+
org_id = get_org_id()
|
|
493
|
+
if org_id is not None:
|
|
494
|
+
params["orgId"] = org_id
|
|
495
|
+
if json_body:
|
|
496
|
+
body = json.loads(json_body)
|
|
497
|
+
else:
|
|
498
|
+
body = {}
|
|
499
|
+
if enabled is not None:
|
|
500
|
+
body["enabled"] = enabled
|
|
501
|
+
if limit_guest_use is not None:
|
|
502
|
+
body["limitGuestUse"] = limit_guest_use
|
|
503
|
+
if guest_hours_limit is not None:
|
|
504
|
+
body["guestHoursLimit"] = guest_hours_limit
|
|
505
|
+
try:
|
|
506
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
507
|
+
except WebexError as e:
|
|
508
|
+
handle_rest_error(e)
|
|
509
|
+
typer.echo(f"Updated.")
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@app.command("show-settings-devices-2")
|
|
514
|
+
def show_settings_devices_2(
|
|
515
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
516
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
517
|
+
):
|
|
518
|
+
"""Read the device override settings for a organization."""
|
|
519
|
+
api = get_api(debug=debug)
|
|
520
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/settings"
|
|
521
|
+
params = {}
|
|
522
|
+
org_id = get_org_id()
|
|
523
|
+
if org_id is not None:
|
|
524
|
+
params["orgId"] = org_id
|
|
525
|
+
try:
|
|
526
|
+
result = api.session.rest_get(url, params=params)
|
|
527
|
+
except WebexError as e:
|
|
528
|
+
handle_rest_error(e)
|
|
529
|
+
if output == "json":
|
|
530
|
+
print_json(result)
|
|
531
|
+
else:
|
|
532
|
+
if isinstance(result, dict):
|
|
533
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
534
|
+
elif isinstance(result, list):
|
|
535
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
536
|
+
else:
|
|
537
|
+
print_json(result)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
@app.command("list-line-key-templates")
|
|
542
|
+
def list_line_key_templates(
|
|
543
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
544
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
545
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
546
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
547
|
+
):
|
|
548
|
+
"""Read the list of Line Key Templates."""
|
|
549
|
+
api = get_api(debug=debug)
|
|
550
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/lineKeyTemplates"
|
|
551
|
+
params = {}
|
|
552
|
+
if limit > 0:
|
|
553
|
+
params["max"] = limit
|
|
554
|
+
if offset > 0:
|
|
555
|
+
params["start"] = offset
|
|
556
|
+
org_id = get_org_id()
|
|
557
|
+
if org_id is not None:
|
|
558
|
+
params["orgId"] = org_id
|
|
559
|
+
result = None
|
|
560
|
+
try:
|
|
561
|
+
result = api.session.rest_get(url, params=params)
|
|
562
|
+
except WebexError as e:
|
|
563
|
+
handle_rest_error(e)
|
|
564
|
+
result = result or []
|
|
565
|
+
items = result.get("lineKeyTemplates", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
566
|
+
if output == "json":
|
|
567
|
+
print_json(items)
|
|
568
|
+
else:
|
|
569
|
+
print_table(items, columns=[('ID', 'id'), ('Template Name', 'templateName'), ('Device Model', 'deviceModel'), ('Display Name', 'modelDisplayName')], limit=limit)
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
@app.command("create")
|
|
574
|
+
def create(
|
|
575
|
+
template_name: str = typer.Option(None, "--template-name", help="(required) Name of the Line Key Template."),
|
|
576
|
+
device_model: str = typer.Option(None, "--device-model", help="(required) The model of the device for which the Line Key Template is a"),
|
|
577
|
+
user_reorder_enabled: bool = typer.Option(None, "--user-reorder-enabled/--no-user-reorder-enabled", help="User Customization Enabled."),
|
|
578
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
579
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
580
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
581
|
+
):
|
|
582
|
+
"""Create a Line Key Template\n\nExample --json-body:\n '{"templateName":"...","deviceModel":"...","lineKeys":[{"lineKeyIndex":"...","lineKeyType":"...","sharedLineIndex":"...","lineKeyLabel":"...","lineKeyValue":"..."}],"userReorderEnabled":true}'."""
|
|
583
|
+
api = get_api(debug=debug)
|
|
584
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/lineKeyTemplates"
|
|
585
|
+
params = {}
|
|
586
|
+
org_id = get_org_id()
|
|
587
|
+
if org_id is not None:
|
|
588
|
+
params["orgId"] = org_id
|
|
589
|
+
if json_body:
|
|
590
|
+
body = json.loads(json_body)
|
|
591
|
+
else:
|
|
592
|
+
body = {}
|
|
593
|
+
if template_name is not None:
|
|
594
|
+
body["templateName"] = template_name
|
|
595
|
+
if device_model is not None:
|
|
596
|
+
body["deviceModel"] = device_model
|
|
597
|
+
if user_reorder_enabled is not None:
|
|
598
|
+
body["userReorderEnabled"] = user_reorder_enabled
|
|
599
|
+
_missing = [f for f in ['templateName', 'deviceModel'] if f not in body or body[f] is None]
|
|
600
|
+
if _missing:
|
|
601
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
602
|
+
raise typer.Exit(1)
|
|
603
|
+
try:
|
|
604
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
605
|
+
except WebexError as e:
|
|
606
|
+
handle_rest_error(e)
|
|
607
|
+
if output == "json":
|
|
608
|
+
print_json(result)
|
|
609
|
+
elif isinstance(result, dict) and "id" in result:
|
|
610
|
+
typer.echo(f"Created: {result['id']}")
|
|
611
|
+
elif not result or result == {}:
|
|
612
|
+
typer.echo("Created.")
|
|
613
|
+
else:
|
|
614
|
+
print_json(result)
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
@app.command("show-line-key-templates")
|
|
619
|
+
def show_line_key_templates(
|
|
620
|
+
template_id: str = typer.Argument(help="templateId"),
|
|
621
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
622
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
623
|
+
):
|
|
624
|
+
"""Get details of a Line Key Template."""
|
|
625
|
+
api = get_api(debug=debug)
|
|
626
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/lineKeyTemplates/{template_id}"
|
|
627
|
+
params = {}
|
|
628
|
+
org_id = get_org_id()
|
|
629
|
+
if org_id is not None:
|
|
630
|
+
params["orgId"] = org_id
|
|
631
|
+
try:
|
|
632
|
+
result = api.session.rest_get(url, params=params)
|
|
633
|
+
except WebexError as e:
|
|
634
|
+
handle_rest_error(e)
|
|
635
|
+
if output == "json":
|
|
636
|
+
print_json(result)
|
|
637
|
+
else:
|
|
638
|
+
if isinstance(result, dict):
|
|
639
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
640
|
+
elif isinstance(result, list):
|
|
641
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
642
|
+
else:
|
|
643
|
+
print_json(result)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
@app.command("update-line-key-templates")
|
|
648
|
+
def update_line_key_templates(
|
|
649
|
+
template_id: str = typer.Argument(help="templateId"),
|
|
650
|
+
user_reorder_enabled: bool = typer.Option(None, "--user-reorder-enabled/--no-user-reorder-enabled", help="Indicates whether the user can reorder the line keys."),
|
|
651
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
652
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
653
|
+
):
|
|
654
|
+
"""Modify a Line Key Template\n\nExample --json-body:\n '{"lineKeys":[{"lineKeyIndex":"...","lineKeyType":"...","sharedLineIndex":"...","lineKeyLabel":"...","lineKeyValue":"..."}],"userReorderEnabled":true}'."""
|
|
655
|
+
api = get_api(debug=debug)
|
|
656
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/lineKeyTemplates/{template_id}"
|
|
657
|
+
params = {}
|
|
658
|
+
org_id = get_org_id()
|
|
659
|
+
if org_id is not None:
|
|
660
|
+
params["orgId"] = org_id
|
|
661
|
+
if json_body:
|
|
662
|
+
body = json.loads(json_body)
|
|
663
|
+
else:
|
|
664
|
+
body = {}
|
|
665
|
+
if user_reorder_enabled is not None:
|
|
666
|
+
body["userReorderEnabled"] = user_reorder_enabled
|
|
667
|
+
try:
|
|
668
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
669
|
+
except WebexError as e:
|
|
670
|
+
handle_rest_error(e)
|
|
671
|
+
typer.echo(f"Updated.")
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
@app.command("delete")
|
|
676
|
+
def delete(
|
|
677
|
+
template_id: str = typer.Argument(help="templateId"),
|
|
678
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
679
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
680
|
+
):
|
|
681
|
+
"""Delete a Line Key Template."""
|
|
682
|
+
if not force:
|
|
683
|
+
typer.confirm(f"Delete {template_id}?", abort=True)
|
|
684
|
+
api = get_api(debug=debug)
|
|
685
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/lineKeyTemplates/{template_id}"
|
|
686
|
+
params = {}
|
|
687
|
+
org_id = get_org_id()
|
|
688
|
+
if org_id is not None:
|
|
689
|
+
params["orgId"] = org_id
|
|
690
|
+
try:
|
|
691
|
+
api.session.rest_delete(url, params=params)
|
|
692
|
+
except WebexError as e:
|
|
693
|
+
handle_rest_error(e)
|
|
694
|
+
typer.echo(f"Deleted: {template_id}")
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
@app.command("preview-apply-line")
|
|
699
|
+
def preview_apply_line(
|
|
700
|
+
action: str = typer.Option(None, "--action", help="Choices: APPLY_TEMPLATE, APPLY_DEFAULT_TEMPLATES"),
|
|
701
|
+
template_id: str = typer.Option(None, "--template-id", help="`templateId` is required for `APPLY_TEMPLATE` action."),
|
|
702
|
+
exclude_devices_with_custom_layout: str = typer.Option(None, "--exclude-devices-with-custom-layout", help="Indicates whether to exclude devices with custom layout."),
|
|
703
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body"),
|
|
704
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
705
|
+
):
|
|
706
|
+
"""Preview Apply Line Key Template\n\nExample --json-body:\n '{"action":"APPLY_TEMPLATE","templateId":"...","locationIds":["..."],"excludeDevicesWithCustomLayout":true,"includeDeviceTags":["..."],"excludeDeviceTags":["..."],"advisoryTypes":{"moreSharedAppearancesEnabled":true,"fewSharedAppearancesEnabled":true,"moreMonitorAppearancesEnabled":true,"moreCPEAppearancesEnabled":true,"moreModeManagementAppearancesEnabled":true}}'."""
|
|
707
|
+
api = get_api(debug=debug)
|
|
708
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/actions/previewApplyLineKeyTemplate/invoke"
|
|
709
|
+
params = {}
|
|
710
|
+
org_id = get_org_id()
|
|
711
|
+
if org_id is not None:
|
|
712
|
+
params["orgId"] = org_id
|
|
713
|
+
if json_body:
|
|
714
|
+
body = json.loads(json_body)
|
|
715
|
+
else:
|
|
716
|
+
body = {}
|
|
717
|
+
if action is not None:
|
|
718
|
+
body["action"] = action
|
|
719
|
+
if template_id is not None:
|
|
720
|
+
body["templateId"] = template_id
|
|
721
|
+
if exclude_devices_with_custom_layout is not None:
|
|
722
|
+
body["excludeDevicesWithCustomLayout"] = exclude_devices_with_custom_layout
|
|
723
|
+
try:
|
|
724
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
725
|
+
except WebexError as e:
|
|
726
|
+
handle_rest_error(e)
|
|
727
|
+
print_json(result)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
@app.command("list-apply-line-key-template")
|
|
732
|
+
def list_apply_line_key_template(
|
|
733
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
734
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
735
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
736
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
737
|
+
):
|
|
738
|
+
"""Get List of Apply Line Key Template jobs."""
|
|
739
|
+
api = get_api(debug=debug)
|
|
740
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/applyLineKeyTemplate"
|
|
741
|
+
params = {}
|
|
742
|
+
if limit > 0:
|
|
743
|
+
params["max"] = limit
|
|
744
|
+
if offset > 0:
|
|
745
|
+
params["start"] = offset
|
|
746
|
+
org_id = get_org_id()
|
|
747
|
+
if org_id is not None:
|
|
748
|
+
params["orgId"] = org_id
|
|
749
|
+
result = None
|
|
750
|
+
try:
|
|
751
|
+
result = api.session.rest_get(url, params=params)
|
|
752
|
+
except WebexError as e:
|
|
753
|
+
handle_rest_error(e)
|
|
754
|
+
result = result or []
|
|
755
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
756
|
+
if output == "json":
|
|
757
|
+
print_json(items)
|
|
758
|
+
else:
|
|
759
|
+
print_table(items, columns=[('ID', 'id'), ('Status', 'latestExecutionStatus')], limit=limit)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
@app.command("create-apply-line-key-template")
|
|
764
|
+
def create_apply_line_key_template(
|
|
765
|
+
action: str = typer.Option(None, "--action", help="(required) Choices: APPLY_TEMPLATE, APPLY_DEFAULT_TEMPLATES"),
|
|
766
|
+
template_id: str = typer.Option(None, "--template-id", help="(required) `templateId` is required for `APPLY_TEMPLATE` action."),
|
|
767
|
+
exclude_devices_with_custom_layout: bool = typer.Option(None, "--exclude-devices-with-custom-layout/--no-exclude-devices-with-custom-layout", help="Indicates whether to exclude devices with custom layout."),
|
|
768
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
769
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
770
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
771
|
+
):
|
|
772
|
+
"""Apply a Line Key Template\n\nExample --json-body:\n '{"action":"APPLY_TEMPLATE","templateId":"...","locationIds":["..."],"excludeDevicesWithCustomLayout":true,"includeDeviceTags":["..."],"excludeDeviceTags":["..."],"advisoryTypes":{"moreSharedAppearancesEnabled":true,"fewSharedAppearancesEnabled":true,"moreMonitorAppearancesEnabled":true,"moreCPEAppearancesEnabled":true,"moreModeManagementAppearancesEnabled":true}}'."""
|
|
773
|
+
api = get_api(debug=debug)
|
|
774
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/applyLineKeyTemplate"
|
|
775
|
+
params = {}
|
|
776
|
+
org_id = get_org_id()
|
|
777
|
+
if org_id is not None:
|
|
778
|
+
params["orgId"] = org_id
|
|
779
|
+
if json_body:
|
|
780
|
+
body = json.loads(json_body)
|
|
781
|
+
else:
|
|
782
|
+
body = {}
|
|
783
|
+
if action is not None:
|
|
784
|
+
body["action"] = action
|
|
785
|
+
if template_id is not None:
|
|
786
|
+
body["templateId"] = template_id
|
|
787
|
+
if exclude_devices_with_custom_layout is not None:
|
|
788
|
+
body["excludeDevicesWithCustomLayout"] = exclude_devices_with_custom_layout
|
|
789
|
+
_missing = [f for f in ['action', 'templateId'] if f not in body or body[f] is None]
|
|
790
|
+
if _missing:
|
|
791
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
792
|
+
raise typer.Exit(1)
|
|
793
|
+
try:
|
|
794
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
795
|
+
except WebexError as e:
|
|
796
|
+
handle_rest_error(e)
|
|
797
|
+
if output == "json":
|
|
798
|
+
print_json(result)
|
|
799
|
+
elif isinstance(result, dict) and "id" in result:
|
|
800
|
+
typer.echo(f"Created: {result['id']}")
|
|
801
|
+
elif not result or result == {}:
|
|
802
|
+
typer.echo("Created.")
|
|
803
|
+
else:
|
|
804
|
+
print_json(result)
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
@app.command("show-apply-line-key-template")
|
|
809
|
+
def show_apply_line_key_template(
|
|
810
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
811
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
812
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
813
|
+
):
|
|
814
|
+
"""Get the job status of an Apply Line Key Template job."""
|
|
815
|
+
api = get_api(debug=debug)
|
|
816
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/applyLineKeyTemplate/{job_id}"
|
|
817
|
+
params = {}
|
|
818
|
+
org_id = get_org_id()
|
|
819
|
+
if org_id is not None:
|
|
820
|
+
params["orgId"] = org_id
|
|
821
|
+
try:
|
|
822
|
+
result = api.session.rest_get(url, params=params)
|
|
823
|
+
except WebexError as e:
|
|
824
|
+
handle_rest_error(e)
|
|
825
|
+
if output == "json":
|
|
826
|
+
print_json(result)
|
|
827
|
+
else:
|
|
828
|
+
if isinstance(result, dict):
|
|
829
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
830
|
+
elif isinstance(result, list):
|
|
831
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
832
|
+
else:
|
|
833
|
+
print_json(result)
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
@app.command("show-errors")
|
|
838
|
+
def show_errors(
|
|
839
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
840
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
841
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
842
|
+
):
|
|
843
|
+
"""Get job errors for an Apply Line Key Template job."""
|
|
844
|
+
api = get_api(debug=debug)
|
|
845
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/applyLineKeyTemplate/{job_id}/errors"
|
|
846
|
+
params = {}
|
|
847
|
+
org_id = get_org_id()
|
|
848
|
+
if org_id is not None:
|
|
849
|
+
params["orgId"] = org_id
|
|
850
|
+
try:
|
|
851
|
+
result = api.session.rest_get(url, params=params)
|
|
852
|
+
except WebexError as e:
|
|
853
|
+
handle_rest_error(e)
|
|
854
|
+
if output == "json":
|
|
855
|
+
print_json(result)
|
|
856
|
+
else:
|
|
857
|
+
if isinstance(result, dict):
|
|
858
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
859
|
+
elif isinstance(result, list):
|
|
860
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
861
|
+
else:
|
|
862
|
+
print_json(result)
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
@app.command("list-supported-devices-dects")
|
|
867
|
+
def list_supported_devices_dects(
|
|
868
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
869
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
870
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
871
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
872
|
+
):
|
|
873
|
+
"""Read the DECT device type list - Deprecated."""
|
|
874
|
+
api = get_api(debug=debug)
|
|
875
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/dects/supportedDevices"
|
|
876
|
+
params = {}
|
|
877
|
+
if limit > 0:
|
|
878
|
+
params["max"] = limit
|
|
879
|
+
if offset > 0:
|
|
880
|
+
params["start"] = offset
|
|
881
|
+
org_id = get_org_id()
|
|
882
|
+
if org_id is not None:
|
|
883
|
+
params["orgId"] = org_id
|
|
884
|
+
try:
|
|
885
|
+
if limit > 0:
|
|
886
|
+
result = api.session.rest_get(url, params=params)
|
|
887
|
+
result = result or {}
|
|
888
|
+
items = result.get("devices", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
889
|
+
else:
|
|
890
|
+
if "max" not in params:
|
|
891
|
+
params["max"] = 1000
|
|
892
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="devices"))
|
|
893
|
+
except WebexError as e:
|
|
894
|
+
handle_rest_error(e)
|
|
895
|
+
if output == "json":
|
|
896
|
+
print_json(items)
|
|
897
|
+
else:
|
|
898
|
+
print_table(items, columns=[('Model', 'model'), ('Display Name', 'displayName'), ('Base Stations', 'numberOfBaseStations')], limit=limit)
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
@app.command("list-supported-devices-dect-networks")
|
|
903
|
+
def list_supported_devices_dect_networks(
|
|
904
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
905
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
906
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
907
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
908
|
+
):
|
|
909
|
+
"""Read the DECT device type list."""
|
|
910
|
+
api = get_api(debug=debug)
|
|
911
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/dectNetworks/supportedDevices"
|
|
912
|
+
params = {}
|
|
913
|
+
if limit > 0:
|
|
914
|
+
params["max"] = limit
|
|
915
|
+
if offset > 0:
|
|
916
|
+
params["start"] = offset
|
|
917
|
+
org_id = get_org_id()
|
|
918
|
+
if org_id is not None:
|
|
919
|
+
params["orgId"] = org_id
|
|
920
|
+
try:
|
|
921
|
+
if limit > 0:
|
|
922
|
+
result = api.session.rest_get(url, params=params)
|
|
923
|
+
result = result or {}
|
|
924
|
+
items = result.get("devices", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
925
|
+
else:
|
|
926
|
+
if "max" not in params:
|
|
927
|
+
params["max"] = 1000
|
|
928
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="devices"))
|
|
929
|
+
except WebexError as e:
|
|
930
|
+
handle_rest_error(e)
|
|
931
|
+
if output == "json":
|
|
932
|
+
print_json(items)
|
|
933
|
+
else:
|
|
934
|
+
print_table(items, columns=[('Model', 'model'), ('Display Name', 'displayName'), ('Base Stations', 'numberOfBaseStations')], limit=limit)
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
@app.command("validate-a-list")
|
|
939
|
+
def validate_a_list(
|
|
940
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body"),
|
|
941
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
942
|
+
):
|
|
943
|
+
"""Validate a list of MAC address\n\nExample --json-body:\n '{"macs":["..."]}'."""
|
|
944
|
+
api = get_api(debug=debug)
|
|
945
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/actions/validateMacs/invoke"
|
|
946
|
+
params = {}
|
|
947
|
+
org_id = get_org_id()
|
|
948
|
+
if org_id is not None:
|
|
949
|
+
params["orgId"] = org_id
|
|
950
|
+
if json_body:
|
|
951
|
+
body = json.loads(json_body)
|
|
952
|
+
else:
|
|
953
|
+
body = {}
|
|
954
|
+
try:
|
|
955
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
956
|
+
except WebexError as e:
|
|
957
|
+
handle_rest_error(e)
|
|
958
|
+
print_json(result)
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
@app.command("list-call-device-settings")
|
|
963
|
+
def list_call_device_settings(
|
|
964
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
965
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
966
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
967
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
968
|
+
):
|
|
969
|
+
"""List Change Device Settings Jobs."""
|
|
970
|
+
api = get_api(debug=debug)
|
|
971
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/callDeviceSettings"
|
|
972
|
+
params = {}
|
|
973
|
+
if limit > 0:
|
|
974
|
+
params["max"] = limit
|
|
975
|
+
if offset > 0:
|
|
976
|
+
params["start"] = offset
|
|
977
|
+
org_id = get_org_id()
|
|
978
|
+
if org_id is not None:
|
|
979
|
+
params["orgId"] = org_id
|
|
980
|
+
try:
|
|
981
|
+
if limit > 0:
|
|
982
|
+
result = api.session.rest_get(url, params=params)
|
|
983
|
+
result = result or {}
|
|
984
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
985
|
+
else:
|
|
986
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
|
|
987
|
+
except WebexError as e:
|
|
988
|
+
handle_rest_error(e)
|
|
989
|
+
if output == "json":
|
|
990
|
+
print_json(items)
|
|
991
|
+
else:
|
|
992
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
@app.command("create-call-device-settings")
|
|
997
|
+
def create_call_device_settings(
|
|
998
|
+
location_id: str = typer.Option(None, "--location-id", help="Location within an organization where changes of device seti"),
|
|
999
|
+
location_customizations_enabled: bool = typer.Option(None, "--location-customizations-enabled/--no-location-customizations-enabled", help="Indicates if all the devices within this location will be cu"),
|
|
1000
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
1001
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
1002
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1003
|
+
):
|
|
1004
|
+
"""Change Device Settings Across Organization Or Location Job\n\nExample --json-body:\n '{"locationId":"...","locationCustomizationsEnabled":true,"customizations":{"ata":{"audioCodecPriority":"...","ataDtmfMode":"...","ataDtmfMethod":"...","cdpEnabled":"...","lldpEnabled":"...","qosEnabled":"...","vlan":"...","webAccessEnabled":"..."},"dect":{"audioCodecPriority":"...","cdpEnabled":"...","dect6825HandsetEmergencyNumber":"...","lldpEnabled":"...","multicast":"...","qosEnabled":"...","vlan":"...","webAccessEnabled":"..."},"mpp":{"pnacEnabled":"...","audioCodecPriority":"...","backlightTimer":"...","background":"...","cdpEnabled":"...","defaultLoggingLevel":"...","dndServicesEnabled":"...","acd":"..."},"wifi":{"audioCodecPriority":"...","ldap":"...","webAccess":"...","phoneSecurityPwd":"..."}}}'."""
|
|
1005
|
+
api = get_api(debug=debug)
|
|
1006
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/callDeviceSettings"
|
|
1007
|
+
params = {}
|
|
1008
|
+
org_id = get_org_id()
|
|
1009
|
+
if org_id is not None:
|
|
1010
|
+
params["orgId"] = org_id
|
|
1011
|
+
if json_body:
|
|
1012
|
+
body = json.loads(json_body)
|
|
1013
|
+
else:
|
|
1014
|
+
body = {}
|
|
1015
|
+
if location_id is not None:
|
|
1016
|
+
body["locationId"] = location_id
|
|
1017
|
+
if location_customizations_enabled is not None:
|
|
1018
|
+
body["locationCustomizationsEnabled"] = location_customizations_enabled
|
|
1019
|
+
try:
|
|
1020
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
1021
|
+
except WebexError as e:
|
|
1022
|
+
handle_rest_error(e)
|
|
1023
|
+
if output == "json":
|
|
1024
|
+
print_json(result)
|
|
1025
|
+
elif isinstance(result, dict) and "id" in result:
|
|
1026
|
+
typer.echo(f"Created: {result['id']}")
|
|
1027
|
+
elif not result or result == {}:
|
|
1028
|
+
typer.echo("Created.")
|
|
1029
|
+
else:
|
|
1030
|
+
print_json(result)
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
@app.command("show-call-device-settings")
|
|
1035
|
+
def show_call_device_settings(
|
|
1036
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
1037
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
1038
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1039
|
+
):
|
|
1040
|
+
"""Get Change Device Settings Job Status."""
|
|
1041
|
+
api = get_api(debug=debug)
|
|
1042
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/callDeviceSettings/{job_id}"
|
|
1043
|
+
try:
|
|
1044
|
+
result = api.session.rest_get(url)
|
|
1045
|
+
except WebexError as e:
|
|
1046
|
+
handle_rest_error(e)
|
|
1047
|
+
if output == "json":
|
|
1048
|
+
print_json(result)
|
|
1049
|
+
else:
|
|
1050
|
+
if isinstance(result, dict):
|
|
1051
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
1052
|
+
elif isinstance(result, list):
|
|
1053
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
1054
|
+
else:
|
|
1055
|
+
print_json(result)
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
@app.command("list-errors-call-device-settings")
|
|
1060
|
+
def list_errors_call_device_settings(
|
|
1061
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
1062
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
1063
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
1064
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
1065
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1066
|
+
):
|
|
1067
|
+
"""List Change Device Settings Job Errors."""
|
|
1068
|
+
api = get_api(debug=debug)
|
|
1069
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/callDeviceSettings/{job_id}/errors"
|
|
1070
|
+
params = {}
|
|
1071
|
+
if limit > 0:
|
|
1072
|
+
params["max"] = limit
|
|
1073
|
+
if offset > 0:
|
|
1074
|
+
params["start"] = offset
|
|
1075
|
+
org_id = get_org_id()
|
|
1076
|
+
if org_id is not None:
|
|
1077
|
+
params["orgId"] = org_id
|
|
1078
|
+
try:
|
|
1079
|
+
if limit > 0:
|
|
1080
|
+
result = api.session.rest_get(url, params=params)
|
|
1081
|
+
result = result or {}
|
|
1082
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
1083
|
+
else:
|
|
1084
|
+
items = list(api.session.follow_pagination(url=url, params=params, item_key="items"))
|
|
1085
|
+
except WebexError as e:
|
|
1086
|
+
handle_rest_error(e)
|
|
1087
|
+
if output == "json":
|
|
1088
|
+
print_json(items)
|
|
1089
|
+
else:
|
|
1090
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
@app.command("list-layout")
|
|
1095
|
+
def list_layout(
|
|
1096
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
1097
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
1098
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
1099
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
1100
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1101
|
+
):
|
|
1102
|
+
"""Get Device Layout by Device ID."""
|
|
1103
|
+
api = get_api(debug=debug)
|
|
1104
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/layout"
|
|
1105
|
+
params = {}
|
|
1106
|
+
if limit > 0:
|
|
1107
|
+
params["max"] = limit
|
|
1108
|
+
if offset > 0:
|
|
1109
|
+
params["start"] = offset
|
|
1110
|
+
org_id = get_org_id()
|
|
1111
|
+
if org_id is not None:
|
|
1112
|
+
params["orgId"] = org_id
|
|
1113
|
+
result = None
|
|
1114
|
+
try:
|
|
1115
|
+
result = api.session.rest_get(url, params=params)
|
|
1116
|
+
except WebexError as e:
|
|
1117
|
+
handle_rest_error(e)
|
|
1118
|
+
result = result or []
|
|
1119
|
+
items = result.get("lineKeys", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
1120
|
+
if output == "json":
|
|
1121
|
+
print_json(items)
|
|
1122
|
+
else:
|
|
1123
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
@app.command("update-layout")
|
|
1128
|
+
def update_layout(
|
|
1129
|
+
device_id: str = typer.Argument(help="deviceId"),
|
|
1130
|
+
layout_mode: str = typer.Option(None, "--layout-mode", help="Choices: DEFAULT, CUSTOM"),
|
|
1131
|
+
user_reorder_enabled: bool = typer.Option(None, "--user-reorder-enabled/--no-user-reorder-enabled", help="If `true`, user customization is enabled."),
|
|
1132
|
+
kem_module_type: str = typer.Option(None, "--kem-module-type", help="Choices: KEM_14_KEYS, KEM_18_KEYS, KEM_20_KEYS"),
|
|
1133
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
1134
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1135
|
+
):
|
|
1136
|
+
"""Modify Device Layout by Device ID\n\nExample --json-body:\n '{"layoutMode":"DEFAULT","lineKeys":[{"lineKeyIndex":"...","lineKeyType":"...","sharedLineIndex":"...","lineKeyLabel":"...","lineKeyValue":"..."}],"userReorderEnabled":true,"kemModuleType":"KEM_14_KEYS","kemKeys":[{"kemModuleIndex":"...","kemKeyIndex":"...","kemKeyType":"...","sharedLineIndex":"...","kemKeyLabel":"...","kemKeyValue":"..."}]}'."""
|
|
1137
|
+
api = get_api(debug=debug)
|
|
1138
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/{device_id}/layout"
|
|
1139
|
+
params = {}
|
|
1140
|
+
org_id = get_org_id()
|
|
1141
|
+
if org_id is not None:
|
|
1142
|
+
params["orgId"] = org_id
|
|
1143
|
+
if json_body:
|
|
1144
|
+
body = json.loads(json_body)
|
|
1145
|
+
else:
|
|
1146
|
+
body = {}
|
|
1147
|
+
if layout_mode is not None:
|
|
1148
|
+
body["layoutMode"] = layout_mode
|
|
1149
|
+
if user_reorder_enabled is not None:
|
|
1150
|
+
body["userReorderEnabled"] = user_reorder_enabled
|
|
1151
|
+
if kem_module_type is not None:
|
|
1152
|
+
body["kemModuleType"] = kem_module_type
|
|
1153
|
+
try:
|
|
1154
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
1155
|
+
except WebexError as e:
|
|
1156
|
+
handle_rest_error(e)
|
|
1157
|
+
typer.echo(f"Updated.")
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
@app.command("list-rebuild-phones")
|
|
1162
|
+
def list_rebuild_phones(
|
|
1163
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
1164
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
1165
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
1166
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1167
|
+
):
|
|
1168
|
+
"""List Rebuild Phones Jobs."""
|
|
1169
|
+
api = get_api(debug=debug)
|
|
1170
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/rebuildPhones"
|
|
1171
|
+
params = {}
|
|
1172
|
+
if limit > 0:
|
|
1173
|
+
params["max"] = limit
|
|
1174
|
+
if offset > 0:
|
|
1175
|
+
params["start"] = offset
|
|
1176
|
+
org_id = get_org_id()
|
|
1177
|
+
if org_id is not None:
|
|
1178
|
+
params["orgId"] = org_id
|
|
1179
|
+
result = None
|
|
1180
|
+
try:
|
|
1181
|
+
result = api.session.rest_get(url, params=params)
|
|
1182
|
+
except WebexError as e:
|
|
1183
|
+
handle_rest_error(e)
|
|
1184
|
+
result = result or []
|
|
1185
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
1186
|
+
if output == "json":
|
|
1187
|
+
print_json(items)
|
|
1188
|
+
else:
|
|
1189
|
+
print_table(items, columns=[('ID', 'id'), ('Status', 'latestExecutionStatus')], limit=limit)
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
@app.command("create-rebuild-phones")
|
|
1194
|
+
def create_rebuild_phones(
|
|
1195
|
+
location_id: str = typer.Option(None, "--location-id", help="(required) Unique identifier of the location."),
|
|
1196
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
1197
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
1198
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1199
|
+
):
|
|
1200
|
+
"""Rebuild Phones Configuration."""
|
|
1201
|
+
api = get_api(debug=debug)
|
|
1202
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/rebuildPhones"
|
|
1203
|
+
params = {}
|
|
1204
|
+
org_id = get_org_id()
|
|
1205
|
+
if org_id is not None:
|
|
1206
|
+
params["orgId"] = org_id
|
|
1207
|
+
if json_body:
|
|
1208
|
+
body = json.loads(json_body)
|
|
1209
|
+
else:
|
|
1210
|
+
body = {}
|
|
1211
|
+
if location_id is not None:
|
|
1212
|
+
body["locationId"] = location_id
|
|
1213
|
+
_missing = [f for f in ['locationId'] if f not in body or body[f] is None]
|
|
1214
|
+
if _missing:
|
|
1215
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
1216
|
+
raise typer.Exit(1)
|
|
1217
|
+
try:
|
|
1218
|
+
result = api.session.rest_post(url, json=body, params=params)
|
|
1219
|
+
except WebexError as e:
|
|
1220
|
+
handle_rest_error(e)
|
|
1221
|
+
if output == "json":
|
|
1222
|
+
print_json(result)
|
|
1223
|
+
elif isinstance(result, dict) and "id" in result:
|
|
1224
|
+
typer.echo(f"Created: {result['id']}")
|
|
1225
|
+
elif not result or result == {}:
|
|
1226
|
+
typer.echo("Created.")
|
|
1227
|
+
else:
|
|
1228
|
+
print_json(result)
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
@app.command("show-rebuild-phones")
|
|
1233
|
+
def show_rebuild_phones(
|
|
1234
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
1235
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
1236
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1237
|
+
):
|
|
1238
|
+
"""Get the Job Status of a Rebuild Phones Job."""
|
|
1239
|
+
api = get_api(debug=debug)
|
|
1240
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/rebuildPhones/{job_id}"
|
|
1241
|
+
params = {}
|
|
1242
|
+
org_id = get_org_id()
|
|
1243
|
+
if org_id is not None:
|
|
1244
|
+
params["orgId"] = org_id
|
|
1245
|
+
try:
|
|
1246
|
+
result = api.session.rest_get(url, params=params)
|
|
1247
|
+
except WebexError as e:
|
|
1248
|
+
handle_rest_error(e)
|
|
1249
|
+
if output == "json":
|
|
1250
|
+
print_json(result)
|
|
1251
|
+
else:
|
|
1252
|
+
if isinstance(result, dict):
|
|
1253
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
1254
|
+
elif isinstance(result, list):
|
|
1255
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
1256
|
+
else:
|
|
1257
|
+
print_json(result)
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
@app.command("list-errors-rebuild-phones")
|
|
1262
|
+
def list_errors_rebuild_phones(
|
|
1263
|
+
job_id: str = typer.Argument(help="jobId"),
|
|
1264
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
1265
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
1266
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
1267
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1268
|
+
):
|
|
1269
|
+
"""Get Job Errors for a Rebuild Phones Job."""
|
|
1270
|
+
api = get_api(debug=debug)
|
|
1271
|
+
url = f"https://webexapis.com/v1/telephony/config/jobs/devices/rebuildPhones/{job_id}/errors"
|
|
1272
|
+
params = {}
|
|
1273
|
+
if limit > 0:
|
|
1274
|
+
params["max"] = limit
|
|
1275
|
+
if offset > 0:
|
|
1276
|
+
params["start"] = offset
|
|
1277
|
+
org_id = get_org_id()
|
|
1278
|
+
if org_id is not None:
|
|
1279
|
+
params["orgId"] = org_id
|
|
1280
|
+
result = None
|
|
1281
|
+
try:
|
|
1282
|
+
result = api.session.rest_get(url, params=params)
|
|
1283
|
+
except WebexError as e:
|
|
1284
|
+
handle_rest_error(e)
|
|
1285
|
+
result = result or []
|
|
1286
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
1287
|
+
if output == "json":
|
|
1288
|
+
print_json(items)
|
|
1289
|
+
else:
|
|
1290
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
1291
|
+
|
|
1292
|
+
|
|
1293
|
+
|
|
1294
|
+
@app.command("show-settings-devices-3")
|
|
1295
|
+
def show_settings_devices_3(
|
|
1296
|
+
person_id: str = typer.Argument(help="personId"),
|
|
1297
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
1298
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1299
|
+
):
|
|
1300
|
+
"""Get Device Settings for a Person."""
|
|
1301
|
+
api = get_api(debug=debug)
|
|
1302
|
+
url = f"https://webexapis.com/v1/telephony/config/people/{person_id}/devices/settings"
|
|
1303
|
+
params = {}
|
|
1304
|
+
org_id = get_org_id()
|
|
1305
|
+
if org_id is not None:
|
|
1306
|
+
params["orgId"] = org_id
|
|
1307
|
+
try:
|
|
1308
|
+
result = api.session.rest_get(url, params=params)
|
|
1309
|
+
except WebexError as e:
|
|
1310
|
+
handle_rest_error(e)
|
|
1311
|
+
if output == "json":
|
|
1312
|
+
print_json(result)
|
|
1313
|
+
else:
|
|
1314
|
+
if isinstance(result, dict):
|
|
1315
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
1316
|
+
elif isinstance(result, list):
|
|
1317
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
1318
|
+
else:
|
|
1319
|
+
print_json(result)
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
|
|
1323
|
+
@app.command("update-settings-devices-1")
|
|
1324
|
+
def update_settings_devices_1(
|
|
1325
|
+
person_id: str = typer.Argument(help="personId"),
|
|
1326
|
+
compression: str = typer.Option(None, "--compression", help="Choices: ON, OFF"),
|
|
1327
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
1328
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1329
|
+
):
|
|
1330
|
+
"""Update Device Settings for a Person\n\nExample --json-body:\n '{"compression":"ON"}'."""
|
|
1331
|
+
api = get_api(debug=debug)
|
|
1332
|
+
url = f"https://webexapis.com/v1/telephony/config/people/{person_id}/devices/settings"
|
|
1333
|
+
params = {}
|
|
1334
|
+
org_id = get_org_id()
|
|
1335
|
+
if org_id is not None:
|
|
1336
|
+
params["orgId"] = org_id
|
|
1337
|
+
if json_body:
|
|
1338
|
+
body = json.loads(json_body)
|
|
1339
|
+
else:
|
|
1340
|
+
body = {}
|
|
1341
|
+
if compression is not None:
|
|
1342
|
+
body["compression"] = compression
|
|
1343
|
+
try:
|
|
1344
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
1345
|
+
except WebexError as e:
|
|
1346
|
+
handle_rest_error(e)
|
|
1347
|
+
typer.echo(f"Updated.")
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
@app.command("show-settings-devices-4")
|
|
1352
|
+
def show_settings_devices_4(
|
|
1353
|
+
workspace_id: str = typer.Argument(help="workspaceId"),
|
|
1354
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
1355
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1356
|
+
):
|
|
1357
|
+
"""Get Device Settings for a Workspace."""
|
|
1358
|
+
api = get_api(debug=debug)
|
|
1359
|
+
url = f"https://webexapis.com/v1/telephony/config/workspaces/{workspace_id}/devices/settings"
|
|
1360
|
+
params = {}
|
|
1361
|
+
org_id = get_org_id()
|
|
1362
|
+
if org_id is not None:
|
|
1363
|
+
params["orgId"] = org_id
|
|
1364
|
+
try:
|
|
1365
|
+
result = api.session.rest_get(url, params=params)
|
|
1366
|
+
except WebexError as e:
|
|
1367
|
+
handle_rest_error(e)
|
|
1368
|
+
if output == "json":
|
|
1369
|
+
print_json(result)
|
|
1370
|
+
else:
|
|
1371
|
+
if isinstance(result, dict):
|
|
1372
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
1373
|
+
elif isinstance(result, list):
|
|
1374
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
1375
|
+
else:
|
|
1376
|
+
print_json(result)
|
|
1377
|
+
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
@app.command("update-settings-devices-2")
|
|
1381
|
+
def update_settings_devices_2(
|
|
1382
|
+
workspace_id: str = typer.Argument(help="workspaceId"),
|
|
1383
|
+
compression: str = typer.Option(None, "--compression", help="Choices: ON, OFF"),
|
|
1384
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
1385
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1386
|
+
):
|
|
1387
|
+
"""Update Device Settings for a Workspace\n\nExample --json-body:\n '{"compression":"ON"}'."""
|
|
1388
|
+
api = get_api(debug=debug)
|
|
1389
|
+
url = f"https://webexapis.com/v1/telephony/config/workspaces/{workspace_id}/devices/settings"
|
|
1390
|
+
params = {}
|
|
1391
|
+
org_id = get_org_id()
|
|
1392
|
+
if org_id is not None:
|
|
1393
|
+
params["orgId"] = org_id
|
|
1394
|
+
if json_body:
|
|
1395
|
+
body = json.loads(json_body)
|
|
1396
|
+
else:
|
|
1397
|
+
body = {}
|
|
1398
|
+
if compression is not None:
|
|
1399
|
+
body["compression"] = compression
|
|
1400
|
+
try:
|
|
1401
|
+
result = api.session.rest_put(url, json=body, params=params)
|
|
1402
|
+
except WebexError as e:
|
|
1403
|
+
handle_rest_error(e)
|
|
1404
|
+
typer.echo(f"Updated.")
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
@app.command("list-background-images")
|
|
1409
|
+
def list_background_images(
|
|
1410
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
1411
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
1412
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
1413
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1414
|
+
):
|
|
1415
|
+
"""Read the List of Background Images."""
|
|
1416
|
+
api = get_api(debug=debug)
|
|
1417
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/backgroundImages"
|
|
1418
|
+
params = {}
|
|
1419
|
+
if limit > 0:
|
|
1420
|
+
params["max"] = limit
|
|
1421
|
+
if offset > 0:
|
|
1422
|
+
params["start"] = offset
|
|
1423
|
+
org_id = get_org_id()
|
|
1424
|
+
if org_id is not None:
|
|
1425
|
+
params["orgId"] = org_id
|
|
1426
|
+
result = None
|
|
1427
|
+
try:
|
|
1428
|
+
result = api.session.rest_get(url, params=params)
|
|
1429
|
+
except WebexError as e:
|
|
1430
|
+
handle_rest_error(e)
|
|
1431
|
+
result = result or []
|
|
1432
|
+
items = result.get("backgroundImages", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
1433
|
+
if output == "json":
|
|
1434
|
+
print_json(items)
|
|
1435
|
+
else:
|
|
1436
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
|
|
1440
|
+
@app.command("delete-background-images")
|
|
1441
|
+
def delete_background_images(
|
|
1442
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
1443
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1444
|
+
):
|
|
1445
|
+
"""Delete Device Background Images."""
|
|
1446
|
+
if not force:
|
|
1447
|
+
typer.confirm("Delete this resource?", abort=True)
|
|
1448
|
+
api = get_api(debug=debug)
|
|
1449
|
+
url = f"https://webexapis.com/v1/telephony/config/devices/backgroundImages"
|
|
1450
|
+
params = {}
|
|
1451
|
+
org_id = get_org_id()
|
|
1452
|
+
if org_id is not None:
|
|
1453
|
+
params["orgId"] = org_id
|
|
1454
|
+
try:
|
|
1455
|
+
api.session.rest_delete(url, params=params)
|
|
1456
|
+
except WebexError as e:
|
|
1457
|
+
handle_rest_error(e)
|
|
1458
|
+
typer.echo("Deleted.")
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
@app.command("show-count-devices")
|
|
1463
|
+
def show_count_devices(
|
|
1464
|
+
person_id: str = typer.Argument(help="personId"),
|
|
1465
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
1466
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
1467
|
+
):
|
|
1468
|
+
"""Get User Devices Count."""
|
|
1469
|
+
api = get_api(debug=debug)
|
|
1470
|
+
url = f"https://webexapis.com/v1/telephony/config/people/{person_id}/devices/count"
|
|
1471
|
+
params = {}
|
|
1472
|
+
org_id = get_org_id()
|
|
1473
|
+
if org_id is not None:
|
|
1474
|
+
params["orgId"] = org_id
|
|
1475
|
+
try:
|
|
1476
|
+
result = api.session.rest_get(url, params=params)
|
|
1477
|
+
except WebexError as e:
|
|
1478
|
+
handle_rest_error(e)
|
|
1479
|
+
if output == "json":
|
|
1480
|
+
print_json(result)
|
|
1481
|
+
else:
|
|
1482
|
+
if isinstance(result, dict):
|
|
1483
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
1484
|
+
elif isinstance(result, list):
|
|
1485
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
1486
|
+
else:
|
|
1487
|
+
print_json(result)
|
|
1488
|
+
|
|
1489
|
+
|