Skip to content

Commit 2ae1a09

Browse files
committed
Merge branch 'main' into dev
2 parents 06d19e2 + e80ce12 commit 2ae1a09

1 file changed

Lines changed: 49 additions & 78 deletions

File tree

src/routers/user_groups.py

Lines changed: 49 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
# Add models to support user emails in requests
3131
class UserGroupCreate(BaseModel):
3232
name: str
33-
users: Optional[List[str]] = None
33+
user_ids: Optional[List[Union[str, int]]] = None # Can be either user IDs or email addresses
3434

3535

3636
class UserGroupUpdate(BaseModel):
@@ -45,42 +45,45 @@ class UserEmailIdentifier(BaseModel):
4545
email: str
4646

4747

48-
# Helper function to get user ID from email or ID
49-
async def get_user_id(cursor: AsyncCursor, user_identifier: Union[str, int]) -> Optional[int]:
48+
# Helper function to process user_ids from request (used by both POST and PUT)
49+
async def process_user_ids(cursor: AsyncCursor, user_ids: List[Union[str, int]]) -> tuple[List[int], List[tuple]]:
5050
"""
51-
Get a user ID from either an email address or ID.
51+
Process a list of user identifiers (can be integers or strings).
52+
Converts all valid identifiers to integer user IDs.
5253
5354
Parameters
5455
----------
5556
cursor : AsyncCursor
5657
Database cursor
57-
user_identifier : Union[str, int]
58-
Either a user email (string) or user ID (int)
58+
user_ids : List[Union[str, int]]
59+
List of user identifiers (integers or numeric strings)
5960
6061
Returns
6162
-------
62-
Optional[int]
63-
User ID if found, None otherwise
63+
tuple[List[int], List[tuple]]
64+
Tuple of (processed_user_ids, conversions)
65+
where conversions is a list of (original_value, converted_id) tuples
6466
"""
65-
try:
66-
if isinstance(user_identifier, int):
67-
# Check if user exists
68-
user = await db.read_user(cursor, user_identifier)
69-
return user.id if user else None
67+
processed_user_ids = []
68+
conversions = []
69+
70+
for user_id in user_ids:
71+
if isinstance(user_id, str):
72+
# String, try to convert to int
73+
try:
74+
numeric_id = int(user_id)
75+
processed_user_ids.append(numeric_id)
76+
conversions.append((user_id, numeric_id))
77+
logger.debug(f"Converted string '{user_id}' to integer {numeric_id}")
78+
except (ValueError, TypeError):
79+
logger.warning(f"Invalid user ID format: {user_id}")
80+
raise HTTPException(status_code=400, detail=f"Invalid user ID format: {user_id}")
7081
else:
71-
# Try to find user by email
72-
user = await db.read_user_by_email(cursor, user_identifier)
73-
return user.id if user else None
74-
except Exception as e:
75-
logger.error(f"Error in get_user_id: {str(e)}")
76-
bugsnag.notify(
77-
e,
78-
metadata={
79-
"user_identifier": str(user_identifier),
80-
"type": type(user_identifier).__name__
81-
}
82-
)
83-
return None
82+
# Already an int
83+
processed_user_ids.append(user_id)
84+
logger.debug(f"Using integer user ID {user_id} as is")
85+
86+
return processed_user_ids, conversions
8487

8588

