@@ -100,22 +100,27 @@ async def invitation_respondent_send(
100100 for the concrete user giving him a role "respondent".
101101 """
102102
103+ invited_user_id : uuid .UUID | None = None
103104 try :
104105 async with atomic (session ):
106+ try :
107+ # Resolve invited user first so failure audit events carry user ID
108+ invited_user = await UserService (session ).get_by_email (invitation_schema .email )
109+ invited_user_id = invited_user .id
110+ except UserNotFound :
111+ # Inviting an email that is not yet associated with a user is valid.
112+ # Continue flow to create subject and send invitation.
113+ pass
114+
105115 await AppletService (session , user .id ).exist_by_id (applet_id )
106116 await CheckAccessService (session , user .id ).check_applet_invite_access (applet_id )
107117 invitation_service = InvitationsService (session , user )
108- try :
109- invited_user = await UserService (session ).get_by_email (invitation_schema .email )
110- is_role_exist = await UserAppletAccessService (session , invited_user .id , applet_id ).has_role (
118+ if invited_user_id :
119+ is_role_exist = await UserAppletAccessService (session , invited_user_id , applet_id ).has_role (
111120 Role .RESPONDENT
112121 )
113122 if is_role_exist :
114123 raise RespondentInvitationExist ()
115- except UserNotFound :
116- # Inviting an email that is not yet associated with a user is valid.
117- # Continue flow to create subject and send invitation.
118- pass
119124
120125 subject_service = SubjectsService (session , user .id )
121126 try :
@@ -134,7 +139,8 @@ async def invitation_respondent_send(
134139 event_action = EventAction .APPLET_INVITE_INITIATE ,
135140 user_id = user .id ,
136141 curious_applet_id = [applet_id ],
137- user_target_email = invitation_schema .email ,
142+ user_target_id = invited_user_id ,
143+ user_target_email = None if invited_user_id else invitation_schema .email ,
138144 user_target_roles = [Role .RESPONDENT ],
139145 ** http_audit_fields (request , e ),
140146 )
@@ -146,7 +152,8 @@ async def invitation_respondent_send(
146152 event_action = EventAction .APPLET_INVITE_INITIATE ,
147153 user_id = user .id ,
148154 curious_applet_id = [applet_id ],
149- user_target_email = invitation_schema .email ,
155+ user_target_id = invited_user_id ,
156+ user_target_email = None if invited_user_id else invitation_schema .email ,
150157 user_target_roles = [Role .RESPONDENT ],
151158 ** http_audit_fields (request ),
152159 )
@@ -166,22 +173,27 @@ async def invitation_reviewer_send(
166173 for the concrete user giving him role "reviewer" for specific respondents.
167174 """
168175
176+ invited_user_id : uuid .UUID | None = None
169177 try :
170178 async with atomic (session ):
179+ try :
180+ # Resolve invited user first so failure audit events carry user ID
181+ invited_user = await UserService (session ).get_by_email (invitation_schema .email )
182+ invited_user_id = invited_user .id
183+ except UserNotFound :
184+ # Inviting by email is allowed even if the user does not exist yet.
185+ # Continue so the invitation can be created for later acceptance/registration.
186+ pass
187+
171188 await AppletService (session , user .id ).exist_by_id (applet_id )
172189 await CheckAccessService (session , user .id ).check_applet_invite_access (applet_id )
173190 invitation_srv = InvitationsService (session , user )
174- try :
175- invited_user = await UserService (session ).get_by_email (invitation_schema .email )
176- is_role_exist = await UserAppletAccessService (session , invited_user .id , applet_id ).has_role (
191+ if invited_user_id :
192+ is_role_exist = await UserAppletAccessService (session , invited_user_id , applet_id ).has_role (
177193 Role .REVIEWER
178194 )
179195 if is_role_exist :
180196 raise ManagerInvitationExist ()
181- except UserNotFound :
182- # Inviting by email is allowed even if the user does not exist yet.
183- # Continue so the invitation can be created for later acceptance/registration.
184- invited_user = None
185197
186198 invitation : InvitationDetailForReviewer = await invitation_srv .send_reviewer_invitation (
187199 applet_id , invitation_schema
@@ -192,7 +204,8 @@ async def invitation_reviewer_send(
192204 event_action = EventAction .APPLET_INVITE_INITIATE ,
193205 user_id = user .id ,
194206 curious_applet_id = [applet_id ],
195- user_target_email = invitation_schema .email ,
207+ user_target_id = invited_user_id ,
208+ user_target_email = None if invited_user_id else invitation_schema .email ,
196209 user_target_roles = [Role .REVIEWER ],
197210 ** http_audit_fields (request , e ),
198211 )
@@ -204,7 +217,8 @@ async def invitation_reviewer_send(
204217 event_action = EventAction .APPLET_INVITE_INITIATE ,
205218 user_id = user .id ,
206219 curious_applet_id = [applet_id ],
207- user_target_email = invitation_schema .email ,
220+ user_target_id = invited_user_id ,
221+ user_target_email = None if invited_user_id else invitation_schema .email ,
208222 user_target_roles = [Role .REVIEWER ],
209223 ** http_audit_fields (request ),
210224 )
@@ -225,22 +239,27 @@ async def invitation_managers_send(
225239 "manager", "coordinator", "editor".
226240 """
227241
242+ invited_user_id : uuid .UUID | None = None
228243 try :
229244 async with atomic (session ):
245+ try :
246+ # Resolve invited user first so failure audit events carry user ID
247+ invited_user = await UserService (session ).get_by_email (invitation_schema .email )
248+ invited_user_id = invited_user .id
249+ except UserNotFound :
250+ # Inviting emails that are not yet associated with a user is allowed.
251+ # In this case there is no existing user-role assignment to validate.
252+ pass
253+
230254 await AppletService (session , user .id ).exist_by_id (applet_id )
231255 await CheckAccessService (session , user .id ).check_applet_invite_access (applet_id )
232256 invitation_srv = InvitationsService (session , user )
233- try :
234- invited_user = await UserService (session ).get_by_email (invitation_schema .email )
235- is_role_exist = await UserAppletAccessService (session , invited_user .id , applet_id ).has_role (
257+ if invited_user_id :
258+ is_role_exist = await UserAppletAccessService (session , invited_user_id , applet_id ).has_role (
236259 invitation_schema .role
237260 )
238261 if is_role_exist :
239262 raise ManagerInvitationExist ()
240- except UserNotFound :
241- # Inviting emails that are not yet associated with a user is allowed.
242- # In this case there is no existing user-role assignment to validate.
243- pass
244263
245264 invitation = await invitation_srv .send_managers_invitation (applet_id , invitation_schema )
246265 except BaseError as e :
@@ -249,7 +268,8 @@ async def invitation_managers_send(
249268 event_action = EventAction .APPLET_INVITE_INITIATE ,
250269 user_id = user .id ,
251270 curious_applet_id = [applet_id ],
252- user_target_email = invitation_schema .email ,
271+ user_target_id = invited_user_id ,
272+ user_target_email = None if invited_user_id else invitation_schema .email ,
253273 user_target_roles = [invitation_schema .role ],
254274 ** http_audit_fields (request , e ),
255275 )
@@ -261,7 +281,8 @@ async def invitation_managers_send(
261281 event_action = EventAction .APPLET_INVITE_INITIATE ,
262282 user_id = user .id ,
263283 curious_applet_id = [applet_id ],
264- user_target_email = invitation_schema .email ,
284+ user_target_id = invited_user_id ,
285+ user_target_email = None if invited_user_id else invitation_schema .email ,
265286 user_target_roles = [invitation_schema .role ],
266287 ** http_audit_fields (request ),
267288 )
@@ -277,11 +298,13 @@ async def invitation_accept(
277298):
278299 """General endpoint to approve the applet invitation."""
279300 applet_id = None
301+ invitation_role = None
280302 try :
281303 invitation_service = InvitationsService (session , user )
282304 invitation = await invitation_service .get (key )
283305 if invitation :
284306 applet_id = invitation .applet_id
307+ invitation_role = invitation .role
285308
286309 try :
287310 async with atomic (session ):
@@ -321,6 +344,8 @@ async def invitation_accept(
321344 event_action = EventAction .APPLET_INVITE_ACCEPT ,
322345 user_id = user .id ,
323346 curious_applet_id = [applet_id ] if applet_id else None ,
347+ user_target_id = user .id ,
348+ user_target_roles = [invitation_role ] if invitation_role else None ,
324349 ** http_audit_fields (request , e ),
325350 )
326351 )
@@ -331,6 +356,8 @@ async def invitation_accept(
331356 event_action = EventAction .APPLET_INVITE_ACCEPT ,
332357 user_id = user .id ,
333358 curious_applet_id = [applet_id ],
359+ user_target_id = user .id ,
360+ user_target_roles = [invitation_role ] if invitation_role else None ,
334361 ** http_audit_fields (request ),
335362 )
336363 )
@@ -343,11 +370,13 @@ async def private_invitation_accept(
343370 session = Depends (get_session ),
344371):
345372 applet_id = None
373+ invitation_role = None
346374 try :
347375 private_service = PrivateInvitationService (session )
348376 invitation = await private_service .get_invitation (key )
349377 if invitation :
350378 applet_id = invitation .applet_id
379+ invitation_role = invitation .role
351380
352381 async with atomic (session ):
353382 await private_service .accept_invitation (user , key )
@@ -357,6 +386,8 @@ async def private_invitation_accept(
357386 event_action = EventAction .APPLET_INVITE_ACCEPT ,
358387 user_id = user .id ,
359388 curious_applet_id = [applet_id ] if applet_id else None ,
389+ user_target_id = user .id ,
390+ user_target_roles = [invitation_role ] if invitation_role else None ,
360391 ** http_audit_fields (request , e ),
361392 )
362393 )
@@ -367,6 +398,8 @@ async def private_invitation_accept(
367398 event_action = EventAction .APPLET_INVITE_ACCEPT ,
368399 user_id = user .id ,
369400 curious_applet_id = [applet_id ],
401+ user_target_id = user .id ,
402+ user_target_roles = [invitation_role ] if invitation_role else None ,
370403 ** http_audit_fields (request ),
371404 )
372405 )
@@ -394,6 +427,7 @@ async def invitation_decline(
394427 event_action = EventAction .APPLET_INVITE_DECLINE ,
395428 user_id = user .id ,
396429 curious_applet_id = [applet_id ] if applet_id else None ,
430+ user_target_id = user .id ,
397431 ** http_audit_fields (request , e ),
398432 )
399433 )
@@ -404,6 +438,7 @@ async def invitation_decline(
404438 event_action = EventAction .APPLET_INVITE_DECLINE ,
405439 user_id = user .id ,
406440 curious_applet_id = [applet_id ],
441+ user_target_id = user .id ,
407442 ** http_audit_fields (request ),
408443 )
409444 )
@@ -416,8 +451,17 @@ async def invitation_subject_send(
416451 schema : ShellAccountInvitation = Body (...),
417452 session = Depends (get_session ),
418453) -> Response [InvitationRespondentResponse ]:
454+ invited_user_id : uuid .UUID | None = None
419455 try :
420456 async with atomic (session ):
457+ try :
458+ # Resolve invited user first so failure audit events carry user ID
459+ invited_user = await UserService (session ).get_by_email (schema .email )
460+ invited_user_id = invited_user .id
461+ except UserNotFound :
462+ # Expected: invitee may not have an account yet; proceed with invitation flow.
463+ pass
464+
421465 await AppletService (session , user .id ).exist_by_id (applet_id )
422466 await CheckAccessService (session , user .id ).check_applet_invite_access (applet_id )
423467
@@ -430,16 +474,12 @@ async def invitation_subject_send(
430474
431475 # check role exists
432476 invitation_service = InvitationsService (session , user )
433- try :
434- invited_user = await UserService (session ).get_by_email (schema .email )
435- is_role_exist = await UserAppletAccessService (session , invited_user .id , applet_id ).has_role (
477+ if invited_user_id :
478+ is_role_exist = await UserAppletAccessService (session , invited_user_id , applet_id ).has_role (
436479 Role .RESPONDENT
437480 )
438481 if is_role_exist :
439482 raise RespondentInvitationExist ()
440- except UserNotFound :
441- # Expected: invitee may not have an account yet; proceed with invitation flow.
442- pass
443483
444484 invitation_schema = InvitationRespondentRequest (
445485 email = schema .email ,
@@ -460,7 +500,8 @@ async def invitation_subject_send(
460500 event_action = EventAction .APPLET_INVITE_INITIATE ,
461501 user_id = user .id ,
462502 curious_applet_id = [applet_id ],
463- user_target_email = schema .email ,
503+ user_target_id = invited_user_id ,
504+ user_target_email = None if invited_user_id else schema .email ,
464505 user_target_roles = [Role .RESPONDENT ],
465506 ** http_audit_fields (request , e ),
466507 )
@@ -472,7 +513,8 @@ async def invitation_subject_send(
472513 event_action = EventAction .APPLET_INVITE_INITIATE ,
473514 user_id = user .id ,
474515 curious_applet_id = [applet_id ],
475- user_target_email = schema .email ,
516+ user_target_id = invited_user_id ,
517+ user_target_email = None if invited_user_id else schema .email ,
476518 user_target_roles = [Role .RESPONDENT ],
477519 ** http_audit_fields (request ),
478520 )
0 commit comments