Start storing users' github user id

This commit is contained in:
Max Brunsfeld 2022-09-20 09:44:56 -07:00
parent e77263a3c7
commit 9886259b3a
6 changed files with 262 additions and 42 deletions

View file

@ -1,8 +1,10 @@
DROP TABLE signups; DROP TABLE signups;
ALTER TABLE users ALTER TABLE users
DROP COLUMN github_user_id,
DROP COLUMN metrics_id; DROP COLUMN metrics_id;
DROP SEQUENCE metrics_id_seq; DROP SEQUENCE metrics_id_seq;
DROP INDEX index_users_on_email_address; DROP INDEX index_users_on_email_address;
DROP INDEX index_users_on_github_user_id;

View file

@ -19,12 +19,15 @@ CREATE TABLE IF NOT EXISTS "signups" (
"programming_languages" VARCHAR[] "programming_languages" VARCHAR[]
); );
CREATE INDEX "index_users_on_email_address" ON "users" ("email_address");
CREATE UNIQUE INDEX "index_signups_on_email_address" ON "signups" ("email_address"); CREATE UNIQUE INDEX "index_signups_on_email_address" ON "signups" ("email_address");
CREATE INDEX "index_signups_on_email_confirmation_sent" ON "signups" ("email_confirmation_sent"); CREATE INDEX "index_signups_on_email_confirmation_sent" ON "signups" ("email_confirmation_sent");
ALTER TABLE "users" ALTER TABLE "users"
ADD "github_user_id" INTEGER,
ADD "metrics_id" INTEGER DEFAULT nextval('metrics_id_seq'); ADD "metrics_id" INTEGER DEFAULT nextval('metrics_id_seq');
CREATE INDEX "index_users_on_email_address" ON "users" ("email_address");
CREATE INDEX "index_users_on_github_user_id" ON "users" ("github_user_id");
UPDATE users UPDATE users
SET metrics_id = nextval('metrics_id_seq'); SET metrics_id = nextval('metrics_id_seq');

View file

