Source code for wxc_sdk.telephony.devices

"""
Telephony devices
"""
import os
from collections.abc import Generator
from io import BufferedReader
from typing import Optional, Union, Any

from pydantic import TypeAdapter, Field, field_validator, field_serializer
from requests_toolbelt import MultipartEncoder

from ..jobs import LineKeyTemplateAdvisoryTypes
from ...api_child import ApiChild
from ...base import ApiModel, plus1, to_camel, enum_str
from ...base import SafeEnum as Enum
from ...common import PrimaryOrShared, UserType, ValidationStatus, DeviceCustomization, IdAndName, \
    ApplyLineKeyTemplateAction, UserLicenseType

__all__ = ['MemberCommon', 'DeviceMember', 'DeviceMembersResponse', 'AvailableMember', 'MACState',
           'MACStatus', 'MACValidationResponse', 'TelephonyDevicesApi', 'LineKeyType', 'ProgrammableLineKey',
           'LineKeyTemplate', 'TelephonyDeviceDetails', 'ActivationState', 'TelephonyDeviceOwner',
           'TelephonyDeviceProxy', 'LayoutMode', 'KemModuleType', 'KemKey', 'DeviceLayout', 'DeviceSettings',
           'BackgroundImage', 'BackgroundImages', 'DeleteImageRequestObject',
           'DeleteImageResponseSuccessObjectResult', 'DeleteImageResponseSuccessObject',
           'DeleteDeviceBackgroundImagesResponse', 'UserDeviceCount']


