diff --git a/backend/btrixcloud/models.py b/backend/btrixcloud/models.py index 6fa729d1..7af5d49c 100644 --- a/backend/btrixcloud/models.py +++ b/backend/btrixcloud/models.py @@ -212,28 +212,6 @@ class UserOrgInfoOut(BaseModel): role: UserRole -# ============================================================================ -class UserOut(BaseModel): - """Output User model""" - - id: UUID - - name: str = "" - email: EmailStr - is_superuser: bool = False - is_verified: bool = False - - orgs: List[UserOrgInfoOut] - - -# ============================================================================ -class UserEmailWithOrgInfo(BaseModel): - """Output model for getting user email list with org info for each""" - - email: EmailStr - orgs: List[UserOrgInfoOut] - - # ============================================================================ ### CRAWL STATES @@ -1833,6 +1811,8 @@ class SubscriptionCanceledResponse(BaseModel): canceled: bool +# ============================================================================ +# User Org Info With Subs # ============================================================================ class UserOrgInfoOutWithSubs(UserOrgInfoOut): """org per user with sub info""" @@ -1843,6 +1823,24 @@ class UserOrgInfoOutWithSubs(UserOrgInfoOut): subscription: Optional[Subscription] = None +# ============================================================================ +class UserOutNoId(BaseModel): + """Output User Model, no ID""" + + name: str = "" + email: EmailStr + orgs: List[UserOrgInfoOut | UserOrgInfoOutWithSubs] + is_verified: bool = False + + +# ============================================================================ +class UserOut(UserOutNoId): + """Output User Model""" + + id: UUID + is_superuser: bool = False + + # ============================================================================ # ORGS # ============================================================================ @@ -2890,10 +2888,10 @@ class PaginatedCrawlErrorResponse(PaginatedResponse): # ============================================================================ -class PaginatedUserEmailsResponse(PaginatedResponse): +class PaginatedUserOutResponse(PaginatedResponse): """Response model for user emails with org info""" - items: List[UserEmailWithOrgInfo] + items: List[UserOutNoId] # ============================================================================ diff --git a/backend/btrixcloud/users.py b/backend/btrixcloud/users.py index 89d20d6f..e41a583b 100644 --- a/backend/btrixcloud/users.py +++ b/backend/btrixcloud/users.py @@ -28,6 +28,7 @@ from .models import ( UserOrgInfoOut, UserOrgInfoOutWithSubs, UserOut, + UserOutNoId, UserRole, InvitePending, InviteOut, @@ -35,8 +36,7 @@ from .models import ( FailedLogin, UpdatedResponse, SuccessResponse, - UserEmailWithOrgInfo, - PaginatedUserEmailsResponse, + PaginatedUserOutResponse, ) from .pagination import DEFAULT_PAGE_SIZE, paginated_format from .utils import is_bool, dt_now @@ -166,8 +166,11 @@ class UserManager: return user async def get_user_info_with_orgs( - self, user: User, info_out_cls: Type[UserOrgInfoOut] = UserOrgInfoOut - ) -> UserOut: + self, + user: User, + info_out_cls: Type[UserOrgInfoOut | UserOrgInfoOutWithSubs] = UserOrgInfoOut, + user_out_cls: Type[UserOut | UserOutNoId] = UserOut, + ) -> UserOut | UserOutNoId: """return User info""" user_orgs, _ = await self.org_ops.get_orgs_for_user( user, @@ -196,7 +199,7 @@ class UserManager: else: orgs = [] - return UserOut( + return user_out_cls( id=user.id, email=user.email, name=user.name, @@ -558,23 +561,23 @@ class UserManager: self, page_size: int = DEFAULT_PAGE_SIZE, page: int = 1, - ) -> Tuple[List[UserEmailWithOrgInfo], int]: + ) -> Tuple[List[UserOutNoId], int]: """Get user emails with org info for each for paginated endpoint""" # Zero-index page for query page = page - 1 skip = page_size * page - emails: List[UserEmailWithOrgInfo] = [] + emails: List[UserOutNoId] = [] total = await self.users.count_documents({"is_superuser": False}) async for res in self.users.find( {"is_superuser": False}, skip=skip, limit=page_size ): user = User(**res) - user_out = await self.get_user_info_with_orgs(user, UserOrgInfoOutWithSubs) - emails.append( - UserEmailWithOrgInfo(email=user_out.email, orgs=user_out.orgs) + user_out = await self.get_user_info_with_orgs( + user, UserOrgInfoOutWithSubs, UserOutNoId ) + emails.append(user_out) return emails, total @@ -739,7 +742,7 @@ def init_users_router( return paginated_format(pending_invites, total, page, pageSize) @users_router.get( - "/emails", tags=["users"], response_model=PaginatedUserEmailsResponse + "/emails", tags=["users"], response_model=PaginatedUserOutResponse ) async def get_user_emails( user: User = Depends(current_active_user), diff --git a/backend/test/test_users.py b/backend/test/test_users.py index 7ca9e9fc..0832959e 100644 --- a/backend/test/test_users.py +++ b/backend/test/test_users.py @@ -59,7 +59,6 @@ def test_me_with_orgs(crawler_auth_headers, default_org_id): data = r.json() assert data["email"] == CRAWLER_USERNAME_LOWERCASE assert data["id"] - # assert data["is_active"] assert data["is_superuser"] is False assert data["is_verified"] is True assert data["name"] == "new-crawler" @@ -801,6 +800,9 @@ def test_user_emails_endpoint_superuser(admin_auth_headers, default_org_id): for user in user_emails: assert user["email"] + assert "id" not in user + assert "is_superuser" not in user + assert user["is_verified"] == True orgs = user.get("orgs") if orgs == []: continue @@ -810,6 +812,9 @@ def test_user_emails_endpoint_superuser(admin_auth_headers, default_org_id): assert org["name"] assert org["slug"] assert org["default"] in (True, False) + assert "readOnly" in org + assert "readOnlyReason" in org + assert "subscription" in org role = org["role"] assert role assert isinstance(role, int)