From 708a2768b382d5dd1e3a5019e05fe18f9a40b3d1 Mon Sep 17 00:00:00 2001 From: Nikita Melkozerov <nikita@some.engineering> Date: Mon, 18 Mar 2024 12:30:30 +0000 Subject: [PATCH] Return a better workspace user roles json --- fixbackend/permissions/router.py | 4 ++- fixbackend/workspaces/router.py | 2 +- fixbackend/workspaces/schemas.py | 42 +++++++++++++++++++--- tests/fixbackend/workspaces/router_test.py | 32 +++++++---------- 4 files changed, 54 insertions(+), 26 deletions(-) diff --git a/fixbackend/permissions/router.py b/fixbackend/permissions/router.py index 4db0aa9a..82b1bacb 100644 --- a/fixbackend/permissions/router.py +++ b/fixbackend/permissions/router.py @@ -43,7 +43,9 @@ async def list_roles( roles = no_assigned_roles + roles - return [UserRolesRead.from_model(role) for role in roles] + only_workspace_roles = [role for role in roles if role.workspace_id == workspace.id] + + return [UserRolesRead.from_model(role) for role in only_workspace_roles] @router.put("/{workspace_id}/roles/{user_id}") async def update_user_role( diff --git a/fixbackend/workspaces/router.py b/fixbackend/workspaces/router.py index f3205765..c5091392 100644 --- a/fixbackend/workspaces/router.py +++ b/fixbackend/workspaces/router.py @@ -135,7 +135,7 @@ async def list_users( ) -> List[WorkspaceUserRead]: user_ids = workspace.all_users() users = await user_repository.get_by_ids(user_ids) - return [WorkspaceUserRead.from_model(user) for user in users] + return [WorkspaceUserRead.from_model(user, workspace.id) for user in users] @router.post("/{workspace_id}/invites/") async def invite_to_organization( diff --git a/fixbackend/workspaces/schemas.py b/fixbackend/workspaces/schemas.py index 45c5e686..3a413375 100644 --- a/fixbackend/workspaces/schemas.py +++ b/fixbackend/workspaces/schemas.py @@ -13,14 +13,15 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from datetime import datetime +from functools import reduce from typing import List, Literal, Optional, Union from fixbackend.auth.models import User from fixbackend.ids import InvitationId, WorkspaceId, UserId, ExternalId from pydantic import BaseModel, EmailStr, Field +from fixbackend.permissions.models import Roles, UserRole from fixbackend.workspaces.models import Workspace, WorkspaceInvitation -from fixbackend.permissions.schemas import UserRolesRead class WorkspaceRead(BaseModel): @@ -179,22 +180,55 @@ class FixUserSource(BaseModel): UserSource = Union[FixUserSource] +class WorkspaceUserRoleRead(BaseModel): + member: bool = Field(description="if user has member role") + admin: bool = Field(description="if user has admin role") + owner: bool = Field(description="if user has owner role") + billing_admin: bool = Field(description="if user has billing role") + + @staticmethod + def from_model(model: List[UserRole]) -> "WorkspaceUserRoleRead": + role_names = reduce(lambda x, y: x | y, [role.role_names for role in model], Roles(0)) + + return WorkspaceUserRoleRead( + member=Roles.workspace_member in role_names, + admin=Roles.workspace_admin in role_names, + owner=Roles.workspace_owner in role_names, + billing_admin=Roles.workspace_billing_admin in role_names, + ) + + model_config = { + "json_schema_extra": { + "examples": [ + { + "user_id": "00000000-0000-0000-0000-000000000000", + "user_email": "foo@example.com", + "member": True, + "owner": True, + "admin": False, + "billing_admin": False, + } + ] + } + } + + class WorkspaceUserRead(BaseModel): id: UserId = Field(description="The user's unique identifier") sources: List[UserSource] = Field(description="Where the user is found") name: str = Field(description="The user's name") email: str = Field(description="The user's email") - roles: List[UserRolesRead] = Field(description="The user's roles") + roles: WorkspaceUserRoleRead = Field(description="The user's roles") last_login: Optional[datetime] = Field(description="The user's last login time, if any") @staticmethod - def from_model(user: User) -> "WorkspaceUserRead": + def from_model(user: User, workspace_id: WorkspaceId) -> "WorkspaceUserRead": return WorkspaceUserRead( id=user.id, sources=[FixUserSource()], name=user.email, email=user.email, - roles=[UserRolesRead.from_model(role) for role in user.roles], + roles=WorkspaceUserRoleRead.from_model([role for role in user.roles if role.workspace_id == workspace_id]), last_login=None, ) diff --git a/tests/fixbackend/workspaces/router_test.py b/tests/fixbackend/workspaces/router_test.py index 97e20f82..5309f6d2 100644 --- a/tests/fixbackend/workspaces/router_test.py +++ b/tests/fixbackend/workspaces/router_test.py @@ -110,27 +110,19 @@ async def test_list_workspace_users( assert user_json.get("id") == str(user.id) assert user_json.get("email") == user.email assert user_json.get("name") == user.email - assert user_json.get("roles") == [ - { - "user_id": str(user.id), - "workspace_id": str(workspace.id), - "member": False, - "admin": False, - "owner": True, - "billing_admin": False, - } - ] + assert user_json.get("roles") == { + "member": False, + "admin": False, + "owner": True, + "billing_admin": False, + } await role_repository.add_roles(user.id, workspace.id, Roles.workspace_admin) response = await client.get(f"/api/workspaces/{workspace.id}/users/") user_json = response.json()[0] - assert user_json.get("roles") == [ - { - "user_id": str(user.id), - "workspace_id": str(workspace.id), - "member": False, - "admin": True, - "owner": True, - "billing_admin": False, - } - ] + assert user_json.get("roles") == { + "member": False, + "admin": True, + "owner": True, + "billing_admin": False, + }