From 8c1a1ea8db258339b4076f7f0dd6ca29c3cd2958 Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Fri, 16 Aug 2024 00:29:51 +0200 Subject: [PATCH] scim: Extract ROLE_TYPE_TO_NAME dict to UserProfile. This allows these mappings to used in other APIs. Specifically, we want to use this for syncing role during SAML auth. --- zerver/lib/scim.py | 15 +++------------ zerver/models/users.py | 11 +++++++++++ zerver/tests/test_scim.py | 3 +-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/zerver/lib/scim.py b/zerver/lib/scim.py index c4387d5c55..df7975c11f 100644 --- a/zerver/lib/scim.py +++ b/zerver/lib/scim.py @@ -32,15 +32,6 @@ class ZulipSCIMUser(SCIMUser): id_field = "id" - ROLE_TYPE_TO_NAME = { - UserProfile.ROLE_REALM_OWNER: "owner", - UserProfile.ROLE_REALM_ADMINISTRATOR: "administrator", - UserProfile.ROLE_MODERATOR: "moderator", - UserProfile.ROLE_MEMBER: "member", - UserProfile.ROLE_GUEST: "guest", - } - ROLE_NAME_TO_TYPE = {v: k for k, v in ROLE_TYPE_TO_NAME.items()} - def __init__(self, obj: UserProfile, request: HttpRequest | None = None) -> None: # We keep the function signature from the superclass, but this actually # shouldn't be called with request being None. @@ -116,7 +107,7 @@ class ZulipSCIMUser(SCIMUser): "name": name, "displayName": self.display_name, "active": self.obj.is_active, - "role": self.ROLE_TYPE_TO_NAME[self.obj.role], + "role": UserProfile.ROLE_ID_TO_API_NAME[self.obj.role], # meta is a property implemented in the superclass # TODO: The upstream implementation uses `user_profile.date_joined` # as the value of the lastModified meta attribute, which is not @@ -200,10 +191,10 @@ class ZulipSCIMUser(SCIMUser): def change_role(self, new_role_name: str) -> None: try: - role = self.ROLE_NAME_TO_TYPE[new_role_name] + role = UserProfile.ROLE_API_NAME_TO_ID[new_role_name] except KeyError: raise scim_exceptions.BadRequestError( - f"Invalid role: {new_role_name}. Valid values are: {list(self.ROLE_NAME_TO_TYPE.keys())}" + f"Invalid role: {new_role_name}. Valid values are: {list(UserProfile.ROLE_API_NAME_TO_ID.keys())}" ) if role != self.obj.role: self._role_new_value = role diff --git a/zerver/models/users.py b/zerver/models/users.py index 28b7f6f836..cdeab1d6e6 100644 --- a/zerver/models/users.py +++ b/zerver/models/users.py @@ -603,6 +603,17 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings): ROLE_GUEST: gettext_lazy("Guest"), } + # Mapping of role ids to simple string identifiers for the roles, + # to be used in API contexts such as SCIM provisioning. + ROLE_ID_TO_API_NAME = { + ROLE_REALM_OWNER: "owner", + ROLE_REALM_ADMINISTRATOR: "administrator", + ROLE_MODERATOR: "moderator", + ROLE_MEMBER: "member", + ROLE_GUEST: "guest", + } + ROLE_API_NAME_TO_ID = {v: k for k, v in ROLE_ID_TO_API_NAME.items()} + class Meta: indexes = [ models.Index(Upper("email"), name="upper_userprofile_email_idx"), diff --git a/zerver/tests/test_scim.py b/zerver/tests/test_scim.py index 3154627872..aec99bb930 100644 --- a/zerver/tests/test_scim.py +++ b/zerver/tests/test_scim.py @@ -9,7 +9,6 @@ from django.conf import settings from typing_extensions import override from zerver.actions.user_settings import do_change_full_name -from zerver.lib.scim import ZulipSCIMUser from zerver.lib.stream_subscription import get_subscribed_stream_ids_for_user from zerver.lib.test_classes import ZulipTestCase from zerver.models import UserProfile @@ -39,7 +38,7 @@ class SCIMTestCase(ZulipTestCase): "userName": user_profile.delivery_email, "name": {"formatted": user_profile.full_name}, "displayName": user_profile.full_name, - "role": ZulipSCIMUser.ROLE_TYPE_TO_NAME[user_profile.role], + "role": UserProfile.ROLE_ID_TO_API_NAME[user_profile.role], "active": True, "meta": { "resourceType": "User",