@@ -244,6 +244,7 @@ async fn modify_owners(
244
244
) ) ,
245
245
246
246
// An opaque error occurred.
247
+ Err ( OwnerAddError :: Diesel ( e) ) => return Err ( e. into ( ) ) ,
247
248
Err ( OwnerAddError :: AppError ( e) ) => return Err ( e) ,
248
249
}
249
250
}
@@ -290,56 +291,78 @@ async fn add_owner(
290
291
krate : & Crate ,
291
292
login : & str ,
292
293
) -> 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) )
317
325
}
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) ) )
336
328
}
337
329
}
338
330
}
339
331
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
+
340
361
/// Error results from a [`add_owner()`] model call.
341
362
#[ derive( Debug , Error ) ]
342
363
enum OwnerAddError {
364
+ #[ error( transparent) ]
365
+ Diesel ( #[ from] diesel:: result:: Error ) ,
343
366
/// An opaque [`BoxedAppError`].
344
367
#[ error( "{0}" ) ] // AppError does not impl Error
345
368
AppError ( BoxedAppError ) ,
0 commit comments