@@ -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
}
@@ -281,91 +282,87 @@ async fn modify_owners(
281
282
Ok ( json ! ( { "msg" : comma_sep_msg, "ok" : true } ) )
282
283
}
283
284
284
- /// Finds the owner by name. Always recreates teams to get the most
285
- /// up-to-date GitHub ID. Fails out if the user isn't found in the
286
- /// database, the team isn't found on GitHub, or if the user isn't a member
287
- /// of the team on GitHub.
288
- ///
289
- /// May be a user's GH login or a full team name. This is case
290
- /// sensitive.
291
- pub async fn find_or_create_owner (
285
+ /// Invite `login` as an owner of this crate, returning the created
286
+ /// [`NewOwnerInvite`].
287
+ async fn add_owner (
292
288
app : & App ,
293
289
conn : & mut AsyncPgConnection ,
294
290
req_user : & User ,
295
- name : & str ,
296
- ) -> AppResult < Owner > {
297
- if name. contains ( ':' ) {
298
- Ok ( Owner :: Team (
299
- Team :: create_or_update ( app, conn, name, req_user) . await ?,
300
- ) )
291
+ krate : & Crate ,
292
+ login : & str ,
293
+ ) -> Result < NewOwnerInvite , OwnerAddError > {
294
+ if login. contains ( ':' ) {
295
+ add_team_owner ( app, conn, req_user, krate, login) . await
301
296
} else {
302
- User :: find_by_login ( conn, name)
303
- . await
304
- . optional ( ) ?
305
- . map ( Owner :: User )
306
- . ok_or_else ( || bad_request ( format_args ! ( "could not find user with login `{name}`" ) ) )
297
+ invite_user_owner ( app, conn, req_user, krate, login) . await
307
298
}
308
299
}
309
300
310
- /// Invite `login` as an owner of this crate, returning the created
311
- /// [`NewOwnerInvite`].
312
- async fn add_owner (
301
+ async fn invite_user_owner (
313
302
app : & App ,
314
303
conn : & mut AsyncPgConnection ,
315
304
req_user : & User ,
316
305
krate : & Crate ,
317
306
login : & str ,
318
307
) -> Result < NewOwnerInvite , OwnerAddError > {
319
- use diesel:: insert_into;
320
-
321
- let owner = find_or_create_owner ( app, conn, req_user, login) . await ?;
322
- match owner {
323
- // Users are invited and must accept before being added
324
- Owner :: User ( user) => {
325
- let expires_at = Utc :: now ( ) + app. config . ownership_invitations_expiration ;
326
- let invite = NewCrateOwnerInvitation {
327
- invited_user_id : user. id ,
328
- invited_by_user_id : req_user. id ,
329
- crate_id : krate. id ,
330
- expires_at,
331
- } ;
332
-
333
- let creation_ret = invite. create ( conn) . await . map_err ( BoxedAppError :: from) ?;
334
-
335
- match creation_ret {
336
- NewCrateOwnerInvitationOutcome :: InviteCreated { plaintext_token } => {
337
- Ok ( NewOwnerInvite :: User ( user, plaintext_token) )
338
- }
339
- NewCrateOwnerInvitationOutcome :: AlreadyExists => {
340
- Err ( OwnerAddError :: AlreadyInvited ( Box :: new ( user) ) )
341
- }
342
- }
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) )
343
325
}
344
- // Teams are added as owners immediately
345
- Owner :: Team ( team) => {
346
- insert_into ( crate_owners:: table)
347
- . values ( & CrateOwner {
348
- crate_id : krate. id ,
349
- owner_id : team. id ,
350
- created_by : req_user. id ,
351
- owner_kind : OwnerKind :: Team ,
352
- email_notifications : true ,
353
- } )
354
- . on_conflict ( crate_owners:: table. primary_key ( ) )
355
- . do_update ( )
356
- . set ( crate_owners:: deleted. eq ( false ) )
357
- . execute ( conn)
358
- . await
359
- . map_err ( BoxedAppError :: from) ?;
360
-
361
- Ok ( NewOwnerInvite :: Team ( team) )
326
+ NewCrateOwnerInvitationOutcome :: AlreadyExists => {
327
+ Err ( OwnerAddError :: AlreadyInvited ( Box :: new ( user) ) )
362
328
}
363
329
}
364
330
}
365
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
+
366
361
/// Error results from a [`add_owner()`] model call.
367
362
#[ derive( Debug , Error ) ]
368
363
enum OwnerAddError {
364
+ #[ error( transparent) ]
365
+ Diesel ( #[ from] diesel:: result:: Error ) ,
369
366
/// An opaque [`BoxedAppError`].
370
367
#[ error( "{0}" ) ] // AppError does not impl Error
371
368
AppError ( BoxedAppError ) ,
0 commit comments