Merge branch 'main' into reconnections-2

This commit is contained in:
Antonio Scandurra 2022-12-02 19:09:33 +01:00
commit 969c314315
78 changed files with 2759 additions and 1281 deletions

View file

@ -338,7 +338,7 @@ async fn create_signup(
Json(params): Json<NewSignup>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<()> {
app.db.create_signup(params).await?;
app.db.create_signup(&params).await?;
Ok(())
}

View file

@ -57,16 +57,14 @@ async fn main() {
}
}
let mut zed_user_ids = Vec::<UserId>::new();
for (github_user, admin) in zed_users {
if let Some(user) = db
if db
.get_user_by_github_account(&github_user.login, Some(github_user.id))
.await
.expect("failed to fetch user")
.is_none()
{
zed_user_ids.push(user.id);
} else if let Some(email) = &github_user.email {
zed_user_ids.push(
if let Some(email) = &github_user.email {
db.create_user(
email,
admin,
@ -77,11 +75,8 @@ async fn main() {
},
)
.await
.expect("failed to insert user")
.user_id,
);
} else if admin {
zed_user_ids.push(
.expect("failed to insert user");
} else if admin {
db.create_user(
&format!("{}@zed.dev", github_user.login),
admin,
@ -92,9 +87,8 @@ async fn main() {
},
)
.await
.expect("failed to insert user")
.user_id,
);
.expect("failed to insert user");
}
}
}
}

View file

