@@ -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 }
@@ -281,91 +282,87 @@ async fn modify_owners(
281282 Ok ( json ! ( { "msg" : comma_sep_msg, "ok" : true } ) )
282283}
283284
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 (
292288 app : & App ,
293289 conn : & mut AsyncPgConnection ,
294290 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
301296 } 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
307298 }
308299}
309300
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 (
313302 app : & App ,
314303 conn : & mut AsyncPgConnection ,
315304 req_user : & User ,
316305 krate : & Crate ,
317306 login : & str ,
318307) -> 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) )
343325 }
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) ) )
362328 }
363329 }
364330}
365331
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+
366361/// Error results from a [`add_owner()`] model call.
367362#[ derive( Debug , Error ) ]
368363enum OwnerAddError {
364+ #[ error( transparent) ]
365+ Diesel ( #[ from] diesel:: result:: Error ) ,
369366 /// An opaque [`BoxedAppError`].
370367 #[ error( "{0}" ) ] // AppError does not impl Error
371368 AppError ( BoxedAppError ) ,
0 commit comments