Source code for wxc_sdk.scim.users

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

from pydantic import Field, TypeAdapter

from wxc_sdk.base import ApiModel
from wxc_sdk.base import SafeEnum as Enum
from wxc_sdk.scim.child import ScimApiChild

__all__ = ['EmailObject', 'EmailObjectType', 'ScimUser',
           'EnterpriseUser', 'ManagedOrg',
           'ManagerObject', 'NameObject', 'PatchUserOperation', 'PatchUserOperationOp', 'PhotoObject',
           'PhotoObjectType',
           'UserManager',
           'WebexUser', 'UserAddress', 'UserPhoneNumber',
           'ScimPhoneNumberType', 'SCIM2UsersApi', 'SearchUserResponse', 'SipAddressObject',
           'UserTypeObject', 'ManagedGroup', 'WebexUserMeta', 'ScimMeta', 'ScimValueDisplayRef']

SCHEMAS = [
    "urn:ietf:params:scim:schemas:core:2.0:User",
    "urn:scim:schemas:extension:cisco:webexidentity:2.0:User",
    "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
]


[docs] class PatchUserOperationOp(str, Enum): add = 'add' replace = 'replace' remove = 'remove'
[docs] class PatchUserOperation(ApiModel): #: The operation to perform. op: Optional[PatchUserOperationOp] = None #: A string containing an attribute path describing the target of the operation. path: Optional[str] = None #: New value. value: Optional[str] = None
[docs] class UserManager(ApiModel): #: Webex Identity assigned user identifier of the user's manager. The manager must be in the same org as the user. value: Optional[str] = None
[docs] class SipAddressObject(ApiModel): #: The sip address value. value: Optional[str] = None #: The type of the sipAddress. type: Optional[str] = None #: A human-readable description, primarily used for display purposes. display: Optional[str] = None #: Designate the primary sipAddress. primary: Optional[bool] = None
[docs] class ManagedOrg(ApiModel): #: Webex Identity assigned organization identifier. org_id: Optional[str] = None #: Role in the target organization for the user. role: Optional[str] = None
[docs] class WebexUserMeta(ApiModel): organization_id: Optional[str] = None
[docs] class ManagedGroup(ApiModel): #: Webex Identity assigned group identifier. group_id: Optional[str] = None #: Role in the target group for the user. role: Optional[str] = None
[docs] class WebexUser(ApiModel): #: Account status of the user. account_status: Optional[list[str]] = None #: sipAddress values for the user. sip_addresses: Optional[list[SipAddressObject]] = None #: Organizations that the user can manage. managed_orgs: Optional[list[ManagedOrg]] = None #: Groups that the user can manage. managed_groups: Optional[list[ManagedGroup]] = None # TODO: missing doc provision_source: Optional[str] = None is_teams_on_jabber_enabled: Optional[bool] = None is_uc_call_on_jabber_enabled: Optional[bool] = Field(alias='isUCCallOnJabberEnabled', default=None) user_settings: Optional[list[str]] = None # TODO: only returned as result of create() but not even in details() ? meta: Optional[WebexUserMeta] = None # TODO: undocumented user_name_type: Optional[str] = None # tODO: undocumented license_id: Optional[list[str]] = Field(alias='licenseID', default=None) # TODO: undocumented mac_addresses: Optional[list[str]] = None # TODO: undocumented user_preferences: Optional[list[str]] = None # TODO: undocumented train_site_names: Optional[list[str]] = None # TODO: undocumented managed_sites: Optional[list[dict]] = None # TODO: undocumented teams_cluster_id: Optional[str] = None # TODO: undocumented avatar_sync_enabled: Optional[bool] = None
[docs] class UserTypeObject(str, Enum): user = 'user' room = 'room' external_calling = 'external_calling' calling_service = 'calling_service'
[docs] class NameObject(ApiModel): #: The given name of the user, or first name in most Western languages (e.g., "Sarah" given the full name "Ms. #: Sarah J Henderson, III"). given_name: Optional[str] = None #: The family name of the user, or last name in most Western languages (e.g., "Henderson" given the full name "Ms. #: Sarah J Henderson, III"). family_name: Optional[str] = None #: The middle name(s) of the user (e.g., "Jane" given the full name "Ms. Sarah J Henderson, III"). middle_name: Optional[str] = None #: The honorific prefix(es) of the user, or title in most Western languages (e.g., "Ms." given the full name "Ms. #: Sarah J Henderson, III"). honorific_prefix: Optional[str] = None #: The honorific suffix(es) of the user, or suffix in most Western languages (e.g., "III" given the full name "Ms. #: Sarah J Henderson, III"). honorific_suffix: Optional[str] = None
[docs] class ScimPhoneNumberType(str, Enum): work = 'work' home = 'home' mobile = 'mobile' work_extension = 'work_extension' fax = 'fax' pager = 'pager' other = 'other'
[docs] class UserPhoneNumber(ApiModel): #: phone number. value: Optional[str] = None #: We support the following types of phone numbers: 'mobile', 'work', 'fax', 'work_extension', 'alternate1', #: 'alternate2'. Alternate 1 and Alternate 2 are types inherited from Webex meeting sites. type: Optional[ScimPhoneNumberType] = None #: A human-readable name, primarily used for display purposes. display: Optional[str] = None #: A Boolean value indicating the phone number premary status. primary: Optional[bool] = None
[docs] class PhotoObjectType(str, Enum): photo = 'photo' thumbnail = 'thumbnail' resizable = 'resizable'
[docs] class PhotoObject(ApiModel): #: photo link. value: Optional[str] = None #: The type of the photo type: Optional[PhotoObjectType] = None #: A human-readable description, primarily used for display purposes. display: Optional[str] = None #: A Boolean value indicating the photo usage status. primary: Optional[bool] = None
[docs] class UserAddress(ApiModel): #: address type type: Optional[str] = None #: The full street address component, which may include house number, street name, P.O. box, and multi-line #: extended street address information. This attribute MAY contain newlines. street_address: Optional[str] = None #: The city or locality component. locality: Optional[str] = None #: The state or region component. region: Optional[str] = None #: The zip code or postal code component. postal_code: Optional[str] = None #: The country name component. country: Optional[str] = None
[docs] class EmailObjectType(str, Enum): work = 'work' home = 'home' room = 'room' other = 'other'
[docs] class EmailObject(ApiModel): #: The email address. value: Optional[str] = None #: The type of the email. type: Optional[EmailObjectType] = None #: A human-readable description, primarily used for display purposes. display: Optional[str] = None #: A Boolean value indicating the email status. If the type is work and primary is true, the value must equal #: "userName". primary: Optional[bool] = None
[docs] class ManagerObject(ApiModel): #: Webex Identity assigned user identifier of the user's manager. The manager must be in the same org as the user. value: Optional[str] = None #: The value to display or show the manager's name in Webex. display_name: Optional[str] = None #: The URI corresponding to a SCIM user that is the manager. ref: Optional[str] = Field(alias='$ref', default=None)
[docs] class EnterpriseUser(ApiModel): #: Identifies the name of a cost center. cost_center: Optional[str] = None #: Identifies the name of an organization. organization: Optional[str] = None #: Identifies the name of a division. division: Optional[str] = None #: Identifies the name of a department. department: Optional[str] = None #: Numeric or alphanumeric identifier assigned to a person, typically based on order of hire or association with an #: organization. employee_number: Optional[str] = None #: The user's manager. manager: Optional[ManagerObject] = None
[docs] class ScimMeta(ApiModel): resource_type: Optional[str] = None location: Optional[str] = None version: Optional[str] = None created: Optional[datetime] = None last_modified: Optional[datetime] = None
[docs] class ScimValueDisplayRef(ApiModel): value: Optional[str] = None display: Optional[str] = None ref: Optional[str] = Field(alias='$ref', default=None)
[docs] class ScimUser(ApiModel): #: Input JSON schemas. schemas: Optional[list[str]] = Field(repr=False, default=None) #: Webex Identity assigned user identifier. id: Optional[str] = None #: A unique identifier for the user and is used to authenticate the user in Webex. This attribute must be set to #: the user's primary email address. No other user in Webex may have the same userName value and thus this value #: is required to be unique within Webex. user_name: Optional[str] = None #: A boolean value of "true" or "false" indicating whether the user is active in Webex. active: Optional[bool] = None #: The components of the user's real name. name: Optional[NameObject] = None #: The value to display or show the user's name in Webex. display_name: Optional[str] = None #: A casual name of the user. The value Bob when the user's formal name is Robert. nick_name: Optional[str] = None #: A list of the user's email addresses with an indicator of the user's primary email address. The primary email #: address must be the same value as the user's userName. emails: Optional[list[EmailObject]] = None #: The type of the user. user_type: Optional[UserTypeObject] = None #: A fully qualified URL pointing to a page representing the user's online profile. profile_url: Optional[str] = None #: The user's business title. Examples of a title is "Business Manager". "Senior Accountant", "Engineer" etc. title: Optional[str] = None #: Indicates the user's preferred language. Acceptable values for this field are based on the #: `ISO-696 <http://www.loc.gov/standards/iso639-2/php/code_list.php>`_ and ISO-3166 #: with the 2 letter language code followed by an _ and then the 2-letter country code. Examples are: #: * en_US : for english spoken in the United States #: * fr_FR: for french spoken in France. preferred_language: Optional[str] = None #: The user's locale which is used to represent the user's currency, time format, and numerical representations. #: Acceptable values for this field are based on the `ISO-696 #: <http://www.loc.gov/standards/iso639-2/php/code_list.php>`_ and ISO-3166 #: followed by an _ and then the 2-letter country code. Examples are: #: * en_US : for English spoken in the United States or #: * fr_FR: for French spoken in France. locale: Optional[str] = None #: External identity. external_id: Optional[str] = None #: The user's time zone specified in the `IANA timezone #: <https://nodatime.org/timezones>`_ timezone format, for example, "America/Los_Angeles". timezone: Optional[str] = None #: A list of user's phone numbers with an indicator of primary to specify the user's main number. phone_numbers: Optional[list[UserPhoneNumber]] = None # group information groups: Optional[list[ScimValueDisplayRef]] = None #: A list of photos for the user that represent a thing the user has. photos: Optional[list[PhotoObject]] = None #: User's physical mailing address. addresses: Optional[list[UserAddress]] = None #: SCIM2 enterprise extension enterprise_user: Optional[EnterpriseUser] = Field( alias='urn:ietf:params:scim:schemas:extension:enterprise:2.0:User', default=None) #: The Cisco extension of SCIM 2. webex_user: Optional[WebexUser] = Field( alias='urn:scim:schemas:extension:cisco:webexidentity:2.0:User', default=None) # TODO: undocumented meta: Optional[ScimMeta] = None entitlements: Optional[list[dict]] = None roles: Optional[list[dict]] = None def create_update(self) -> dict: """ :meta private: """ data = self.model_dump(mode='json', exclude_none=True, by_alias=True, exclude={'id': True, 'schemas': True, 'meta': True, 'webex_user': {'meta': True}}) data['schemas'] = SCHEMAS return data
[docs] class SearchUserResponse(ApiModel): #: Input JSON schemas. schemas: Optional[list[str]] = None #: Total number of users in search results. total_results: Optional[int] = None #: The total number of items in a paged result. items_per_page: Optional[int] = None #: Start at the one-based offset in the list of matching users. start_index: Optional[int] = None #: A list of users with details. resources: Optional[list[ScimUser]] = Field(alias='Resources', default=None)
[docs] class SCIM2UsersApi(ScimApiChild, base='identity/scim'): """ SCIM 2 Users Implementation of the SCIM 2.0 user part for user management in a standards based manner. Please also see the `SCIM Specification <http://www.simplecloud.info/>`_. The schema and API design follows the standard SCIM 2.0 definition with detailed in `SCIM 2.0 schema <https://datatracker.ietf.org/doc/html/rfc7643>`_ and SCIM 2.0 Protocol """
[docs] def create(self, org_id: str, user: ScimUser) -> ScimUser: """ Create a user The SCIM 2 /Users API provides a programmatic way to manage users in Webex Identity using The Internet Engineering Task Force standard SCIM 2.0 standard as specified by `RFC 7643 SCIM 2.0 Core Schema <https://datatracker.ietf.org/doc/html/rfc7643>`_ and `RFC 7644 SCIM 2.0 Core Protocol <https://datatracker.ietf.org/doc/html/rfc7644>`_. The WebEx SCIM 2.0 APIs allow clients supporting the SCIM 2.0 standard to manage users, and groups within Webex. Webex supports the following SCIM 2.0 Schemas: • urn:ietf:params:scim:schemas:core:2.0:User • urn:ietf:params:scim:schemas:extension:enterprise:2.0:User • urn:scim:schemas:extension:cisco:webexidentity:2.0:User **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` The following administrators can use this API: - `id_full_admin` - `id_user_admin` **Usage**: 1. Input JSON must contain schema: "urn:ietf:params:scim:schemas:core:2.0:User". 1. Support 3 schemas : - "urn:ietf:params:scim:schemas:core:2.0:User" - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" - "urn:scim:schemas:extension:cisco:webexidentity:2.0:User" 1. Unrecognized schemas (ID/section) are ignored. 1. Read-only attributes provided as input values are ignored. :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param user: User settings :type user: ScimUser :rtype: :class:`ScimUser` """ body = user.create_update() url = self.ep(f'{org_id}/v2/Users') data = super().post(url, json=body) r = ScimUser.model_validate(data) return r
[docs] def details(self, org_id: str, user_id: str) -> ScimUser: """ Get a user **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` - `identity:people_read` The following administrators can use this API: - `id_full_admin` - `id_user_admin` - `id_readonly_admin` - `id_device_admin` :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param user_id: Webex Identity assigned user identifier. :type user_id: str :rtype: :class:`ScimUser` """ url = self.ep(f'{org_id}/v2/Users/{user_id}') data = super().get(url) r = ScimUser.model_validate(data) return r
[docs] def search(self, org_id: str, filter: str = None, attributes: str = None, excluded_attributes: str = None, sort_by: str = None, sort_order: str = None, start_index: int = None, count: int = None, return_groups: bool = None, include_group_details: bool = None, group_usage_types: str = None) -> SearchUserResponse: """ Search users **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` - `identity:people_read` The following administrators can use this API: - `id_full_admin` - `id_user_admin` - `id_readonly_admin` - `id_device_admin` :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param filter: The url encoded filter. If the value is empty, the API will return all users under the organization. The examples below show some search filters: - userName eq "user1@example.com" - userName sw "user1@example" - userName ew "example" - phoneNumbers [ type eq "mobile" and value eq "14170120"] - urn:scim:schemas:extension:cisco:webexidentity:2.0:User:meta.organizationId eq "0ae87ade-8c8a-4952-af08-318798958d0c" - More filter patterns, please check https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.2" .. list-table:: :header-rows: 1 * - **Attributes** - **Operators** * - **SCIM Core** - * - `id` - eq * - `userName` - eq sw ew * - `name.familyName` - eq sw ew * - `name.givenName` - eq sw * - `name.middleName` - eq sw * - `name.formatted` - eq sw * - `displayName` - eq sw ew * - `nickName` - eq sw ew * - `emails.display` - eq sw ew * - `emails.value` - eq sw ew * - `phoneNumbers.value` - eq sw ew * - `phoneNumbers.display` - eq sw ew * - **Enterprise Extensions** - * - `employeeNumber` - eq sw ew * - `costCenter` - eq sw ew * - `organization` - eq sw ew * - `division` - eq sw ew * - `department` - eq sw ew * - `manager.value` - eq * - `manager.displayName` - eq sw ew :type filter: str :param attributes: A multi-valued list of strings indicating the names of resource attributes to return in the response, like 'userName,department,emails'. It supports the SCIM id 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User,userName'. The default is empty, all attributes will be returned :type attributes: str :param excluded_attributes: A multi-valued list of strings indicating the names of resource attributes to be removed from the default set of attributes to return. The default is empty, all attributes will be returned :type excluded_attributes: str :param sort_by: A string indicating the attribute whose value be used to order the returned responses. Now we only allow 'userName, id, meta.lastModified' to sort. :type sort_by: str :param sort_order: A string indicating the order in which the 'sortBy' parameter is applied. Allowed values are 'ascending' and 'descending'. :type sort_order: str :param start_index: An integer indicating the 1-based index of the first query result. The default is 1. :type start_index: int :param count: An integer indicating the desired maximum number of query results per page. The default is 100. :type count: int :param return_groups: Define whether the group information needs to be returned. The default is false. :type return_groups: str :param include_group_details: Define whether the group information with details need been returned. The default is false. :type include_group_details: str :param group_usage_types: Returns groups with details of the specified group type :type group_usage_types: str :rtype: :class:`SearchUserResponse` """ params = {} if filter is not None: params['filter'] = filter if attributes is not None: params['attributes'] = attributes if excluded_attributes is not None: params['excludedAttributes'] = excluded_attributes if sort_by is not None: params['sortBy'] = sort_by if sort_order is not None: params['sortOrder'] = sort_order if start_index is not None: params['startIndex'] = start_index if count is not None: params['count'] = count if return_groups is not None: params['returnGroups'] = return_groups if include_group_details is not None: params['includeGroupDetails'] = include_group_details if group_usage_types is not None: params['groupUsageTypes'] = group_usage_types url = self.ep(f'{org_id}/v2/Users') data = super().get(url, params=params) r = SearchUserResponse.model_validate(data) return r
[docs] def search_all(self, org_id: str, filter: str = None, attributes: str = None, excluded_attributes: str = None, sort_by: str = None, sort_order: str = None, count: int = None, return_groups: str = None, include_group_details: str = None, group_usage_types: str = None) -> Generator[ScimUser, None, None]: """ Same operation as search() but returns a generator of ScimUsers instead of paginated resources See :meth:`SCIM2UsersApi.search` for parameter documentation :param org_id: :param filter: :param attributes: :param excluded_attributes: :param sort_by: :param sort_order: :param count: :param return_groups: :param include_group_details: :param group_usage_types: :return: """ '''async async def search_all_gen(self, org_id: str, filter: str = None, attributes: str = None, excluded_attributes: str = None, sort_by: str = None, sort_order: str = None, count: int = None, return_groups: str = None, include_group_details: str = None, group_usage_types: str = None) -> AsyncGenerator[ScimUser, None, None]: params = {k: v for k, v in locals().items() if k not in {'self', 'count'} and v is not None} start_index = None while True: paginated_result = await self.search(**params, start_index=start_index, count=count) for r in paginated_result.resources: yield r # prepare getting the next page count = paginated_result.items_per_page start_index = paginated_result.start_index + paginated_result.items_per_page if start_index > paginated_result.total_results: break return async def search_all(self, org_id: str, filter: str = None, attributes: str = None, excluded_attributes: str = None, sort_by: str = None, sort_order: str = None, count: int = None, return_groups: str = None, include_group_details: str = None, group_usage_types: str = None) -> list[ScimUser]: params = {k: v for k, v in locals().items() if k not in {'self'} and v is not None} return [u async for u in self.search_all_gen(**params)] ''' params = {k: v for k, v in locals().items() if k not in {'self', 'count'} and v is not None} start_index = None while True: paginated_result = self.search(**params, start_index=start_index, count=count) yield from paginated_result.resources # prepare getting the next page count = paginated_result.items_per_page start_index = paginated_result.start_index + paginated_result.items_per_page if start_index > paginated_result.total_results: break return
[docs] def update(self, org_id: str, user: ScimUser) -> ScimUser: """ Update a user with PUT **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` The following administrators can use this API: - `id_full_admin` - `id_user_admin` **Usage**: 1. Input JSON must contain schema: "urn:ietf:params:scim:schemas:core:2.0:User". 2. Support 3 schemas: - "urn:ietf:params:scim:schemas:core:2.0:User" - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" - "urn:scim:schemas:extension:cisco:webexidentity:2.0:User" 3. Unrecognized schemas (ID/section) are ignored. 4. Read-only attributes provided as input values are ignored. 5. User `id` will not be changed. 6. `meta`.`created` will not be changed. 7. The PUT API replaces the contents of the user's data with the data in the request body. All attributes specified in the request body will replace all existing attributes for the userId specified in the URL. Should you wish to replace or change some attributes as opposed to all attributes please refer to the SCIM PATCH operation https://developer.webex.com/docs/api/v1/scim2-user/update-a-user-with-patch . :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param user: user to be updates :rtype: :class:`ScimUser` """ body = user.create_update() url = self.ep(f'{org_id}/v2/Users/{user.id}') data = super().put(url, json=body) r = ScimUser.model_validate(data) return r
[docs] def patch(self, org_id: str, user_id: str, operations: list[PatchUserOperation]) -> ScimUser: """ Update a user with PATCH **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` The following administrators can use this API: - `id_full_admin` - `id_user_admin` **Usage**: 1. The PATCH API replaces individual attributes of the user's data in the request body. The PATCH api supports `add`, `remove` and `replace` operations on any individual attribute allowing only specific attributes of the user's object to be modified. 2. Each operation against an attribute must be compatible with the attribute's mutability. 3. Each PATCH operation represents a single action to be applied to the same SCIM resource specified by the request URI. Operations are applied sequentially in the order they appear in the array. Each operation in the sequence is applied to the target resource; the resulting resource becomes the target of the next operation. Evaluation continues until all operations are successfully applied or until an error condition is encountered. **Add operations**: The `add` operation is used to add a new attribute value to an existing resource. The operation must contain a `value` member whose content specifies the value to be added. The value may be a quoted value, or it may be a JSON object containing the sub-attributes of the complex attribute specified in the operation's `path`. The result of the add operation depends upon the target location indicated by `path` references: - If omitted, the target location is assumed to be the resource itself. The `value` parameter contains a set of attributes to be added to the resource. - If the target location does not exist, the attribute and value are added. - If the target location specifies a complex attribute, a set of sub-attributes shall be specified in the `value` parameter. - If the target location specifies a multi-valued attribute, a new value is added to the attribute. - If the target location specifies a single-valued attribute, the existing value is replaced. - If the target location specifies an attribute that does not exist (has no value), the attribute is added with the new value. - If the target location exists, the value is replaced. - If the target location already contains the value specified, no changes should be made to the resource. **Replace operations**: The `replace` operation replaces the value at the target location specified by the `path`. The operation performs the following functions, depending on the target location specified by `path`: - If the `path` parameter is omitted, the target is assumed to be the resource itself. In this case, the `value` attribute shall contain a list of one or more attributes that are to be replaced. - If the target location is a single-value attribute, the value of the attribute is replaced. - If the target location is a multi-valued attribute and no filter is specified, the attribute and all values are replaced. - If the target location path specifies an attribute that does not exist, the service provider shall treat the operation as an "add". - If the target location specifies a complex attribute, a set of sub-attributes SHALL be specified in the `value` parameter, which replaces any existing values or adds where an attribute did not previously exist. Sub-attributes that are not specified in the `value` parameters are left unchanged. - If the target location is a multi-valued attribute and a value selection ("valuePath") filter is specified that matches one or more values of the multi-valued attribute, then all matching record values will be replaced. - If the target location is a complex multi-valued attribute with a value selection filter ("valuePath") and a specific sub-attribute (e.g., "addresses[type eq "work"].streetAddress"), the matching sub-attribute of all matching records is replaced. - If the target location is a multi-valued attribute for which a value selection filter ("valuePath") has been supplied and no record match was made, the service provider will indicate the failure by returning HTTP status code 400 and a `scimType` error code of "noTarget". **Remove operations**: The `remove` operation removes the value at the target location specified by the required attribute `path`. The operation performs the following functions, depending on the target location specified by `path`: - If `path` is unspecified, the operation fails with HTTP status code 400 and a "scimType" error code of "noTarget". - If the target location is a single-value attribute, the attribute and its associated value is removed, and the attribute will be considered unassigned. - If the target location is a multi-valued attribute and no filter is specified, the attribute and all values are removed, and the attribute SHALL be considered unassigned. - If the target location is a multi-valued attribute and a complex filter is specified comparing a `value`, the values matched by the filter are removed. If no other values remain after the removal of the selected values, the multi-valued attribute will be considered unassigned. - If the target location is a complex multi-valued attribute and a complex filter is specified based on the attribute's sub-attributes, the matching records are removed. Sub-attributes whose values have been removed will be considered unassigned. If the complex multi-valued attribute has no remaining records, the attribute will be considered unassigned. :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param user_id: Webex Identity assigned user identifier. :type user_id: str :param operations: A list of patch operations. :type operations: list[PatchUserOperation] :rtype: :class:`ScimUser` """ body = dict() body['schemas'] = ["urn:ietf:params:scim:api:messages:2.0:PatchOp"] body['Operations'] = TypeAdapter(list[PatchUserOperation]).dump_python(operations, mode='json', by_alias=True, exclude_none=True) url = self.ep(f'{org_id}/v2/Users/{user_id}') data = super().patch(url, json=body) r = ScimUser.model_validate(data) return r
[docs] def delete(self, org_id: str, user_id: str): """ Delete a user **Authorization** OAuth token rendered by Identity Broker. One of the following OAuth scopes is required: - `identity:people_rw` - `Identity:SCIM` The following administrators can use this API: - `id_full_admin` - `id_user_admin` :param org_id: Webex Identity assigned organization identifier for user's organization. :type org_id: str :param user_id: Webex Identity assigned user identifier. :type user_id: str :rtype: None """ url = self.ep(f'{org_id}/v2/Users/{user_id}') super().delete(url)