Source code for wxc_sdk.people

"""
People types and API

People are registered users of Webex. Searching and viewing People requires an auth token with a scope
of spark:people_read. Viewing the list of all People in your Organization requires an administrator auth token with
spark-admin:people_read scope. Adding, updating, and removing People requires an administrator auth token with the
spark-admin:people_write and spark-admin:people_read scope.

A person's call settings are for Webex Calling and necessitate Webex Calling licenses.

To learn more about managing people in a room see the Memberships API. For information about how to allocate Hybrid
Services licenses to people, see the Managing Hybrid Services guide.
"""

import datetime
from collections.abc import Generator
from typing import Optional

from pydantic import Field

from ..api_child import ApiChild
from ..base import ApiModel, to_camel, webex_id_to_uuid, ApiModelWithErrors
from ..base import SafeEnum as Enum

__all__ = ['PhoneNumberType', 'PhoneNumber', 'SipType', 'SipAddress', 'PeopleStatus', 'PersonType', 'Person',
           'PeopleApi']

# there seems to be a problem with getting too many users with calling data at the same time
# this is the maximum number the SDK enforces
MAX_USERS_WITH_CALLING_DATA = 10
CALLING_DATA_TIMEOUT_PROTECTION = False


[docs]class PhoneNumberType(str, Enum): """ Webex phone number type """ work = 'work' mobile = 'mobile' fax = 'fax' work_extension = 'work_extension'
[docs]class PhoneNumber(ApiModel): """ Webex phone number: type and Value """ number_type: PhoneNumberType = Field(alias='type') value: str
[docs]class SipType(str, Enum): """ SIP address type """ enterprise = 'enterprise' cloudCalling = 'cloud-calling' personalRoom = 'personal-room' unknown = 'unknown'
[docs]class SipAddress(ApiModel): """ SIP address: type, value and primary indication """ sip_type: SipType = Field(alias='type') value: str primary: bool
[docs]class PeopleStatus(str, Enum): active = 'active' #: active within the last 10 minutes call = 'call' #: the user is in a call do_not_disturb = 'DoNotDisturb' #: the user has manually set their status to "Do Not Disturb" inactive = 'inactive' #: last activity occurred more than 10 minutes ago meeting = 'meeting' #: last activity occurred more than 10 minutes ago out_of_office = 'OutOfOffice' #: the user or a Hybrid Calendar service has indicated that they are "Out of Office" pending = 'pending' #: the user has never logged in; a status cannot be determined presenting = 'presenting' #: the user is sharing content unknown = 'unknown' #: the user’s status could not be determined
[docs]class PersonType(str, Enum): person = 'person' #: account belongs to a person bot = 'bot' #: account is a bot user app_user = 'appuser' #: account is a guest user
[docs]class Person(ApiModelWithErrors): """ Webex person """ #: A unique identifier for the person. person_id: Optional[str] = Field(alias='id') #: The email addresses of the person. emails: Optional[list[str]] #: Phone numbers for the person. phone_numbers: Optional[list[PhoneNumber]] #: The Webex Calling extension for the person. Only applies to a person with a Webex Calling license extension: Optional[str] #: The ID of the location for this person retrieved from BroadCloud. location_id: Optional[str] #: The full name of the person. display_name: Optional[str] #: The nickname of the person if configured. If no nickname is configured for the person, this field will not #: be present. nick_name: Optional[str] #: first_name: Optional[str] first_name: Optional[str] #: The last name of the person. last_name: Optional[str] #: The URL to the person's avatar in PNG format avatar: Optional[str] #: The ID of the organization to which this person belongs. org_id: Optional[str] #: An array of role strings representing the roles to which this person belongs. roles: Optional[list[str]] #: An array of license strings allocated to this person. licenses: Optional[list[str]] #: The date and time the person was created. created: Optional[datetime.datetime] #: The date and time the person was last changed. last_modified: Optional[datetime.datetime] #: The time zone of the person if configured. If no timezone is configured on the account, this field will not be #: present timezone: Optional[str] #: The date and time of the person's last activity within Webex. This will only be returned for people within #: your organization or an organization you manage. Presence information will not be shown if the authenticated #: user has disabled status sharing. last_activity: Optional[str] #: One or several site names where this user has a role (host or attendee) site_urls: Optional[list[str]] #: The users sip addresses sip_addresses: Optional[list[SipAddress]] #: The current presence status of the person. This will only be returned for people within your organization or #: an organization you manage. Presence information will not be shown if the authenticated user has disabled #: status sharing. status: Optional[PeopleStatus] #: Whether or not an invite is pending for the user to complete account activation. This property is only #: returned if the authenticated user is an admin user for the person's organization. #: True: the person has been invited to Webex but has not created an account #: #: False: the person has been invited to Webex but has not created an account invite_pending: Optional[bool] #: Whether or not the user is allowed to use Webex. This property is only returned if the authenticated user is an #: admin user for the person's organization. #: True: the person can log into Webex #: #: False: the person cannot log into Webex login_enabled: Optional[bool] #: The type of person account, such as person or bot. person_type: Optional[PersonType] = Field(alias='type') @property def person_id_uuid(self) -> str: """ person id in uuid format """ return webex_id_to_uuid(self.person_id) @property def plus_e164(self) -> list[PhoneNumber]: """ List of +E.164 phone numbers of the user :return: """ return self.phone_numbers and [number for number in self.phone_numbers if number.value.startswith('+')] or [] @property def tn(self) -> Optional[PhoneNumber]: """ user's TN (first +E.164 number if any) :return: """ if not self.phone_numbers: return None return next((number for number in self.phone_numbers if number.value.startswith('+')), None)
[docs]class PeopleApi(ApiChild, base='people'): """ People API """
[docs] def list(self, email: str = None, display_name: str = None, id_list: list[str] = None, org_id: str = None, calling_data: bool = None, location_id: str = None, **params) -> Generator[Person, None, None]: """ List people in your organization. For most users, either the email or displayName parameter is required. Admin users can omit these fields and list all users in their organization. Response properties associated with a user's presence status, such as status or lastActivity, will only be returned for people within your organization or an organization you manage. Presence information will not be returned if the authenticated user has disabled status sharing. Admin users can include Webex Calling (BroadCloud) user details in the response by specifying callingData parameter as true. Admin users can list all users in a location or with a specific phone number. Admin users will receive an enriched payload with additional administrative fields like liceneses,roles etc. These fields are shown when accessing a user via GET /people/{id}, not when doing a GET /people?id= Lookup by email is only supported for people within the same org or where a partner admin relationship is in place. :param email: List people with this email address. For non-admin requests, either this or displayName are required. :type email: str :param display_name: List people whose name starts with this string. For non-admin requests, either this or email are required. :type display_name: str :param id_list: List people by ID. Accepts up to 85 person IDs. If this parameter is provided then presence information (such as the last_activity or status properties) will not be included in the response. :type id_list: list[str] :param org_id: List people in this organization. Only admin users of another organization (such as partners) may use this parameter. :type org_id: str :param calling_data: Include Webex Calling user details in the response. Default: False :type calling_data: bool :param location_id: List people present in this location. :type location_id: str :return: yield :class:`Person` instances """ params.update((to_camel(k), v) for i, (k, v) in enumerate(locals().items()) if i and v is not None and k != 'params') if calling_data: params['callingData'] = 'true' # apparently there is a performance problem with getting too many users w/ calling data at the same time if CALLING_DATA_TIMEOUT_PROTECTION: params['max'] = params.get('max', MAX_USERS_WITH_CALLING_DATA) id_list = params.pop('idList', None) if id_list: params['id'] = ','.join(id_list) ep = self.ep() # noinspection PyTypeChecker return self.session.follow_pagination(url=ep, model=Person, params=params)
[docs] def create(self, settings: Person, calling_data: bool = False) -> Person: """ Create a Person Create a new user account for a given organization. Only an admin can create a new user account. At least one of the following body parameters is required to create a new user: displayName, firstName, lastName. Currently, users may have only one email address associated with their account. The emails parameter is an array, which accepts multiple values to allow for future expansion, but currently only one email address will be used for the new user. Admin users can include Webex calling (BroadCloud) user details in the response by specifying callingData parameter as true. When doing attendee management, to make the new user an attendee for a site: append #attendee to the siteUrl parameter (eg: mysite.webex.com#attendee). :param settings: settings for new user :type settings: Person :param calling_data: Include Webex Calling user details in the response. :type calling_data: bool :return: new user :rtype: Person """ params = calling_data and {'callingData': 'true'} or None url = self.ep() data = settings.json(exclude={'person_id': True, 'created': True, 'last_modified': True, 'timezone': True, 'last_activity': True, 'sip_addresses': True, 'status': True, 'invite_pending': True, 'login_enabled': True, 'person_type': True}) return Person.parse_obj(self.post(url, data=data, params=params))
[docs] def details(self, person_id: str, calling_data: bool = False) -> Person: """ Shows details for a person, by ID. Response properties associated with a user's presence status, such as status or last_activity, will only be displayed for people within your organization or an organization you manage. Presence information will not be shown if the authenticated user has disabled status sharing. Admin users can include Webex Calling (BroadCloud) user details in the response by specifying calling_data parameter as True. :param person_id: A unique identifier for the person. :type person_id: str :param calling_data: Include Webex Calling user details in the response. Default: false :type calling_data: bool :return: person details :rtype: Person """ ep = self.ep(path=person_id) params = calling_data and {'callingData': 'true'} or None return Person.parse_obj(self.get(ep, params=params))
[docs] def delete_person(self, person_id: str): """ Remove a person from the system. Only an admin can remove a person. :param person_id: A unique identifier for the person. :return: """ ep = self.ep(path=person_id) self.delete(ep)
[docs] def update(self, person: Person, calling_data: bool = False, show_all_types: bool = False) -> Person: """ Update details for a person, by ID. Specify the person ID in the personId parameter in the URI. Only an admin can update a person details. Include all details for the person. This action expects all user details to be present in the request. A common approach is to first GET the person's details, make changes, then PUT both the changed and unchanged values. Admin users can include Webex Calling (BroadCloud) user details in the response by specifying callingData parameter as true. Note: The locationId can only be set when adding a calling license to a user. It cannot be changed if a user is already an existing calling user. When doing attendee management, to update a user from host role to an attendee for a site append #attendee to the respective siteUrl and remove the meeting host license for this site from the license array. To update a person from an attendee role to a host for a site, add the meeting license for this site in the meeting array, and remove that site from the siteurl parameter. To remove the attendee privilege for a user on a meeting site, remove the sitename#attendee from the siteUrls array. The showAllTypes parameter must be set to true. :param person: The person to update :type person: Person :param calling_data: Include Webex Calling user details in the response. Default: False :type calling_data: bool :param show_all_types: Include additional user data like #attendee role :type show_all_types: bool :return: Person details :rtype: Person """ params = {} if calling_data: params['callingData'] = 'true' if show_all_types: params['showAllTypes'] = 'true' if not all(v is not None for v in (person.display_name, person.first_name, person.last_name)): raise ValueError('display_name, first_name, and last_name are required') # some attributes should not be included in update data = person.json(exclude={'created': True, 'last_modified': True, 'timezone': True, 'last_activity': True, 'sip_addresses': True, 'status': True, 'invite_pending': True, 'login_enabled': True, 'person_type': True}) ep = self.ep(path=person.person_id) return Person.parse_obj(self.put(url=ep, data=data, params=params))
[docs] def me(self, calling_data: bool = False) -> Person: """ Show the profile for the authenticated user. This is the same as GET /people/{personId} using the Person ID associated with your Auth token. Admin users can include Webex Calling (BroadCloud) user details in the response by specifying callingData parameter as true. :param calling_data: True -> return calling data :type calling_data: bool :rtype: Person :return: profile of authenticated user """ ep = self.ep('me') params = calling_data and {'callingData': 'true'} or None data = self.get(ep, params=params) result = Person.parse_obj(data) return result