Skip to content

Commit 7b58aa2

Browse files
committed
controllers/krate/owners: Extract invite_user_owner() and add_team_owner() fns
1 parent 63a8908 commit 7b58aa2

File tree

1 file changed

+61
-64
lines changed

1 file changed

+61
-64
lines changed

src/controllers/krate/owners.rs

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
368363
enum 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

Comments
 (0)