[docs] class ActivationState(str, Enum): #: Indicates a device is activating using an activation code. activating = 'activating' #: Indicates a device has been activated using an activation code. activated = 'activated' #: Indicates a device has not been activated using an activation code. deactivated = 'deactivated'
[docs] class TelephonyDeviceOwner(ApiModel): #: Identifies a device endpoint in standalone mode or a SIP URI public identity in IMS mode. line_port: Optional[str] = None #: SIP authentication user name for the owner of the device. sip_user_name: Optional[str] = None
[docs] class TelephonyDeviceProxy(ApiModel): #: Outgoing server which the phone should use for all SIP requests. Not set if the response has no body. outbound_proxy: Optional[str] = None
[docs] class TelephonyDeviceDetails(ApiModel): #: Manufacturer of the device. manufacturer: Optional[str] = None #: Device manager(s). managed_by: Optional[str] = None #: A unique identifier for the device. id: Optional[str] = None #: The current IP address of the device. ip: Optional[str] = None #: The unique address for the network adapter. mac: Optional[str] = None #: A model type of the device. model: Optional[str] = None #: Activation state of the device. This field is only populated for a device added by a unique activation code #: generated by Control Hub for use with Webex. activation_state: Optional[ActivationState] = None #: Comma-separated array of tags used to describe the device. description: Optional[list[str]] = None #: Enabled / disabled status of the upgrade channel. upgrade_channel_enabled: Optional[bool] = None owner: Optional[TelephonyDeviceOwner] = None proxy: Optional[TelephonyDeviceProxy] = None
[docs] class MemberCommon(ApiModel): #: Unique identifier for the member. member_id: str = Field(alias='id') member_type: UserType = Field(default=UserType.people) #: First name of a person or workspace. first_name: Optional[str] = None #: Last name of a person or workspace. last_name: Optional[str] = None #: Phone Number of a person or workspace. In some regions phone numbers are not returned in E.164 format. This #: will be supported in a future update. phone_number: Optional[str] = None #: Extension of a person or workspace. extension: Optional[str] = None #: Routing prefix of location. routingPrefix: Optional[str] = None #: Routing prefix + extension of a person or workspace. esn: Optional[str] = None #: T.38 Fax Compression setting and is available only for ATA Devices. Choose T.38 fax compression if the device #: requires this option. This will override user level compression options. t38_fax_compression_enabled: Optional[bool] = None #: Line type is used to differentiate Primary and SCA, at which endpoint it is assigned. line_type: PrimaryOrShared = Field(default=PrimaryOrShared.primary) #: Set how a person's device behaves when a call is declined. When set to true, a call decline request is extended #: to all the endpoints on the device. When set to false, a call decline request only declines the current endpoint. allow_call_decline_enabled: Optional[bool] = Field(default=True) location: Optional[IdAndName] = None license_type: Optional[UserLicenseType] = None @field_validator('phone_number', mode='before') def e164(cls, v): """ :meta private: """ return plus1(v)
[docs] class DeviceMember(MemberCommon): #: This field indicates whether the person or the workspace is the owner of the device, and points to a primary #: Line/Port of the device. primary_owner: bool = Field(default=False) #: Port number assigned to person or workspace. port: int = Field(default=1) #: Number of lines that have been configured for the person on the device. Can only be larger than one for primary #: owner line_weight: int = Field(default=1) #: Device line label. line_label: Optional[str] = None #: Registration Host IP address for the line port. host_ip: Optional[str] = Field(alias='hostIP', default=None) #: Registration Remote IP address for the line port. remote_ip: Optional[str] = Field(alias='remoteIP', default=None) #: Enable Hotline. Configure this line to automatically call a predefined number whenever taken off-hook. Once #: enabled, the line can only make calls to the predefined number set in hotlineDestination. hotline_enabled: bool = Field(default=False) #: The preconfigured number for Hotline. Required only if hotlineEnabled is set to true. hotline_destination: Optional[str] = None
[docs] @staticmethod def from_available(available: 'AvailableMember') -> 'DeviceMember': data = available.model_dump(mode='json', by_alias=True, exclude_none=True) return DeviceMember.model_validate(data)
[docs] class DeviceMembersResponse(ApiModel): """ Get Device Members response """ model: str members: list[DeviceMember] max_line_count: int # assert that members are always sorted by port number @field_validator('members', mode='after') def sort_members(cls, v): """ :meta private: """ v.sort(key=lambda dm: dm.port) return v
[docs] class AvailableMember(MemberCommon): ...
[docs] class MACState(str, Enum): """ State of the MAC address. """ #: The requested MAC address is available. available = 'AVAILABLE' #: The requested MAC address is unavailable. unavailable = 'UNAVAILABLE' #: The requested MAC address is duplicated. duplicate_in_list = 'DUPLICATE_IN_LIST' #: The requested MAC address is invalid. invalid = 'INVALID'
[docs] class MACStatus(ApiModel): #: MAC address. mac: str #: State of the MAC address. state: MACState #: MAC address validation error code. error_code: Optional[int] = None #: Provides a status message about the MAC address. message: Optional[str] = None
[docs] class MACValidationResponse(ApiModel): #: Status of MAC address. status: ValidationStatus #: Contains an array of all the MAC address provided and their statuses. mac_status: Optional[list[MACStatus]] = None
[docs] class LineKeyType(str, Enum): #: PRIMARY_LINE is the user's primary extension. This is the default assignment for Line Key Index 1 and cannot be #: modified. primary_line = 'PRIMARY_LINE' #: Shows the appearance of other users on the owner's phone. shared_line = 'SHARED_LINE' #: Enables User and Call Park monitoring. monitor = 'MONITOR' #: Enables the configure layout feature in Control Hub to set call park extension implicitly. call_park_extension = 'CALL_PARK_EXTENSION' #: Allows users to reach a telephone number, extension or a SIP URI. speed_dial = 'SPEED_DIAL' #: An open key will automatically take the configuration of a monitor button starting with the first open key. #: These buttons are also usable by the user to configure speed dial numbers on these keys. open = 'OPEN' #: Button not usable but reserved for future features. closed = 'CLOSED'
[docs] class ProgrammableLineKey(ApiModel): #: An index representing a Line Key. Index starts from 1 representing the first key on the left side of the phone. line_key_index: Optional[int] = None #: The action that would be performed when the Line Key is pressed. line_key_type: Optional[LineKeyType] = None #: This is applicable only when the lineKeyType is `SPEED_DIAL`. line_key_label: Optional[str] = None #: This is applicable only when the lineKeyType is `SPEED_DIAL` and the value must be a valid Telephone Number, #: Ext, or SIP URI (format: user@host using A-Z,a-z,0-9,-_ .+ for user and host). line_key_value: Optional[str] = None
[docs] @classmethod def standard_plk_list(cls, lines: int = 10) -> list['ProgrammableLineKey']: """ get a standard list of programmable line keys of given length. 1st line key is primary line and all other are "open" :param lines: number of programmable line keys :return: list of programmable line keys """ r = [ProgrammableLineKey(line_key_index=i, line_key_type=LineKeyType.open) for i in range(1, lines + 1)] r[0].line_key_type = LineKeyType.primary_line return r
[docs] class LineKeyTemplate(ApiModel): #: Unique identifier for the Line Key Template id: Optional[str] = None #: Name of the Line Key Template template_name: Optional[str] = None #: The Device Model for which the Line Key Template is applicable device_model: Optional[str] = None #: The friendly display name used to represent the device model in Control Hub display_name: Optional[str] = Field(alias='modelDisplayName', default=None) #: Indicates whether user can reorder the line keys. user_reorder_enabled: Optional[bool] = None #: Contains a mapping of Line Keys and their corresponding actions. line_keys: Optional[list[ProgrammableLineKey]] = None def create_or_update(self) -> dict[str, Any]: """ dict for create or update :meta private: """ return self.model_dump(mode='json', exclude_none=True, by_alias=True, exclude={'id', 'display_name'})
[docs] class LayoutMode(str, Enum): #: Default layout mode when a new device is added. default = 'DEFAULT' #: Enables a device to have its custom layout. custom = 'CUSTOM'
[docs] class KemModuleType(str, Enum): #: Extension module has 14 line keys that can be configured. kem_14_keys = 'KEM_14_KEYS' #: Extension module has 18 line keys that can be configured. kem_18_keys = 'KEM_18_KEYS' #: Extension module has 20 line keys that can be configured. kem_20_keys = 'KEM_20_KEYS'
[docs] class KemKey(ApiModel): #: An index representing a KEM Module. The Index starts from 1 representing the first KEM Module. kem_module_index: Optional[int] = None #: An index representing a KEM Key. The Index starts from 1 representing the first key on the left side of the #: phone. kem_key_index: Optional[int] = None #: The action that would be performed when the KEM Key is pressed. kem_key_type: Optional[LineKeyType] = None #: Applicable only when the kemKeyType is `SPEED_DIAL`. kem_key_label: Optional[str] = None #: Applicable only when the kemKeyType is `SPEED_DIAL`. Value must be a valid Telephone Number, Ext, or SIP URI #: (format: `user@host` limited to `A-Z,a-z,0-9,-_ .+` for user and host). kem_key_value: Optional[str] = None
[docs] class DeviceLayout(ApiModel): #: Defines the layout mode of the device, i.e. DEFAULT or CUSTOM. layout_mode: Optional[LayoutMode] = None #: If `true`, user customization is enabled.. user_reorder_enabled: Optional[bool] = None #: Contains a mapping of Line Keys and their corresponding actions. line_keys: Optional[list[ProgrammableLineKey]] = None #: Type of KEM module. kem_module_type: Optional[KemModuleType] = None #: Contains a mapping of KEM Keys and their corresponding actions. kem_keys: Optional[list[KemKey]] = None
[docs] def update(self) -> dict: """ get data for update :meta private: """ return self.model_dump(mode='json', exclude_none=True, by_alias=True)
[docs] class DeviceSettings(ApiModel): #: True -> Minimize data use during compression. #: #: False -> Ignore data use during compression. compression: Optional[bool] = None @field_serializer('compression') def ser_compression(self, v: bool) -> str: """ :meta private: """ return 'ON' if v else 'OFF'
[docs] class BackgroundImage(ApiModel): #: The URL of the image file. background_image_url: Optional[str] = None #: The name of the image file. file_name: Optional[str] = None #: The total number of images in the org after uploading. count: Optional[int] = None
[docs] class BackgroundImages(ApiModel): #: Array of background images. background_images: Optional[list[BackgroundImage]] = None #: The total number of images in the org. count: Optional[int] = None
[docs] class DeleteImageRequestObject(ApiModel): #: The name of the image file to be deleted. file_name: Optional[str] = None #: Flag to force delete the image. When `forceDelete` = true, if any device, location, or org level custom #: background URL is configured with the `backgroundImageURL` containing the filename being deleted, the #: background image is set to `None`. force_delete: Optional[bool] = None
[docs] class DeleteImageResponseSuccessObjectResult(ApiModel): #: The status of the deletion. status: Optional[int] = None
[docs] class DeleteImageResponseSuccessObject(ApiModel): #: The name of the image file. file_name: Optional[str] = None #: The result of the deletion. result: Optional[DeleteImageResponseSuccessObjectResult] = None
[docs] class DeleteDeviceBackgroundImagesResponse(ApiModel): #: Array of deleted images. items: Optional[list[DeleteImageResponseSuccessObject]] = None #: The total number of images in the org after deletion. count: Optional[int] = None
[docs] class UserDeviceCount(ApiModel): #: The total count of devices associated with the user as a sum of: #: #: - Count of total primary physical devices. #: - Count of Webex-Team system device endpoints. #: - Count of 1 for any or all applications present. total_device_count: Optional[int] = None #: The total count of applications associated with the user. applications_count: Optional[int] = None
[docs] class TelephonyDevicesApi(ApiChild, base='telephony/config'): """ Telephony devices API """
[docs] def details(self, device_id: str, org_id: str = None) -> TelephonyDeviceDetails: """ Get Webex Calling Device Details Not supported for Webex for Government (FedRAMP) Retrieves Webex Calling device details that include information needed for third-party device management. Webex calling devices are associated with a specific user Workspace or Virtual Line. Webex Calling devices share the location with the entity that owns them. Person or workspace to which the device is assigned. Its fields point to a primary line/port of the device. Requires a full, location, user, or read-only admin auth token with the scope of `spark-admin:telephony_config_read`. :param device_id: Unique identifier for the device. :type device_id: str :param org_id: ID of the organization in which the device resides. :type org_id: str :rtype: :class:`TelephonyDeviceDetails` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/{device_id}') data = super().get(url, params=params) r = TelephonyDeviceDetails.model_validate(data) return r
[docs] def update_third_party_device(self, device_id: str, sip_password: str, org_id: str = None): """ Update Third Party Device Not supported for Webex for Government (FedRAMP) Modify a device's `sipPassword`. Updating `sipPassword` on the device requires a full or user administrator auth token with a scope of `spark-admin:telephony_config_write`. :param device_id: Unique identifier for the device. :type device_id: str :param sip_password: Password to be updated. :type sip_password: str :param org_id: ID of the organization in which the device resides. :type org_id: str :rtype: None """ params = {} if org_id is not None: params['orgId'] = org_id body = dict() body['sipPassword'] = sip_password url = self.ep(f'devices/{device_id}') super().put(url, params=params, json=body)
[docs] def members(self, device_id: str, org_id: str = None) -> DeviceMembersResponse: """ Get Device Members Get the list of all the members of the device including primary and secondary users. A device member can be either a person or a workspace. An admin can access the list of member details, modify member details and search for available members on a device. Retrieving this list requires a full or read-only administrator auth token with a scope of spark-admin:telephony_config_read. :param device_id: Unique identifier for the device. :type device_id: str :param org_id: Retrieves the list of all members of the device in this Organization. :type org_id: str :return: Device model, line count, and members :rtype: DeviceMembersResponse """ params = org_id and {'orgId': org_id} or None url = self.ep(f'devices/{device_id}/members') data = self.get(url=url, params=params) return DeviceMembersResponse.model_validate(data)
[docs] def update_members(self, device_id: str, members: Optional[list[Union[DeviceMember, AvailableMember]]], org_id: str = None): """ Modify member details on the device. A device member can be either a person or a workspace. An admin can access the list of member details, modify member details and search for available members on a device. Modifying members on the device requires a full administrator auth token with a scope of spark-admin:telephony_config_write. :param device_id: Unique identifier for the device. :type device_id: str :param members: New member details for the device. If the member's list is missing then all the users are removed except the primary user. :type members: list[Union[DeviceMember, AvailableMember] :param org_id: Modify members on the device in this organization. :type org_id: str """ members_for_update = [] for member in members: if isinstance(member, AvailableMember): member = DeviceMember.from_available(member) else: member = member.model_copy(deep=True) members_for_update.append(member) if members_for_update: # now assign port indices port = 1 for member in members_for_update: member.port = port port += member.line_weight # create body if members_for_update: members = ','.join(m.model_dump_json(include={'member_id', 'port', 't38_fax_compression_enabled', 'primary_owner', 'line_type', 'line_weight', 'line_label', 'hotline_enabled', 'hotline_destination', 'allow_call_decline_enabled'}) for m in members_for_update) body = f'{{"members": [{members}]}}' else: body = None url = self.ep(f'devices/{device_id}/members') params = org_id and {'orgId': org_id} or None self.put(url=url, data=body, params=params)
[docs] def available_members(self, device_id: str, location_id: str = None, member_name: str = None, phone_number: str = None, extension: str = None, org_id: str = None, **params) -> Generator[AvailableMember, None, None]: """ Search members that can be assigned to the device. A device member can be either a person or a workspace. A admin can access the list of member details, modify member details and search for available members on a device. This requires a full or read-only administrator auth token with a scope of spark-admin:telephony_config_read. :param device_id: Unique identifier for the device. :type device_id: str :param location_id: Search (Contains) based on number. :type location_id: str :param member_name: Search (Contains) numbers based on member name. :type member_name: str :param phone_number: Search (Contains) based on number. :type phone_number: str :param extension: Search (Contains) based on extension. :type extension: str :param org_id: Retrieves the list of available members on the device in this Organization. :type org_id: str :return: list of available members """ params.update((to_camel(p), v) for p, v in locals().items() if p not in {'self', 'params', 'device_id'} and v is not None) url = self.ep(f'devices/{device_id}/availableMembers') # noinspection PyTypeChecker return self.session.follow_pagination(url=url, model=AvailableMember, params=params, item_key='members')
[docs] def apply_changes(self, device_id: str, org_id: str = None): """ Apply Changes for a specific device Issues request to the device to download and apply changes to the configuration. Applying changes for a specific device requires a full administrator auth token with a scope of spark-admin:telephony_config_write. :param device_id: Unique identifier for the device. :type device_id: str :param org_id: Apply changes for a device in this Organization. :type org_id: str """ params = org_id and {'orgId': org_id} or None url = self.ep(f'devices/{device_id}/actions/applyChanges/invoke') self.post(url=url, params=params)
[docs] def device_settings(self, device_id: str, device_model: str, org_id: str = None) -> DeviceCustomization: """ Get override settings for a device. Device settings lists all the applicable settings for an MPP and an ATA devices at the device level. An admin can also modify the settings. DECT devices do not support settings at the device level. This requires a full or read-only administrator auth token with a scope of spark-admin:telephony_config_read. :param device_id: Unique identifier for the device. :type device_id: str :param device_model: Model type of the device. :type device_model: str :param org_id: Settings on the device in this organization. :type org_id: str :return: Device settings :rtype: DeviceCustomization """ params = {'model': device_model} if org_id: params['orgId'] = org_id url = self.ep(f'devices/{device_id}/settings') data = self.get(url=url, params=params) return DeviceCustomization.model_validate(data)
[docs] def update_device_settings(self, device_id: str, device_model: str, customization: DeviceCustomization, org_id: str = None): """ Modify override settings for a device. Device settings list all the applicable settings for an MPP and an ATA devices at the device level. Admins can also modify the settings. NOTE: DECT devices do not support settings at the device level. Updating settings on the device requires a full administrator auth token with a scope of spark-admin:telephony_config_write. :param device_id: Unique identifier for the device. :type device_id: str :param device_model: Device model name. :type device_model: str :param customization: Indicates the customization object of the device settings. :type customization: DeviceCustomization :param org_id: Organization in which the device resides.. :type org_id: str Example : .. code-block:: python # target_device is a TelephonyDevice object target_device: TelephonyDevice # get device level settings settings = api.telephony.devices.device_settings(device_id=target_device.device_id, device_model=target_device.model) # update settings (display name format) and enable device level customization settings.customizations.mpp.display_name_format = DisplayNameSelection.person_last_then_first_name settings.custom_enabled = True # update the device level settings api.telephony.devices.update_device_settings(device_id=target_device.device_id, device_model=target_device.model, customization=settings) # apply changes to device api.telephony.devices.apply_changes(device_id=target_device.device_id) """ params = {'model': device_model} if org_id: params['orgId'] = org_id url = self.ep(f'devices/{device_id}/settings') body = customization.model_dump_json(include={'customizations', 'custom_enabled'}) self.put(url=url, params=params, data=body)
[docs] def validate_macs(self, macs: list[str], org_id: str = None) -> MACValidationResponse: """ Validate a list of MAC addresses. Validating this list requires a full or read-only administrator auth token with a scope of spark-admin:telephony_config_write. :param macs: MAC addresses to be validated. :type macs: list[str] :param org_id: Validate the mac address(es) for this organization. :type org_id: str :return: validation response :rtype: :class:`MACValidationResponse` """ params = org_id and {'orgId': org_id} or None url = self.ep('devices/actions/validateMacs/invoke') data = self.post(url=url, params=params, json={'macs': macs}) return MACValidationResponse.model_validate(data)
[docs] def create_line_key_template(self, template: LineKeyTemplate, org_id: str = None) -> str: """ Create a Line Key Template Create a Line Key Template in this organization. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows customers to create a Line Key Template for a device model. Creating a Line Key Template requires a full administrator auth token with a scope of `spark-admin:telephony_config_write`. :param template: Line key template to create :type template: LineKeyTemplate :param org_id: id of organization to create the line key template in :type org_id: str :return: id of new line key template :rtype: str """ params = {} if org_id is not None: params['orgId'] = org_id body = template.create_or_update() url = self.ep('devices/lineKeyTemplates') data = super().post(url, params=params, json=body) r = data['id'] return r
[docs] def list_line_key_templates(self, org_id: str = None) -> list[LineKeyTemplate]: """ Read the list of Line Key Templates List all Line Key Templates available for this organization. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows users to retrieve the list of Line Key Templates that are available for the organization. Retrieving this list requires a full, user or read-only administrator or location administrator auth token with a scope of `spark-admin:telephony_config_read`. :param org_id: List line key templates for this organization. :type org_id: str :rtype: list[LineKeyTemplate] """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep('devices/lineKeyTemplates') data = super().get(url, params=params) r = TypeAdapter(list[LineKeyTemplate]).validate_python(data['lineKeyTemplates']) return r
[docs] def line_key_template_details(self, template_id: str, org_id: str = None) -> LineKeyTemplate: """ Get details of a Line Key Template Get detailed information about a Line Key Template by template ID in an organization. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows users to retrieve a line key template by its ID in an organization. Retrieving a line key template requires a full, user or read-only administrator auth token with a scope of `spark-admin:telephony_config_read`. :param template_id: Get line key template for this template ID. :type template_id: str :param org_id: Retrieve a line key template for this organization. :type org_id: str :rtype: :class:`GetLineKeyTemplateResponse` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/lineKeyTemplates/{template_id}') data = super().get(url, params=params) r = LineKeyTemplate.model_validate(data) return r
[docs] def modify_line_key_template(self, template: LineKeyTemplate, org_id: str = None): """ Modify a Line Key Template Modify a line key template by its template ID in an organization. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows users to modify an existing Line Key Template by its ID in an organization. Modifying an existing line key template requires a full administrator auth token with a scope of `spark-admin:telephony_config_write`. :param template: new line key template settings :type template: LineKeyTemplate :param org_id: Modify a line key template for this organization. :type org_id: str """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/lineKeyTemplates/{template.id}') super().put(url, params=params, json=template.create_or_update())
[docs] def delete_line_key_template(self, template_id: str, org_id: str = None): """ Delete a Line Key Template Delete a Line Key Template by its template ID in an organization. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows users to delete an existing Line Key Templates by its ID in an organization. Deleting an existing line key template requires a full administrator auth token with a scope of `spark-admin:telephony_config_write`. :param template_id: Delete line key template with this template ID. :type template_id: str :param org_id: Delete a line key template for this organization. :type org_id: str :rtype: None """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/lineKeyTemplates/{template_id}') super().delete(url, params=params)
[docs] def preview_apply_line_key_template(self, action: ApplyLineKeyTemplateAction, template_id: str = None, location_ids: list[str] = None, exclude_devices_with_custom_layout: bool = None, include_device_tags: list[str] = None, exclude_device_tags: list[str] = None, advisory_types: LineKeyTemplateAdvisoryTypes = None, org_id: str = None) -> int: """ Preview Apply Line Key Template Preview the number of devices that will be affected by the application of a Line Key Template or when resetting devices to their factory Line Key settings. Line Keys also known as Programmable Line Keys (PLK) are the keys found on either sides of a typical desk phone display. A Line Key Template is a definition of actions that will be performed by each of the Line Keys for a particular device model. This API allows users to preview the number of devices that will be affected if a customer were to apply a Line Key Template or apply factory default Line Key settings to devices. Retrieving the number of devices affected requires a full administrator auth token with a scope of `spark-admin:telephony_config_write`. :param action: Line key Template action to perform. :type action: PostApplyLineKeyTemplateRequestAction :param template_id: `templateId` is required for `APPLY_TEMPLATE` action. :type template_id: str :param location_ids: Used to search for devices only in the given locations. :type location_ids: list[str] :param exclude_devices_with_custom_layout: Indicates whether to exclude devices with custom layout. :type exclude_devices_with_custom_layout: bool :param include_device_tags: Include devices only with these tags. :type include_device_tags: list[str] :param exclude_device_tags: Exclude devices with these tags. :type exclude_device_tags: list[str] :param advisory_types: Refine search with advisories. :type advisory_types: LineKeyTemplateAdvisoryTypes :param org_id: Preview Line Key Template for this organization. :type org_id: str :rtype: int """ params = {} if org_id is not None: params['orgId'] = org_id body = dict() body['action'] = enum_str(action) if template_id is not None: body['templateId'] = template_id if location_ids is not None: body['locationIds'] = location_ids if exclude_devices_with_custom_layout is not None: body['excludeDevicesWithCustomLayout'] = exclude_devices_with_custom_layout if include_device_tags is not None: body['includeDeviceTags'] = include_device_tags if exclude_device_tags is not None: body['excludeDeviceTags'] = exclude_device_tags if advisory_types is not None: body['advisoryTypes'] = advisory_types.model_dump(mode='json', by_alias=True, exclude_none=True) url = self.ep('devices/actions/previewApplyLineKeyTemplate/invoke') data = super().post(url, params=params, json=body) r = data['deviceCount'] return r
[docs] def get_device_layout(self, device_id: str, org_id: str = None) -> DeviceLayout: """ Get Device Layout by Device ID Get layout information of a device by device ID in an organization. Device layout customizes a user’s programmable line keys (PLK) on the phone and any attached Key Expansion Modules (KEM) with the existing configured line members and the user’s monitoring list. This API requires a full or location administrator auth token with a scope of `spark-admin:telephony_config_read`. :param device_id: Get device layout for this device ID. :type device_id: str :param org_id: Retrieve a device layout for the device in this organization. :type org_id: str :rtype: :class:`DeviceLayout` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/{device_id}/layout') data = super().get(url, params=params) r = DeviceLayout.model_validate(data) return r
[docs] def modify_device_layout(self, device_id: str, layout: DeviceLayout, org_id: str = None): """ Modify Device Layout by Device ID Modify the layout of a device by device ID in an organization. Device layout customizes a user’s programmable line keys (PLK) on the phone and any attached Key Expansion Modules (KEM) with the existing configured line members and the user’s monitoring list. This API requires a full or location administrator auth token with a scope of `spark-admin:telephony_config_write`. :param device_id: Modify device layout for this device ID. :type device_id: str :param layout: New layout :param org_id: Modify a device layout for the device in this organization. :type org_id: str :rtype: None """ params = {} if org_id is not None: params['orgId'] = org_id body = layout.update() url = self.ep(f'devices/{device_id}/layout') super().put(url, params=params, json=body)
[docs] def get_person_device_settings(self, person_id: str, org_id: str = None) -> DeviceSettings: """ Get Device Settings for a Person Device settings list the compression settings for a person. Device settings customize a device's behavior and performance. The compression field optimizes call quality for inbound and outbound calls. This API requires a full, location, user, or read-only administrator auth token with a scope of `spark-admin:telephony_config_read`. :param person_id: ID of the person to retrieve device settings. :type person_id: str :param org_id: Retrieves the device settings for a person in this organization. :type org_id: str :rtype: Compression """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'people/{person_id}/devices/settings') data = super().get(url, params=params) r = DeviceSettings.model_validate(data) return r
[docs] def update_person_device_settings(self, person_id: str, settings: DeviceSettings, org_id: str = None): """ Update Device Settings for a Person Update device settings modifies the compression settings for a person. Device settings customize a device's behavior and performance. The compression field optimizes call quality for inbound and outbound calls. This API requires a full, location, or user administrator auth token with a scope of `spark-admin:telephony_config_write`. :param person_id: ID of the person to update device settings. :type person_id: str :param settings: New device settings :type settings: DeviceSettings :param org_id: Modify device settings for a person in this organization. :type org_id: str :rtype: None """ params = {} if org_id is not None: params['orgId'] = org_id body = settings.model_dump(mode='json', exclude_none=True, by_alias=True) url = self.ep(f'people/{person_id}/devices/settings') super().put(url, params=params, json=body)
[docs] def get_workspace_device_settings(self, workspace_id: str, org_id: str = None) -> DeviceSettings: """ Get Device Settings for a Workspace Device settings list the compression settings for a workspace. Device settings customize a device's behavior and performance. The compression field optimizes call quality for inbound and outbound calls. This API requires a full, location, user, or read-only administrator auth token with a scope of `spark-admin:telephony_config_read`. :param workspace_id: ID of the workspace for which to retrieve device settings. :type workspace_id: str :param org_id: Retrieves the device settings for a workspace in this organization. :type org_id: str :rtype: Compression """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'workspaces/{workspace_id}/devices/settings') data = super().get(url, params=params) r = DeviceSettings.model_validate(data) return r
[docs] def update_workspace_device_settings(self, workspace_id: str, settings: DeviceSettings, org_id: str = None): """ Update Device Settings for a Workspace Update device settings modifies the compression settings for a workspace. Device settings customize a device's behavior and performance. The compression field optimizes call quality for inbound and outbound calls. This API requires a full, location, or user administrator auth token with a scope of `spark-admin:telephony_config_write`. :param workspace_id: ID of the workspace for which to update device settings. :type workspace_id: str :param settings: New device settings :type settings: DeviceSettings :param org_id: Modify the device settings for a workspace in this organization. :type org_id: str :rtype: None """ params = {} if org_id is not None: params['orgId'] = org_id body = settings.model_dump(mode='json', exclude_none=True, by_alias=True) url = self.ep(f'workspaces/{workspace_id}/devices/settings') super().put(url, params=params, json=body)
[docs] def list_background_images(self, org_id: str = None) -> BackgroundImages: """ Read the List of Background Images Gets the list of device background images for an organization. Webex Calling supports the upload of up to 100 background image files for each org. These image files can then be referenced by MPP phones in that org for use as their background image. Retrieving this list requires a full, device, or read-only administrator auth token with a scope of `spark-admin:telephony_config_read`. :param org_id: Retrieves the list of images in this organization. :type org_id: str :rtype: :class:`BackgroundImages` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep('devices/backgroundImages') data = super().get(url, params=params) r = BackgroundImages.model_validate(data) return r
[docs] def upload_background_image(self, device_id: str, file: Union[BufferedReader, str], file_name: str = None, org_id: str = None) -> BackgroundImage: """ Upload a Device Background Image Configure a device's background image by uploading an image with file format, `.jpeg` or `.png`, encoded image file. Maximum image file size allowed to upload is 625 KB. The request must be a multipart/form-data request rather than JSON, using the image/jpeg or image/png content-type. Webex Calling supports the upload of up to 100 background image files for each org. These image files can then be referenced by MPP phones in that org for use as their background image. Uploading a device background image requires a full or device administrator auth token with a scope of `spark-admin:telephony_config_write`. :param device_id: Unique identifier for the device. :type device_id: str :param file: the file to be uploaded, can be a path to a file or a buffered reader (opened file); if a reader referring to an open file is passed then make sure to open the file as binary b/c otherwise the content length might be calculated wrong :type file: Union[BufferedReader, str] :param file_name: filename for the content. Only required if content is a reader :type file_name: str :param org_id: Uploads the image in this organization. :type org_id: str :rtype: :class:`BackgroundImage` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'devices/{device_id}/actions/backgroundImageUpload/invoke') if isinstance(file, str): file_name = file_name or os.path.basename(file) file = open(file, mode='rb') must_close = True else: must_close = False # an existing reader if not file_name: raise ValueError('file_name is required') encoder = MultipartEncoder({'fileName': file_name, 'file': (file_name, file, f'image/{file_name.split(".")[-1].lower()}')}) try: data = super().post(url, data=encoder, headers={'Content-Type': encoder.content_type}, params=params) finally: if must_close: file.close() r = BackgroundImage.model_validate(data) return r
[docs] def delete_background_images(self, background_images: list[DeleteImageRequestObject], org_id: str = None) -> DeleteDeviceBackgroundImagesResponse: """ Delete Device Background Images Delete the list of designated device background images for an organization. Maximum is 10 images per request. Deleting a device background image requires a full or device administrator auth token with a scope of `spark-admin:telephony_config_write`. :param background_images: Array of images to be deleted. :type background_images: list[DeleteImageRequestObject] :param org_id: Deletes the list of images in this organization. :type org_id: str :rtype: :class:`DeleteDeviceBackgroundImagesResponse` """ params = {} if org_id is not None: params['orgId'] = org_id body = dict() body['backgroundImages'] = TypeAdapter(list[DeleteImageRequestObject]).dump_python(background_images, mode='json', by_alias=True, exclude_none=True) url = self.ep('devices/backgroundImages') data = super().delete(url, params=params, json=body) r = DeleteDeviceBackgroundImagesResponse.model_validate(data) return r
[docs] def user_devices_count(self, person_id: str, org_id: str = None) -> UserDeviceCount: """ Get User Devices Count Get the total device and application count for a person. The device count can be used to determine if more devices can be added for users with a device count limit. For example, users with standard calling licenses can only have one physical device. This requires a full or read-only administrator or location administrator auth token with a scope of `spark-admin:telephony_config_read`. :param person_id: Person for whom to retrieve the device count. :type person_id: str :param org_id: Organization to which the person belongs. :type org_id: str :rtype: :class:`UserDeviceCount` """ params = {} if org_id is not None: params['orgId'] = org_id url = self.ep(f'people/{person_id}/devices/count') data = super().get(url, params=params) r = UserDeviceCount.model_validate(data) return r