@ -112,9 +112,11 @@ async fn get_users(
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct CreateUserParams { struct CreateUserParams {
github_user_id: i32,
github_login: String, github_login: String,
email_address: String, email_address: String,
email_confirmation_code: Option<String>, email_confirmation_code: Option<String>,
#[serde(default)]
invite_count: i32, invite_count: i32,
} }
@ -123,6 +125,11 @@ async fn create_user(
Extension(app): Extension<Arc<AppState>>, Extension(app): Extension<Arc<AppState>>,
Extension(rpc_server): Extension<Arc<rpc::Server>>, Extension(rpc_server): Extension<Arc<rpc::Server>>,
) -> Result<Json<User>> { ) -> Result<Json<User>> {
let user = NewUserParams {
github_login: params.github_login,
github_user_id: params.github_user_id,
invite_count: params.invite_count,
};
let (user_id, inviter_id) = let (user_id, inviter_id) =
// Creating a user via the normal signup process // Creating a user via the normal signup process
if let Some(email_confirmation_code) = params.email_confirmation_code { if let Some(email_confirmation_code) = params.email_confirmation_code {
@ -132,10 +139,7 @@ async fn create_user(
email_address: params.email_address, email_address: params.email_address,
email_confirmation_code, email_confirmation_code,
}, },
NewUserParams { user,
github_login: params.github_login,
invite_count: params.invite_count,
},
) )
.await? .await?
} }
@ -143,7 +147,7 @@ async fn create_user(
else { else {
( (
app.db app.db
.create_user(&params.github_login, &params.email_address, false) .create_user(&params.email_address, false, user)
.await?, .await?,
None, None,
) )

View file

@ -14,9 +14,9 @@ use time::{OffsetDateTime, PrimitiveDateTime};
pub trait Db: Send + Sync { pub trait Db: Send + Sync {
async fn create_user( async fn create_user(
&self, &self,
github_login: &str,
email_address: &str, email_address: &str,
admin: bool, admin: bool,
params: NewUserParams,
) -> Result<UserId>; ) -> Result<UserId>;
async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>>; async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>>;
async fn fuzzy_search_users(&self, query: &str, limit: u32) -> Result<Vec<User>>; async fn fuzzy_search_users(&self, query: &str, limit: u32) -> Result<Vec<User>>;
@ -196,19 +196,20 @@ impl Db for PostgresDb {
async fn create_user( async fn create_user(
&self, &self,
github_login: &str,
email_address: &str, email_address: &str,
admin: bool, admin: bool,
params: NewUserParams,
) -> Result<UserId> { ) -> Result<UserId> {
let query = " let query = "
INSERT INTO users (github_login, email_address, admin) INSERT INTO users (email_address, github_login, github_user_id, admin)
VALUES ($1, $2, $3) VALUES ($1, $2, $3, $4)
ON CONFLICT (github_login) DO UPDATE SET github_login = excluded.github_login ON CONFLICT (github_login) DO UPDATE SET github_login = excluded.github_login
RETURNING id RETURNING id
"; ";
Ok(sqlx::query_scalar(query) Ok(sqlx::query_scalar(query)
.bind(github_login)
.bind(email_address) .bind(email_address)
.bind(params.github_login)
.bind(params.github_user_id)
.bind(admin) .bind(admin)
.fetch_one(&self.pool) .fetch_one(&self.pool)
.await .await
@ -431,14 +432,15 @@ impl Db for PostgresDb {
let user_id: UserId = sqlx::query_scalar( let user_id: UserId = sqlx::query_scalar(
" "
INSERT INTO users INSERT INTO users
(email_address, github_login, admin, invite_count, invite_code, metrics_id) (email_address, github_login, github_user_id, admin, invite_count, invite_code, metrics_id)
VALUES VALUES
($1, $2, 'f', $3, $4, $5) ($1, $2, $3, 'f', $4, $5, $6)
RETURNING id RETURNING id
", ",
) )
.bind(&invite.email_address) .bind(&invite.email_address)
.bind(&user.github_login) .bind(&user.github_login)
.bind(&user.github_user_id)
.bind(&user.invite_count) .bind(&user.invite_count)
.bind(random_invite_code()) .bind(random_invite_code())
.bind(metrics_id) .bind(metrics_id)
@ -1508,6 +1510,7 @@ id_type!(UserId);
pub struct User { pub struct User {
pub id: UserId, pub id: UserId,
pub github_login: String, pub github_login: String,
pub github_user_id: i32,
pub email_address: Option<String>, pub email_address: Option<String>,
pub admin: bool, pub admin: bool,
pub invite_code: Option<String>, pub invite_code: Option<String>,
@ -1637,6 +1640,7 @@ pub struct Invite {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct NewUserParams { pub struct NewUserParams {
pub github_login: String, pub github_login: String,
pub github_user_id: i32,
pub invite_count: i32, pub invite_count: i32,
} }
@ -1719,16 +1723,16 @@ mod test {
impl Db for FakeDb { impl Db for FakeDb {
async fn create_user( async fn create_user(
&self, &self,
github_login: &str,
email_address: &str, email_address: &str,
admin: bool, admin: bool,
params: NewUserParams,
) -> Result<UserId> { ) -> Result<UserId> {
self.background.simulate_random_delay().await; self.background.simulate_random_delay().await;
let mut users = self.users.lock(); let mut users = self.users.lock();
if let Some(user) = users if let Some(user) = users
.values() .values()
.find(|user| user.github_login == github_login) .find(|user| user.github_login == params.github_login)
{ {
Ok(user.id) Ok(user.id)
} else { } else {
@ -1737,7 +1741,8 @@ mod test {
user_id, user_id,
User { User {
id: user_id, id: user_id,
github_login: github_login.to_string(), github_login: params.github_login,
github_user_id: params.github_user_id,
email_address: Some(email_address.to_string()), email_address: Some(email_address.to_string()),
admin, admin,
invite_code: None, invite_code: None,

View file

@ -12,10 +12,54 @@ async fn test_get_users_by_ids() {
] { ] {
let db = test_db.db(); let db = test_db.db();
let user1 = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user1 = db
let user2 = db.create_user("u2", "u2@example.com", false).await.unwrap(); .create_user(
let user3 = db.create_user("u3", "u3@example.com", false).await.unwrap(); "u1@example.com",
let user4 = db.create_user("u4", "u4@example.com", false).await.unwrap(); false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 1,
invite_count: 0,
},
)
.await
.unwrap();
let user2 = db
.create_user(
"u2@example.com",
false,
NewUserParams {
github_login: "u2".into(),
github_user_id: 2,
invite_count: 0,
},
)
.await
.unwrap();
let user3 = db
.create_user(
"u3@example.com",
false,
NewUserParams {
github_login: "u3".into(),
github_user_id: 3,
invite_count: 0,
},
)
.await
.unwrap();
let user4 = db
.create_user(
"u4@example.com",
false,
NewUserParams {
github_login: "u4".into(),
github_user_id: 4,
invite_count: 0,
},
)
.await
.unwrap();
assert_eq!( assert_eq!(
db.get_users_by_ids(vec![user1, user2, user3, user4]) db.get_users_by_ids(vec![user1, user2, user3, user4])
@ -25,6 +69,7 @@ async fn test_get_users_by_ids() {
User { User {
id: user1, id: user1,
github_login: "u1".to_string(), github_login: "u1".to_string(),
github_user_id: 1,
email_address: Some("u1@example.com".to_string()), email_address: Some("u1@example.com".to_string()),
admin: false, admin: false,
..Default::default() ..Default::default()
@ -32,6 +77,7 @@ async fn test_get_users_by_ids() {
User { User {
id: user2, id: user2,
github_login: "u2".to_string(), github_login: "u2".to_string(),
github_user_id: 2,
email_address: Some("u2@example.com".to_string()), email_address: Some("u2@example.com".to_string()),
admin: false, admin: false,
..Default::default() ..Default::default()
@ -39,6 +85,7 @@ async fn test_get_users_by_ids() {
User { User {
id: user3, id: user3,
github_login: "u3".to_string(), github_login: "u3".to_string(),
github_user_id: 3,
email_address: Some("u3@example.com".to_string()), email_address: Some("u3@example.com".to_string()),
admin: false, admin: false,
..Default::default() ..Default::default()
@ -46,6 +93,7 @@ async fn test_get_users_by_ids() {
User { User {
id: user4, id: user4,
github_login: "u4".to_string(), github_login: "u4".to_string(),
github_user_id: 4,
email_address: Some("u4@example.com".to_string()), email_address: Some("u4@example.com".to_string()),
admin: false, admin: false,
..Default::default() ..Default::default()
@ -60,7 +108,18 @@ async fn test_worktree_extensions() {
let test_db = TestDb::postgres().await; let test_db = TestDb::postgres().await;
let db = test_db.db(); let db = test_db.db();
let user = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user = db
.create_user(
"u1@example.com",
false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
let project = db.register_project(user).await.unwrap(); let project = db.register_project(user).await.unwrap();
db.update_worktree_extensions(project, 100, Default::default()) db.update_worktree_extensions(project, 100, Default::default())
@ -120,9 +179,42 @@ async fn test_user_activity() {
let test_db = TestDb::postgres().await; let test_db = TestDb::postgres().await;
let db = test_db.db(); let db = test_db.db();
let user_1 = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user_1 = db
let user_2 = db.create_user("u2", "u2@example.com", false).await.unwrap(); .create_user(
let user_3 = db.create_user("u3", "u3@example.com", false).await.unwrap(); "u1@example.com",
false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
let user_2 = db
.create_user(
"u2@example.com",
false,
NewUserParams {
github_login: "u2".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
let user_3 = db
.create_user(
"u3@example.com",
false,
NewUserParams {
github_login: "u3".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
let project_1 = db.register_project(user_1).await.unwrap(); let project_1 = db.register_project(user_1).await.unwrap();
db.update_worktree_extensions( db.update_worktree_extensions(
project_1, project_1,
@ -340,7 +432,18 @@ async fn test_recent_channel_messages() {
TestDb::fake(build_background_executor()), TestDb::fake(build_background_executor()),
] { ] {
let db = test_db.db(); let db = test_db.db();
let user = db.create_user("u", "u@example.com", false).await.unwrap(); let user = db
.create_user(
"u@example.com",
false,
NewUserParams {
github_login: "u".into(),
github_user_id: 1,
invite_count: 0,
},
)
.await
.unwrap();
let org = db.create_org("org", "org").await.unwrap(); let org = db.create_org("org", "org").await.unwrap();
let channel = db.create_org_channel(org, "channel").await.unwrap(); let channel = db.create_org_channel(org, "channel").await.unwrap();
for i in 0..10 { for i in 0..10 {
@ -373,7 +476,18 @@ async fn test_channel_message_nonces() {
TestDb::fake(build_background_executor()), TestDb::fake(build_background_executor()),
] { ] {
let db = test_db.db(); let db = test_db.db();
let user = db.create_user("u", "u@example.com", false).await.unwrap(); let user = db
.create_user(
"user@example.com",
false,
NewUserParams {
github_login: "user".into(),
github_user_id: 1,
invite_count: 0,
},
)
.await
.unwrap();
let org = db.create_org("org", "org").await.unwrap(); let org = db.create_org("org", "org").await.unwrap();
let channel = db.create_org_channel(org, "channel").await.unwrap(); let channel = db.create_org_channel(org, "channel").await.unwrap();
@ -404,7 +518,18 @@ async fn test_channel_message_nonces() {
async fn test_create_access_tokens() { async fn test_create_access_tokens() {
let test_db = TestDb::postgres().await; let test_db = TestDb::postgres().await;
let db = test_db.db(); let db = test_db.db();
let user = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user = db
.create_user(
"u1@example.com",
false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 1,
invite_count: 0,
},
)
.await
.unwrap();
db.create_access_token_hash(user, "h1", 3).await.unwrap(); db.create_access_token_hash(user, "h1", 3).await.unwrap();
db.create_access_token_hash(user, "h2", 3).await.unwrap(); db.create_access_token_hash(user, "h2", 3).await.unwrap();
@ -443,7 +568,7 @@ fn test_fuzzy_like_string() {
async fn test_fuzzy_search_users() { async fn test_fuzzy_search_users() {
let test_db = TestDb::postgres().await; let test_db = TestDb::postgres().await;
let db = test_db.db(); let db = test_db.db();
for github_login in [ for (i, github_login) in [
"California", "California",
"colorado", "colorado",
"oregon", "oregon",
@ -451,10 +576,21 @@ async fn test_fuzzy_search_users() {
"florida", "florida",
"delaware", "delaware",
"rhode-island", "rhode-island",
] { ]
db.create_user(github_login, &format!("{github_login}@example.com"), false) .into_iter()
.await .enumerate()
.unwrap(); {
db.create_user(
&format!("{github_login}@example.com"),
false,
NewUserParams {
github_login: github_login.into(),
github_user_id: i as i32,
invite_count: 0,
},
)
.await
.unwrap();
} }
assert_eq!( assert_eq!(
@ -484,9 +620,42 @@ async fn test_add_contacts() {
] { ] {
let db = test_db.db(); let db = test_db.db();
let user_1 = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user_1 = db
let user_2 = db.create_user("u2", "u2@example.com", false).await.unwrap(); .create_user(
let user_3 = db.create_user("u3", "u3@example.com", false).await.unwrap(); "u1@example.com",
false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
let user_2 = db
.create_user(
"u2@example.com",
false,
NewUserParams {
github_login: "u2".into(),
github_user_id: 1,
invite_count: 0,
},
)
.await
.unwrap();
let user_3 = db
.create_user(
"u3@example.com",
false,
NewUserParams {
github_login: "u3".into(),
github_user_id: 2,
invite_count: 0,
},
)
.await
.unwrap();
// User starts with no contacts // User starts with no contacts
assert_eq!( assert_eq!(
@ -700,7 +869,18 @@ async fn test_add_contacts() {
async fn test_invite_codes() { async fn test_invite_codes() {
let postgres = TestDb::postgres().await; let postgres = TestDb::postgres().await;
let db = postgres.db(); let db = postgres.db();
let user1 = db.create_user("u1", "u1@example.com", false).await.unwrap(); let user1 = db
.create_user(
"u1@example.com",
false,
NewUserParams {
github_login: "u1".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await
.unwrap();
// Initially, user 1 has no invite code // Initially, user 1 has no invite code
assert_eq!(db.get_invite_code_for_user(user1).await.unwrap(), None); assert_eq!(db.get_invite_code_for_user(user1).await.unwrap(), None);
@ -724,6 +904,7 @@ async fn test_invite_codes() {
&user2_invite, &user2_invite,
NewUserParams { NewUserParams {
github_login: "user2".into(), github_login: "user2".into(),
github_user_id: 2,
invite_count: 7, invite_count: 7,
}, },
) )
@ -773,6 +954,7 @@ async fn test_invite_codes() {
&user3_invite, &user3_invite,
NewUserParams { NewUserParams {
github_login: "user-3".into(), github_login: "user-3".into(),
github_user_id: 3,
invite_count: 3, invite_count: 3,
}, },
) )
@ -837,6 +1019,7 @@ async fn test_invite_codes() {
&user4_invite, &user4_invite,
NewUserParams { NewUserParams {
github_login: "user-4".into(), github_login: "user-4".into(),
github_user_id: 4,
invite_count: 5, invite_count: 5,
}, },
) )
@ -983,6 +1166,7 @@ async fn test_signups() {
}, },
NewUserParams { NewUserParams {
github_login: "person-0".into(), github_login: "person-0".into(),
github_user_id: 0,
invite_count: 5, invite_count: 5,
}, },
) )
@ -1002,6 +1186,7 @@ async fn test_signups() {
}, },
NewUserParams { NewUserParams {
github_login: "some-other-github_account".into(), github_login: "some-other-github_account".into(),
github_user_id: 1,
invite_count: 5, invite_count: 5,
}, },
) )
@ -1016,6 +1201,7 @@ async fn test_signups() {
}, },
NewUserParams { NewUserParams {
github_login: "person-1".into(), github_login: "person-1".into(),
github_user_id: 2,
invite_count: 5, invite_count: 5,
}, },
) )

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
db::{ProjectId, TestDb, UserId}, db::{NewUserParams, ProjectId, TestDb, UserId},
rpc::{Executor, Server, Store}, rpc::{Executor, Server, Store},
AppState, AppState,
}; };
@ -4641,7 +4641,15 @@ async fn test_random_collaboration(
let mut server = TestServer::start(cx.foreground(), cx.background()).await; let mut server = TestServer::start(cx.foreground(), cx.background()).await;
let db = server.app_state.db.clone(); let db = server.app_state.db.clone();
let host_user_id = db let host_user_id = db
.create_user("host", "host@example.com", false) .create_user(
"host@example.com",
false,
NewUserParams {
github_login: "host".into(),
github_user_id: 0,
invite_count: 0,
},
)
.await .await
.unwrap(); .unwrap();
let mut available_guests = vec![ let mut available_guests = vec![
@ -4651,9 +4659,17 @@ async fn test_random_collaboration(
"guest-4".to_string(), "guest-4".to_string(),
]; ];
for username in &available_guests { for (ix, username) in available_guests.iter().enumerate() {
let guest_user_id = db let guest_user_id = db
.create_user(username, &format!("{username}@example.com"), false) .create_user(
&format!("{username}@example.com"),
false,
NewUserParams {
github_login: username.into(),
github_user_id: ix as i32,
invite_count: 0,
},
)
.await .await
.unwrap(); .unwrap();
assert_eq!(*username, format!("guest-{}", guest_user_id)); assert_eq!(*username, format!("guest-{}", guest_user_id));
@ -5163,7 +5179,11 @@ impl TestServer {
} else { } else {
self.app_state self.app_state
.db .db
.create_user(name, &format!("{name}@example.com"), false) .create_user(&format!("{name}@example.com"), false, NewUserParams {
github_login: name.into(),
github_user_id: 0,
invite_count: 0,
})
.await .await
.unwrap() .unwrap()
}; };