Skip to content

Commit d9620cc

Browse files
committed
feat: add user synchronization with authentication token data
- Implemented a new method in UserService to synchronize user data with information from the authentication token, creating or updating the user as necessary. - Updated the user router to utilize this new synchronization method, enhancing user data management and ensuring consistency between the database and authentication token data.
1 parent e68d32e commit d9620cc

File tree

2 files changed

+82
-24
lines changed

2 files changed

+82
-24
lines changed

src/backend/database/service/user_service.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,61 @@ async def update_user(self, user_id: UUID, data: Dict[str, Any]) -> Optional[Dic
9797
async def delete_user(self, user_id: UUID) -> bool:
9898
"""Delete a user"""
9999
return await self.repository.delete(user_id)
100+
101+
async def sync_user_with_token_data(self, user_id: UUID, token_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
102+
"""
103+
Synchronize user data in the database with data from the authentication token.
104+
If the user doesn't exist, it will be created. If it exists but has different data,
105+
it will be updated to match the token data.
106+
107+
Args:
108+
user_id: The user's UUID
109+
token_data: Dictionary containing user data from the authentication token
110+
111+
Returns:
112+
The user data dictionary or None if operation failed
113+
"""
114+
# Check if user exists
115+
user_data = await self.get_user(user_id)
116+
117+
# If user doesn't exist, create a new one
118+
if not user_data:
119+
try:
120+
return await self.create_user(
121+
user_id=user_id,
122+
username=token_data.get("username", ""),
123+
email=token_data.get("email", ""),
124+
email_verified=token_data.get("email_verified", False),
125+
name=token_data.get("name"),
126+
given_name=token_data.get("given_name"),
127+
family_name=token_data.get("family_name"),
128+
roles=token_data.get("roles", [])
129+
)
130+
except ValueError as e:
131+
# Handle case where user might have been created in a race condition
132+
if "already exists" in str(e):
133+
user_data = await self.get_user(user_id)
134+
else:
135+
raise e
136+
137+
# Check if user data needs to be updated
138+
update_data = {}
139+
fields_to_check = [
140+
"username", "email", "email_verified",
141+
"name", "given_name", "family_name"
142+
]
143+
144+
for field in fields_to_check:
145+
token_value = token_data.get(field)
146+
if token_value is not None and user_data.get(field) != token_value:
147+
update_data[field] = token_value
148+
149+
# Handle roles separately as they might have a different structure
150+
if "roles" in token_data and user_data.get("roles") != token_data["roles"]:
151+
update_data["roles"] = token_data["roles"]
152+
153+
# Update user if any field has changed
154+
if update_data:
155+
return await self.update_user(user_id, update_data)
156+
157+
return user_data

src/backend/routers/user_router.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,34 +57,34 @@ async def get_user_info(
5757
user: UserSession = Depends(require_auth),
5858
user_service: UserService = Depends(get_user_service),
5959
):
60-
"""Get the current user's information"""
61-
62-
user_data = await user.get_user_data(user_service)
63-
64-
if not user_data:
65-
try:
66-
user = await user_service.create_user(
67-
user_id=user.id,
68-
username=user.username,
69-
email=user.email,
70-
email_verified=user.email_verified,
71-
name=user.name,
72-
given_name=user.given_name,
73-
family_name=user.family_name,
74-
roles=user.roles,
75-
)
76-
except Exception as e:
77-
raise HTTPException(
78-
status_code=500,
79-
detail=f"Error creating user: {e}"
80-
)
81-
60+
"""Get the current user's information and sync with token data"""
61+
62+
# Create token data dictionary from UserSession properties
63+
token_data = {
64+
"username": user.username,
65+
"email": user.email,
66+
"email_verified": user.email_verified,
67+
"name": user.name,
68+
"given_name": user.given_name,
69+
"family_name": user.family_name,
70+
"roles": user.roles
71+
}
72+
73+
try:
74+
# Sync user with token data
75+
user_data = await user_service.sync_user_with_token_data(user.id, token_data)
76+
except Exception as e:
77+
raise HTTPException(
78+
status_code=500,
79+
detail=f"Error syncing user data: {e}"
80+
)
81+
8282
if os.getenv("VITE_PUBLIC_POSTHOG_KEY"):
8383
telemetry = user_data.copy()
8484
telemetry["$current_url"] = FRONTEND_URL
8585
posthog.identify(distinct_id=user_data["id"], properties=telemetry)
86-
87-
return user
86+
87+
return user_data
8888

8989

9090
@user_router.get("/count")

0 commit comments

Comments
 (0)