@@ -244,6 +244,7 @@ async fn modify_owners(
244244 ) ) ,
245245
246246 // An opaque error occurred.
247+ Err ( OwnerAddError :: Diesel ( e) ) => return Err ( e. into ( ) ) ,
247248 Err ( OwnerAddError :: AppError ( e) ) => return Err ( e) ,
248249 }
249250 }
@@ -290,56 +291,78 @@ async fn add_owner(
290291 krate : & Crate ,
291292 login : & str ,
292293) -> Result < NewOwnerInvite , OwnerAddError > {
293- use diesel:: insert_into;
294-
295- let owner = Owner :: find_or_create_by_login ( app, conn, req_user, login) . await ?;
296- match owner {
297- // Users are invited and must accept before being added
298- Owner :: User ( user) => {
299- let expires_at = Utc :: now ( ) + app. config . ownership_invitations_expiration ;
300- let invite = NewCrateOwnerInvitation {
301- invited_user_id : user. id ,
302- invited_by_user_id : req_user. id ,
303- crate_id : krate. id ,
304- expires_at,
305- } ;
306-
307- let creation_ret = invite. create ( conn) . await . map_err ( BoxedAppError :: from) ?;
308-
309- match creation_ret {
310- NewCrateOwnerInvitationOutcome :: InviteCreated { plaintext_token } => {
311- Ok ( NewOwnerInvite :: User ( user, plaintext_token) )
312- }
313- NewCrateOwnerInvitationOutcome :: AlreadyExists => {
314- Err ( OwnerAddError :: AlreadyInvited ( Box :: new ( user) ) )
315- }
316- }
294+ if login. contains ( ':' ) {
295+ add_team_owner ( app, conn, req_user, krate, login) . await
296+ } else {
297+ invite_user_owner ( app, conn, req_user, krate, login) . await
298+ }
299+ }
300+
301+ async fn invite_user_owner (
302+ app : & App ,
303+ conn : & mut AsyncPgConnection ,
304+ req_user : & User ,
305+ krate : & Crate ,
306+ login : & str ,
307+ ) -> Result < NewOwnerInvite , OwnerAddError > {
308+ let user = User :: find_by_login ( conn, login)
309+ . await
310+ . optional ( ) ?
311+ . ok_or_else ( || bad_request ( format_args ! ( "could not find user with login `{login}`" ) ) ) ?;
312+
313+ // Users are invited and must accept before being added
314+ let expires_at = Utc :: now ( ) + app. config . ownership_invitations_expiration ;
315+ let invite = NewCrateOwnerInvitation {
316+ invited_user_id : user. id ,
317+ invited_by_user_id : req_user. id ,
318+ crate_id : krate. id ,
319+ expires_at,
320+ } ;
321+
322+ match invite. create ( conn) . await ? {
323+ NewCrateOwnerInvitationOutcome :: InviteCreated { plaintext_token } => {
324+ Ok ( NewOwnerInvite :: User ( user, plaintext_token) )
317325 }
318- // Teams are added as owners immediately
319- Owner :: Team ( team) => {
320- insert_into ( crate_owners:: table)
321- . values ( & CrateOwner {
322- crate_id : krate. id ,
323- owner_id : team. id ,
324- created_by : req_user. id ,
325- owner_kind : OwnerKind :: Team ,
326- email_notifications : true ,
327- } )
328- . on_conflict ( crate_owners:: table. primary_key ( ) )
329- . do_update ( )
330- . set ( crate_owners:: deleted. eq ( false ) )
331- . execute ( conn)
332- . await
333- . map_err ( BoxedAppError :: from) ?;
334-
335- Ok ( NewOwnerInvite :: Team ( team) )
326+ NewCrateOwnerInvitationOutcome :: AlreadyExists => {
327+ Err ( OwnerAddError :: AlreadyInvited ( Box :: new ( user) ) )
336328 }
337329 }
338330}
339331
332+ async fn add_team_owner (
333+ app : & App ,
334+ conn : & mut AsyncPgConnection ,
335+ req_user : & User ,
336+ krate : & Crate ,
337+ login : & str ,
338+ ) -> Result < NewOwnerInvite , OwnerAddError > {
339+ // Always recreate teams to get the most up-to-date GitHub ID
340+ let team = Team :: create_or_update ( app, conn, login, req_user) . await ?;
341+
342+ // Teams are added as owners immediately, since the above call ensures
343+ // the user is a team member.
344+ diesel:: insert_into ( crate_owners:: table)
345+ . values ( & CrateOwner {
346+ crate_id : krate. id ,
347+ owner_id : team. id ,
348+ created_by : req_user. id ,
349+ owner_kind : OwnerKind :: Team ,
350+ email_notifications : true ,
351+ } )
352+ . on_conflict ( crate_owners:: table. primary_key ( ) )
353+ . do_update ( )
354+ . set ( crate_owners:: deleted. eq ( false ) )
355+ . execute ( conn)
356+ . await ?;
357+
358+ Ok ( NewOwnerInvite :: Team ( team) )
359+ }
360+
340361/// Error results from a [`add_owner()`] model call.
341362#[ derive( Debug , Error ) ]
342363enum OwnerAddError {
364+ #[ error( transparent) ]
365+ Diesel ( #[ from] diesel:: result:: Error ) ,
343366 /// An opaque [`BoxedAppError`].
344367 #[ error( "{0}" ) ] // AppError does not impl Error
345368 AppError ( BoxedAppError ) ,
0 commit comments