8689
@router.get("", response_model=List[UserGroup], **user_group_defaults)
@@ -324,24 +327,21 @@ async def create_user_group(
324327
admin_ids.append(current_user.id) # Make current user an admin
325328
logger.debug(f"Added current user (ID: {current_user.id}) as member and admin")
326329

327-
# Handle email addresses if provided
328-
user_emails_added = []
329-
if group_data.users:
330-
logger.debug(f"Processing {len(group_data.users)} user emails from request body")
331-
for email in group_data.users:
332-
logger.debug(f"Looking up user with email: {email}")
333-
user = await db.read_user_by_email(cursor, email)
334-
if user and user.id and user.id not in user_ids: # Avoid duplicates
335-
user_ids.append(user.id)
336-
user_emails_added.append(email)
337-
logger.debug(f"Added user {user.id} ({email}) as member")
330+
# Process user_ids field
331+
if group_data.user_ids:
332+
logger.debug(f"Processing {len(group_data.user_ids)} user identifiers from request body")
333+
processed_user_ids, conversions = await process_user_ids(cursor, group_data.user_ids)
334+
335+
# Add processed user IDs, avoiding duplicates
336+
for processed_id in processed_user_ids:
337+
if processed_id not in user_ids:
338+
user_ids.append(processed_id)
339+
logger.debug(f"Added user ID {processed_id} as member")
338340
else:
339-
if not user:
340-
logger.warning(f"User with email {email} not found")
341-
elif user.id in user_ids:
342-
logger.debug(f"User {user.id} ({email}) already added to members list")
341+
logger.debug(f"User ID {processed_id} already in members list")
343342

344-
logger.debug(f"Added {len(user_emails_added)} users as members from request body: {user_emails_added}")
343+
if conversions:
344+
logger.debug(f"Converted {len(conversions)} string IDs to integers: {conversions}")
345345

346346
# Handle admin emails if provided
347347
admin_emails_added = []
@@ -400,8 +400,8 @@ async def create_user_group(
400400
},
401401
"group_data": {
402402
"name": group_data.name,
403-
"users_count": len(group_data.users) if group_data.users else 0,
404-
"users": group_data.users if group_data.users else [],
403+
"user_ids_count": len(group_data.user_ids) if group_data.user_ids else 0,
404+
"user_ids": group_data.user_ids if group_data.user_ids else [],
405405
"admins_count": len(admins) if admins else 0,
406406
"admins": admins if admins else [],
407407
"current_user_id": current_user.id if current_user else None,
@@ -532,42 +532,13 @@ async def update_user_group(
532532
logger.warning(f"ID mismatch: path ID {group_id} != body ID {group_data.id}")
533533
raise exceptions.id_mismatch
534534

535-
# Process user_ids field in case it contains emails instead of integer IDs
536-
processed_user_ids = []
537-
email_conversions = []
538-
535+
# Process user_ids field
539536
logger.debug(f"Processing {len(group_data.user_ids)} user identifiers...")
540-
for user_id in group_data.user_ids:
541-
if isinstance(user_id, str):
542-
# Check if it's an email (contains @ sign)
543-
if '@' in user_id:
544-
# This looks like an email address, try to find the user ID
545-
logger.debug(f"Looking up user by email: {user_id}")
546-
user = await db.read_user_by_email(cursor, user_id)
547-
if user and user.id:
548-
processed_user_ids.append(user.id)
549-
email_conversions.append((user_id, user.id))
550-
logger.debug(f"Converted email {user_id} to user ID {user.id}")
551-
else:
552-
logger.warning(f"User with email {user_id} not found")
553-
raise HTTPException(status_code=404, detail=f"User with email {user_id} not found")
554-
else:
555-
# String but not an email, try to convert to int if it's a digit string
556-
try:
557-
numeric_id = int(user_id)
558-
processed_user_ids.append(numeric_id)
559-
logger.debug(f"Converted string '{user_id}' to integer {numeric_id}")
560-
except (ValueError, TypeError):
561-
logger.warning(f"Invalid user ID format: {user_id}")
562-
raise HTTPException(status_code=400, detail=f"Invalid user ID format: {user_id}")
563-
else:
564-
# Already an int
565-
processed_user_ids.append(user_id)
566-
logger.debug(f"Using integer user ID {user_id} as is")
567-
537+
processed_user_ids, conversions = await process_user_ids(cursor, group_data.user_ids)
538+
568539
logger.debug(f"Processed {len(processed_user_ids)} user IDs: {processed_user_ids}")
569-
if email_conversions:
570-
logger.debug(f"Converted {len(email_conversions)} emails to user IDs: {email_conversions}")
540+
if conversions:
541+
logger.debug(f"Converted {len(conversions)} string IDs to integers: {conversions}")
571542

572543
# Log collaborator map details if present
573544
if group_data.collaborator_map:

0 commit comments

Comments
 (0)