@ -660,9 +660,9 @@ impl Database {
// signups
pub async fn create_signup(&self, signup: NewSignup) -> Result<()> {
pub async fn create_signup(&self, signup: &NewSignup) -> Result<()> {
self.transact(|tx| async {
signup::ActiveModel {
signup::Entity::insert(signup::ActiveModel {
email_address: ActiveValue::set(signup.email_address.clone()),
email_confirmation_code: ActiveValue::set(random_email_confirmation_code()),
email_confirmation_sent: ActiveValue::set(false),
@ -673,9 +673,15 @@ impl Database {
editor_features: ActiveValue::set(Some(signup.editor_features.clone())),
programming_languages: ActiveValue::set(Some(signup.programming_languages.clone())),
device_id: ActiveValue::set(signup.device_id.clone()),
added_to_mailing_list: ActiveValue::set(signup.added_to_mailing_list),
..Default::default()
}
.insert(&tx)
})
.on_conflict(
OnConflict::column(signup::Column::EmailAddress)
.update_column(signup::Column::EmailAddress)
.to_owned(),
)
.exec(&tx)
.await?;
tx.commit().await?;
Ok(())
@ -746,6 +752,7 @@ impl Database {
.or(signup::Column::PlatformUnknown.eq(true)),
),
)
.order_by_asc(signup::Column::CreatedAt)
.limit(count as u64)
.into_model()
.all(&tx)
@ -772,32 +779,41 @@ impl Database {
Err(anyhow!("email address is already in use"))?;
}
let inviter = match user::Entity::find()
.filter(user::Column::InviteCode.eq(code))
let inviting_user_with_invites = match user::Entity::find()
.filter(
user::Column::InviteCode
.eq(code)
.and(user::Column::InviteCount.gt(0)),
)
.one(&tx)
.await?
{
Some(inviter) => inviter,
Some(inviting_user) => inviting_user,
None => {
return Err(Error::Http(
StatusCode::NOT_FOUND,
"invite code not found".to_string(),
StatusCode::UNAUTHORIZED,
"unable to find an invite code with invites remaining".to_string(),
))?
}
};
if inviter.invite_count == 0 {
Err(Error::Http(
StatusCode::UNAUTHORIZED,
"no invites remaining".to_string(),
))?;
}
user::Entity::update_many()
.filter(
user::Column::Id
.eq(inviting_user_with_invites.id)
.and(user::Column::InviteCount.gt(0)),
)
.col_expr(
user::Column::InviteCount,
Expr::col(user::Column::InviteCount).sub(1),
)
.exec(&tx)
.await?;
let signup = signup::Entity::insert(signup::ActiveModel {
email_address: ActiveValue::set(email_address.into()),
email_confirmation_code: ActiveValue::set(random_email_confirmation_code()),
email_confirmation_sent: ActiveValue::set(false),
inviting_user_id: ActiveValue::set(Some(inviter.id)),
inviting_user_id: ActiveValue::set(Some(inviting_user_with_invites.id)),
platform_linux: ActiveValue::set(false),
platform_mac: ActiveValue::set(false),
platform_windows: ActiveValue::set(false),
@ -873,26 +889,6 @@ impl Database {
let signup = signup.update(&tx).await?;
if let Some(inviting_user_id) = signup.inviting_user_id {
let result = user::Entity::update_many()
.filter(
user::Column::Id
.eq(inviting_user_id)
.and(user::Column::InviteCount.gt(0)),
)
.col_expr(
user::Column::InviteCount,
Expr::col(user::Column::InviteCount).sub(1),
)
.exec(&tx)
.await?;
if result.rows_affected == 0 {
Err(Error::Http(
StatusCode::UNAUTHORIZED,
"no invites remaining".to_string(),
))?;
}
contact::Entity::insert(contact::ActiveModel {
user_id_a: ActiveValue::set(inviting_user_id),
user_id_b: ActiveValue::set(user.id),

View file

@ -20,6 +20,7 @@ pub struct Model {
pub platform_unknown: bool,
pub editor_features: Option<Vec<String>>,
pub programming_languages: Option<Vec<String>>,
pub added_to_mailing_list: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
@ -27,7 +28,7 @@ pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Debug, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
pub struct Invite {
pub email_address: String,
pub email_confirmation_code: String,
@ -42,6 +43,7 @@ pub struct NewSignup {
pub editor_features: Vec<String>,
pub programming_languages: Vec<String>,
pub device_id: Option<String>,
pub added_to_mailing_list: bool,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, FromQueryResult)]

View file

@ -667,19 +667,29 @@ async fn test_signups() {
let test_db = TestDb::postgres(build_background_executor());
let db = test_db.db();
// people sign up on the waitlist
for i in 0..8 {
db.create_signup(NewSignup {
email_address: format!("person-{i}@example.com"),
let usernames = (0..8).map(|i| format!("person-{i}")).collect::<Vec<_>>();
let all_signups = usernames
.iter()
.enumerate()
.map(|(i, username)| NewSignup {
email_address: format!("{username}@example.com"),
platform_mac: true,
platform_linux: i % 2 == 0,
platform_windows: i % 4 == 0,
editor_features: vec!["speed".into()],
programming_languages: vec!["rust".into(), "c".into()],
device_id: Some(format!("device_id_{i}")),
added_to_mailing_list: i != 0, // One user failed to subscribe
})
.await
.unwrap();
.collect::<Vec<NewSignup>>();
// people sign up on the waitlist
for signup in &all_signups {
// users can sign up multiple times without issues
for _ in 0..2 {
db.create_signup(&signup).await.unwrap();
}
}
assert_eq!(
@ -702,9 +712,9 @@ async fn test_signups() {
assert_eq!(
addresses,
&[
"person-0@example.com",
"person-1@example.com",
"person-2@example.com"
all_signups[0].email_address.as_str(),
all_signups[1].email_address.as_str(),
all_signups[2].email_address.as_str()
]
);
assert_ne!(
@ -728,9 +738,9 @@ async fn test_signups() {
assert_eq!(
addresses,
&[
"person-3@example.com",
"person-4@example.com",
"person-5@example.com"
all_signups[3].email_address.as_str(),
all_signups[4].email_address.as_str(),
all_signups[5].email_address.as_str()
]
);
@ -756,11 +766,10 @@ async fn test_signups() {
} = db
.create_user_from_invite(
&Invite {
email_address: signups_batch1[0].email_address.clone(),
email_confirmation_code: signups_batch1[0].email_confirmation_code.clone(),
..signups_batch1[0].clone()
},
NewUserParams {
github_login: "person-0".into(),
github_login: usernames[0].clone(),
github_user_id: 0,
invite_count: 5,
},
@ -770,8 +779,11 @@ async fn test_signups() {
.unwrap();
let user = db.get_user_by_id(user_id).await.unwrap().unwrap();
assert!(inviting_user_id.is_none());
assert_eq!(user.github_login, "person-0");
assert_eq!(user.email_address.as_deref(), Some("person-0@example.com"));
assert_eq!(user.github_login, usernames[0]);
assert_eq!(
user.email_address,
Some(all_signups[0].email_address.clone())
);
assert_eq!(user.invite_count, 5);
assert_eq!(signup_device_id.unwrap(), "device_id_0");
@ -799,7 +811,7 @@ async fn test_signups() {
email_confirmation_code: "the-wrong-code".to_string(),
},
NewUserParams {
github_login: "person-1".into(),
github_login: usernames[1].clone(),
github_user_id: 2,
invite_count: 5,
},

View file

@ -5566,6 +5566,13 @@ async fn test_random_collaboration(
guest_client.username,
id
);
assert_eq!(
guest_snapshot.abs_path(),
host_snapshot.abs_path(),
"{} has different abs path than the host for worktree {}",
guest_client.username,
id
);
assert_eq!(
guest_snapshot.entries(false).collect::<Vec<_>>(),
host_snapshot.entries(false).collect::<Vec<_>>(),