mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Identify users in amplitude via a separate 'metrics_id' UUID
This commit is contained in:
parent
efdedaab53
commit
5d09083a7d
13 changed files with 316 additions and 239 deletions
|
@ -320,11 +320,9 @@ impl Client {
|
||||||
log::info!("set status on client {}: {:?}", self.id, status);
|
log::info!("set status on client {}: {:?}", self.id, status);
|
||||||
let mut state = self.state.write();
|
let mut state = self.state.write();
|
||||||
*state.status.0.borrow_mut() = status;
|
*state.status.0.borrow_mut() = status;
|
||||||
let user_id = state.credentials.as_ref().map(|c| c.user_id);
|
|
||||||
|
|
||||||
match status {
|
match status {
|
||||||
Status::Connected { .. } => {
|
Status::Connected { .. } => {
|
||||||
self.telemetry.set_user_id(user_id);
|
|
||||||
state._reconnect_task = None;
|
state._reconnect_task = None;
|
||||||
}
|
}
|
||||||
Status::ConnectionLost => {
|
Status::ConnectionLost => {
|
||||||
|
@ -353,7 +351,7 @@ impl Client {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Status::SignedOut | Status::UpgradeRequired => {
|
Status::SignedOut | Status::UpgradeRequired => {
|
||||||
self.telemetry.set_user_id(user_id);
|
self.telemetry.set_metrics_id(None);
|
||||||
state._reconnect_task.take();
|
state._reconnect_task.take();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub struct Telemetry {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TelemetryState {
|
struct TelemetryState {
|
||||||
user_id: Option<Arc<str>>,
|
metrics_id: Option<Arc<str>>,
|
||||||
device_id: Option<Arc<str>>,
|
device_id: Option<Arc<str>>,
|
||||||
app_version: Option<Arc<str>>,
|
app_version: Option<Arc<str>>,
|
||||||
os_version: Option<Arc<str>>,
|
os_version: Option<Arc<str>>,
|
||||||
|
@ -115,7 +115,7 @@ impl Telemetry {
|
||||||
flush_task: Default::default(),
|
flush_task: Default::default(),
|
||||||
next_event_id: 0,
|
next_event_id: 0,
|
||||||
log_file: None,
|
log_file: None,
|
||||||
user_id: None,
|
metrics_id: None,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -176,8 +176,8 @@ impl Telemetry {
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_user_id(&self, user_id: Option<u64>) {
|
pub fn set_metrics_id(&self, metrics_id: Option<String>) {
|
||||||
self.state.lock().user_id = user_id.map(|id| id.to_string().into());
|
self.state.lock().metrics_id = metrics_id.map(|s| s.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_event(self: &Arc<Self>, kind: &str, properties: Value) {
|
pub fn report_event(self: &Arc<Self>, kind: &str, properties: Value) {
|
||||||
|
@ -199,7 +199,7 @@ impl Telemetry {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
user_properties: None,
|
user_properties: None,
|
||||||
user_id: state.user_id.clone(),
|
user_id: state.metrics_id.clone(),
|
||||||
device_id: state.device_id.clone(),
|
device_id: state.device_id.clone(),
|
||||||
os_name: state.os_name,
|
os_name: state.os_name,
|
||||||
os_version: state.os_version.clone(),
|
os_version: state.os_version.clone(),
|
||||||
|
|
|
@ -142,10 +142,14 @@ impl UserStore {
|
||||||
match status {
|
match status {
|
||||||
Status::Connected { .. } => {
|
Status::Connected { .. } => {
|
||||||
if let Some((this, user_id)) = this.upgrade(&cx).zip(client.user_id()) {
|
if let Some((this, user_id)) = this.upgrade(&cx).zip(client.user_id()) {
|
||||||
let user = this
|
let fetch_user = this
|
||||||
.update(&mut cx, |this, cx| this.fetch_user(user_id, cx))
|
.update(&mut cx, |this, cx| this.fetch_user(user_id, cx))
|
||||||
.log_err()
|
.log_err();
|
||||||
.await;
|
let fetch_metrics_id =
|
||||||
|
client.request(proto::GetPrivateUserInfo {}).log_err();
|
||||||
|
let (user, info) = futures::join!(fetch_user, fetch_metrics_id);
|
||||||
|
client.telemetry.set_metrics_id(info.map(|i| i.metrics_id));
|
||||||
|
client.telemetry.report_event("sign in", Default::default());
|
||||||
current_user_tx.send(user).await.ok();
|
current_user_tx.send(user).await.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
DROP TABLE signups;
|
|
||||||
|
|
||||||
ALTER TABLE users
|
|
||||||
DROP COLUMN github_user_id;
|
|
||||||
|
|
||||||
DROP INDEX index_users_on_email_address;
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE "users"
|
||||||
|
ADD "metrics_id" uuid NOT NULL DEFAULT gen_random_uuid();
|
|
@ -24,6 +24,7 @@ use tracing::instrument;
|
||||||
|
|
||||||
pub fn routes(rpc_server: &Arc<rpc::Server>, state: Arc<AppState>) -> Router<Body> {
|
pub fn routes(rpc_server: &Arc<rpc::Server>, state: Arc<AppState>) -> Router<Body> {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
.route("/user", get(get_authenticated_user))
|
||||||
.route("/users", get(get_users).post(create_user))
|
.route("/users", get(get_users).post(create_user))
|
||||||
.route("/users/:id", put(update_user).delete(destroy_user))
|
.route("/users/:id", put(update_user).delete(destroy_user))
|
||||||
.route("/users/:id/access_tokens", post(create_access_token))
|
.route("/users/:id/access_tokens", post(create_access_token))
|
||||||
|
@ -85,10 +86,33 @@ pub async fn validate_api_token<B>(req: Request<B>, next: Next<B>) -> impl IntoR
|
||||||
Ok::<_, Error>(next.run(req).await)
|
Ok::<_, Error>(next.run(req).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct AuthenticatedUserParams {
|
||||||
|
github_user_id: i32,
|
||||||
|
github_login: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct AuthenticatedUserResponse {
|
||||||
|
user: User,
|
||||||
|
metrics_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_authenticated_user(
|
||||||
|
Query(params): Query<AuthenticatedUserParams>,
|
||||||
|
Extension(app): Extension<Arc<AppState>>,
|
||||||
|
) -> Result<Json<AuthenticatedUserResponse>> {
|
||||||
|
let user = app
|
||||||
|
.db
|
||||||
|
.get_user_by_github_account(¶ms.github_login, Some(params.github_user_id))
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| Error::Http(StatusCode::NOT_FOUND, "user not found".into()))?;
|
||||||
|
let metrics_id = app.db.get_user_metrics_id(user.id).await?;
|
||||||
|
return Ok(Json(AuthenticatedUserResponse { user, metrics_id }));
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct GetUsersQueryParams {
|
struct GetUsersQueryParams {
|
||||||
github_user_id: Option<i32>,
|
|
||||||
github_login: Option<String>,
|
|
||||||
query: Option<String>,
|
query: Option<String>,
|
||||||
page: Option<u32>,
|
page: Option<u32>,
|
||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
|
@ -98,14 +122,6 @@ async fn get_users(
|
||||||
Query(params): Query<GetUsersQueryParams>,
|
Query(params): Query<GetUsersQueryParams>,
|
||||||
Extension(app): Extension<Arc<AppState>>,
|
Extension(app): Extension<Arc<AppState>>,
|
||||||
) -> Result<Json<Vec<User>>> {
|
) -> Result<Json<Vec<User>>> {
|
||||||
if let Some(github_login) = ¶ms.github_login {
|
|
||||||
let user = app
|
|
||||||
.db
|
|
||||||
.get_user_by_github_account(github_login, params.github_user_id)
|
|
||||||
.await?;
|
|
||||||
return Ok(Json(Vec::from_iter(user)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let limit = params.limit.unwrap_or(100);
|
let limit = params.limit.unwrap_or(100);
|
||||||
let users = if let Some(query) = params.query {
|
let users = if let Some(query) = params.query {
|
||||||
app.db.fuzzy_search_users(&query, limit).await?
|
app.db.fuzzy_search_users(&query, limit).await?
|
||||||
|
@ -124,6 +140,8 @@ struct CreateUserParams {
|
||||||
email_address: String,
|
email_address: String,
|
||||||
email_confirmation_code: Option<String>,
|
email_confirmation_code: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
admin: bool,
|
||||||
|
#[serde(default)]
|
||||||
invite_count: i32,
|
invite_count: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +149,7 @@ struct CreateUserParams {
|
||||||
struct CreateUserResponse {
|
struct CreateUserResponse {
|
||||||
user: User,
|
user: User,
|
||||||
signup_device_id: Option<String>,
|
signup_device_id: Option<String>,
|
||||||
|
metrics_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_user(
|
async fn create_user(
|
||||||
|
@ -143,12 +162,10 @@ async fn create_user(
|
||||||
github_user_id: params.github_user_id,
|
github_user_id: params.github_user_id,
|
||||||
invite_count: params.invite_count,
|
invite_count: params.invite_count,
|
||||||
};
|
};
|
||||||
let user_id;
|
|
||||||
let signup_device_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 {
|
let result = if let Some(email_confirmation_code) = params.email_confirmation_code {
|
||||||
let result = app
|
app.db
|
||||||
.db
|
|
||||||
.create_user_from_invite(
|
.create_user_from_invite(
|
||||||
&Invite {
|
&Invite {
|
||||||
email_address: params.email_address,
|
email_address: params.email_address,
|
||||||
|
@ -156,34 +173,37 @@ async fn create_user(
|
||||||
},
|
},
|
||||||
user,
|
user,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?
|
||||||
user_id = result.user_id;
|
|
||||||
signup_device_id = result.signup_device_id;
|
|
||||||
if let Some(inviter_id) = result.inviting_user_id {
|
|
||||||
rpc_server
|
|
||||||
.invite_code_redeemed(inviter_id, user_id)
|
|
||||||
.await
|
|
||||||
.trace_err();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Creating a user as an admin
|
// Creating a user as an admin
|
||||||
else {
|
else if params.admin {
|
||||||
user_id = app
|
app.db
|
||||||
.db
|
|
||||||
.create_user(¶ms.email_address, false, user)
|
.create_user(¶ms.email_address, false, user)
|
||||||
.await?;
|
.await?
|
||||||
signup_device_id = None;
|
} else {
|
||||||
|
Err(Error::Http(
|
||||||
|
StatusCode::UNPROCESSABLE_ENTITY,
|
||||||
|
"email confirmation code is required".into(),
|
||||||
|
))?
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(inviter_id) = result.inviting_user_id {
|
||||||
|
rpc_server
|
||||||
|
.invite_code_redeemed(inviter_id, result.user_id)
|
||||||
|
.await
|
||||||
|
.trace_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = app
|
let user = app
|
||||||
.db
|
.db
|
||||||
.get_user_by_id(user_id)
|
.get_user_by_id(result.user_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| anyhow!("couldn't find the user we just created"))?;
|
.ok_or_else(|| anyhow!("couldn't find the user we just created"))?;
|
||||||
|
|
||||||
Ok(Json(CreateUserResponse {
|
Ok(Json(CreateUserResponse {
|
||||||
user,
|
user,
|
||||||
signup_device_id,
|
metrics_id: result.metrics_id,
|
||||||
|
signup_device_id: result.signup_device_id,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,11 @@ pub trait Db: Send + Sync {
|
||||||
email_address: &str,
|
email_address: &str,
|
||||||
admin: bool,
|
admin: bool,
|
||||||
params: NewUserParams,
|
params: NewUserParams,
|
||||||
) -> Result<UserId>;
|
) -> Result<NewUserResult>;
|
||||||
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>>;
|
||||||
async fn get_user_by_id(&self, id: UserId) -> Result<Option<User>>;
|
async fn get_user_by_id(&self, id: UserId) -> Result<Option<User>>;
|
||||||
|
async fn get_user_metrics_id(&self, id: UserId) -> Result<String>;
|
||||||
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>>;
|
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>>;
|
||||||
async fn get_users_with_no_invites(&self, invited_by_another_user: bool) -> Result<Vec<User>>;
|
async fn get_users_with_no_invites(&self, invited_by_another_user: bool) -> Result<Vec<User>>;
|
||||||
async fn get_user_by_github_account(
|
async fn get_user_by_github_account(
|
||||||
|
@ -208,21 +209,26 @@ impl Db for PostgresDb {
|
||||||
email_address: &str,
|
email_address: &str,
|
||||||
admin: bool,
|
admin: bool,
|
||||||
params: NewUserParams,
|
params: NewUserParams,
|
||||||
) -> Result<UserId> {
|
) -> Result<NewUserResult> {
|
||||||
let query = "
|
let query = "
|
||||||
INSERT INTO users (email_address, github_login, github_user_id, admin)
|
INSERT INTO users (email_address, github_login, github_user_id, admin)
|
||||||
VALUES ($1, $2, $3, $4)
|
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, metrics_id::text
|
||||||
";
|
";
|
||||||
Ok(sqlx::query_scalar(query)
|
let (user_id, metrics_id): (UserId, String) = sqlx::query_as(query)
|
||||||
.bind(email_address)
|
.bind(email_address)
|
||||||
.bind(params.github_login)
|
.bind(params.github_login)
|
||||||
.bind(params.github_user_id)
|
.bind(params.github_user_id)
|
||||||
.bind(admin)
|
.bind(admin)
|
||||||
.fetch_one(&self.pool)
|
.fetch_one(&self.pool)
|
||||||
.await
|
.await?;
|
||||||
.map(UserId)?)
|
Ok(NewUserResult {
|
||||||
|
user_id,
|
||||||
|
metrics_id,
|
||||||
|
signup_device_id: None,
|
||||||
|
inviting_user_id: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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>> {
|
||||||
|
@ -256,6 +262,18 @@ impl Db for PostgresDb {
|
||||||
Ok(users.into_iter().next())
|
Ok(users.into_iter().next())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_user_metrics_id(&self, id: UserId) -> Result<String> {
|
||||||
|
let query = "
|
||||||
|
SELECT metrics_id::text
|
||||||
|
FROM users
|
||||||
|
WHERE id = $1
|
||||||
|
";
|
||||||
|
Ok(sqlx::query_scalar(query)
|
||||||
|
.bind(id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
|
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
|
||||||
let ids = ids.into_iter().map(|id| id.0).collect::<Vec<_>>();
|
let ids = ids.into_iter().map(|id| id.0).collect::<Vec<_>>();
|
||||||
let query = "
|
let query = "
|
||||||
|
@ -493,13 +511,13 @@ impl Db for PostgresDb {
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_id: UserId = sqlx::query_scalar(
|
let (user_id, metrics_id): (UserId, String) = sqlx::query_as(
|
||||||
"
|
"
|
||||||
INSERT INTO users
|
INSERT INTO users
|
||||||
(email_address, github_login, github_user_id, admin, invite_count, invite_code)
|
(email_address, github_login, github_user_id, admin, invite_count, invite_code)
|
||||||
VALUES
|
VALUES
|
||||||
($1, $2, $3, 'f', $4, $5)
|
($1, $2, $3, 'f', $4, $5)
|
||||||
RETURNING id
|
RETURNING id, metrics_id::text
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.bind(&invite.email_address)
|
.bind(&invite.email_address)
|
||||||
|
@ -559,6 +577,7 @@ impl Db for PostgresDb {
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
Ok(NewUserResult {
|
Ok(NewUserResult {
|
||||||
user_id,
|
user_id,
|
||||||
|
metrics_id,
|
||||||
inviting_user_id,
|
inviting_user_id,
|
||||||
signup_device_id,
|
signup_device_id,
|
||||||
})
|
})
|
||||||
|
@ -1722,6 +1741,7 @@ pub struct NewUserParams {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NewUserResult {
|
pub struct NewUserResult {
|
||||||
pub user_id: UserId,
|
pub user_id: UserId,
|
||||||
|
pub metrics_id: String,
|
||||||
pub inviting_user_id: Option<UserId>,
|
pub inviting_user_id: Option<UserId>,
|
||||||
pub signup_device_id: Option<String>,
|
pub signup_device_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -1808,15 +1828,15 @@ mod test {
|
||||||
email_address: &str,
|
email_address: &str,
|
||||||
admin: bool,
|
admin: bool,
|
||||||
params: NewUserParams,
|
params: NewUserParams,
|
||||||
) -> Result<UserId> {
|
) -> Result<NewUserResult> {
|
||||||
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
|
let user_id = if let Some(user) = users
|
||||||
.values()
|
.values()
|
||||||
.find(|user| user.github_login == params.github_login)
|
.find(|user| user.github_login == params.github_login)
|
||||||
{
|
{
|
||||||
Ok(user.id)
|
user.id
|
||||||
} else {
|
} else {
|
||||||
let id = post_inc(&mut *self.next_user_id.lock());
|
let id = post_inc(&mut *self.next_user_id.lock());
|
||||||
let user_id = UserId(id);
|
let user_id = UserId(id);
|
||||||
|
@ -1833,8 +1853,14 @@ mod test {
|
||||||
connected_once: false,
|
connected_once: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(user_id)
|
user_id
|
||||||
}
|
};
|
||||||
|
Ok(NewUserResult {
|
||||||
|
user_id,
|
||||||
|
metrics_id: "the-metrics-id".to_string(),
|
||||||
|
inviting_user_id: None,
|
||||||
|
signup_device_id: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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>> {
|
||||||
|
@ -1850,6 +1876,10 @@ mod test {
|
||||||
Ok(self.get_users_by_ids(vec![id]).await?.into_iter().next())
|
Ok(self.get_users_by_ids(vec![id]).await?.into_iter().next())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_user_metrics_id(&self, _id: UserId) -> Result<String> {
|
||||||
|
Ok("the-metrics-id".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
|
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
|
||||||
self.background.simulate_random_delay().await;
|
self.background.simulate_random_delay().await;
|
||||||
let users = self.users.lock();
|
let users = self.users.lock();
|
||||||
|
|
|
@ -12,89 +12,56 @@ async fn test_get_users_by_ids() {
|
||||||
] {
|
] {
|
||||||
let db = test_db.db();
|
let db = test_db.db();
|
||||||
|
|
||||||
let user1 = db
|
let mut user_ids = Vec::new();
|
||||||
.create_user(
|
for i in 1..=4 {
|
||||||
"u1@example.com",
|
user_ids.push(
|
||||||
false,
|
db.create_user(
|
||||||
NewUserParams {
|
&format!("user{i}@example.com"),
|
||||||
github_login: "u1".into(),
|
false,
|
||||||
github_user_id: 1,
|
NewUserParams {
|
||||||
invite_count: 0,
|
github_login: format!("user{i}"),
|
||||||
},
|
github_user_id: i,
|
||||||
)
|
invite_count: 0,
|
||||||
.await
|
},
|
||||||
.unwrap();
|
)
|
||||||
let user2 = db
|
.await
|
||||||
.create_user(
|
.unwrap()
|
||||||
"u2@example.com",
|
.user_id,
|
||||||
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(user_ids.clone()).await.unwrap(),
|
||||||
.await
|
|
||||||
.unwrap(),
|
|
||||||
vec![
|
vec![
|
||||||
User {
|
User {
|
||||||
id: user1,
|
id: user_ids[0],
|
||||||
github_login: "u1".to_string(),
|
github_login: "user1".to_string(),
|
||||||
github_user_id: Some(1),
|
github_user_id: Some(1),
|
||||||
email_address: Some("u1@example.com".to_string()),
|
email_address: Some("user1@example.com".to_string()),
|
||||||
admin: false,
|
admin: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
User {
|
User {
|
||||||
id: user2,
|
id: user_ids[1],
|
||||||
github_login: "u2".to_string(),
|
github_login: "user2".to_string(),
|
||||||
github_user_id: Some(2),
|
github_user_id: Some(2),
|
||||||
email_address: Some("u2@example.com".to_string()),
|
email_address: Some("user2@example.com".to_string()),
|
||||||
admin: false,
|
admin: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
User {
|
User {
|
||||||
id: user3,
|
id: user_ids[2],
|
||||||
github_login: "u3".to_string(),
|
github_login: "user3".to_string(),
|
||||||
github_user_id: Some(3),
|
github_user_id: Some(3),
|
||||||
email_address: Some("u3@example.com".to_string()),
|
email_address: Some("user3@example.com".to_string()),
|
||||||
admin: false,
|
admin: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
User {
|
User {
|
||||||
id: user4,
|
id: user_ids[3],
|
||||||
github_login: "u4".to_string(),
|
github_login: "user4".to_string(),
|
||||||
github_user_id: Some(4),
|
github_user_id: Some(4),
|
||||||
email_address: Some("u4@example.com".to_string()),
|
email_address: Some("user4@example.com".to_string()),
|
||||||
admin: false,
|
admin: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
@ -121,7 +88,8 @@ async fn test_get_user_by_github_account() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
let user_id2 = db
|
let user_id2 = db
|
||||||
.create_user(
|
.create_user(
|
||||||
"user2@example.com",
|
"user2@example.com",
|
||||||
|
@ -133,7 +101,8 @@ async fn test_get_user_by_github_account() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
|
|
||||||
let user = db
|
let user = db
|
||||||
.get_user_by_github_account("login1", None)
|
.get_user_by_github_account("login1", None)
|
||||||
|
@ -177,7 +146,8 @@ async fn test_worktree_extensions() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
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())
|
||||||
|
@ -237,43 +207,25 @@ 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
|
let mut user_ids = Vec::new();
|
||||||
.create_user(
|
for i in 0..=2 {
|
||||||
"u1@example.com",
|
user_ids.push(
|
||||||
false,
|
db.create_user(
|
||||||
NewUserParams {
|
&format!("user{i}@example.com"),
|
||||||
github_login: "u1".into(),
|
false,
|
||||||
github_user_id: 0,
|
NewUserParams {
|
||||||
invite_count: 0,
|
github_login: format!("user{i}"),
|
||||||
},
|
github_user_id: i,
|
||||||
)
|
invite_count: 0,
|
||||||
.await
|
},
|
||||||
.unwrap();
|
)
|
||||||
let user_2 = db
|
.await
|
||||||
.create_user(
|
.unwrap()
|
||||||
"u2@example.com",
|
.user_id,
|
||||||
false,
|
);
|
||||||
NewUserParams {
|
}
|
||||||
github_login: "u2".into(),
|
|
||||||
github_user_id: 0,
|
let project_1 = db.register_project(user_ids[0]).await.unwrap();
|
||||||
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();
|
|
||||||
db.update_worktree_extensions(
|
db.update_worktree_extensions(
|
||||||
project_1,
|
project_1,
|
||||||
1,
|
1,
|
||||||
|
@ -281,34 +233,37 @@ async fn test_user_activity() {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let project_2 = db.register_project(user_2).await.unwrap();
|
let project_2 = db.register_project(user_ids[1]).await.unwrap();
|
||||||
let t0 = OffsetDateTime::now_utc() - Duration::from_secs(60 * 60);
|
let t0 = OffsetDateTime::now_utc() - Duration::from_secs(60 * 60);
|
||||||
|
|
||||||
// User 2 opens a project
|
// User 2 opens a project
|
||||||
let t1 = t0 + Duration::from_secs(10);
|
let t1 = t0 + Duration::from_secs(10);
|
||||||
db.record_user_activity(t0..t1, &[(user_2, project_2)])
|
db.record_user_activity(t0..t1, &[(user_ids[1], project_2)])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t2 = t1 + Duration::from_secs(10);
|
let t2 = t1 + Duration::from_secs(10);
|
||||||
db.record_user_activity(t1..t2, &[(user_2, project_2)])
|
db.record_user_activity(t1..t2, &[(user_ids[1], project_2)])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// User 1 joins the project
|
// User 1 joins the project
|
||||||
let t3 = t2 + Duration::from_secs(10);
|
let t3 = t2 + Duration::from_secs(10);
|
||||||
db.record_user_activity(t2..t3, &[(user_2, project_2), (user_1, project_2)])
|
db.record_user_activity(
|
||||||
.await
|
t2..t3,
|
||||||
.unwrap();
|
&[(user_ids[1], project_2), (user_ids[0], project_2)],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// User 1 opens another project
|
// User 1 opens another project
|
||||||
let t4 = t3 + Duration::from_secs(10);
|
let t4 = t3 + Duration::from_secs(10);
|
||||||
db.record_user_activity(
|
db.record_user_activity(
|
||||||
t3..t4,
|
t3..t4,
|
||||||
&[
|
&[
|
||||||
(user_2, project_2),
|
(user_ids[1], project_2),
|
||||||
(user_1, project_2),
|
(user_ids[0], project_2),
|
||||||
(user_1, project_1),
|
(user_ids[0], project_1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -319,10 +274,10 @@ async fn test_user_activity() {
|
||||||
db.record_user_activity(
|
db.record_user_activity(
|
||||||
t4..t5,
|
t4..t5,
|
||||||
&[
|
&[
|
||||||
(user_2, project_2),
|
(user_ids[1], project_2),
|
||||||
(user_1, project_2),
|
(user_ids[0], project_2),
|
||||||
(user_1, project_1),
|
(user_ids[0], project_1),
|
||||||
(user_3, project_1),
|
(user_ids[2], project_1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -330,13 +285,16 @@ async fn test_user_activity() {
|
||||||
|
|
||||||
// User 2 leaves
|
// User 2 leaves
|
||||||
let t6 = t5 + Duration::from_secs(5);
|
let t6 = t5 + Duration::from_secs(5);
|
||||||
db.record_user_activity(t5..t6, &[(user_1, project_1), (user_3, project_1)])
|
db.record_user_activity(
|
||||||
.await
|
t5..t6,
|
||||||
.unwrap();
|
&[(user_ids[0], project_1), (user_ids[2], project_1)],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let t7 = t6 + Duration::from_secs(60);
|
let t7 = t6 + Duration::from_secs(60);
|
||||||
let t8 = t7 + Duration::from_secs(10);
|
let t8 = t7 + Duration::from_secs(10);
|
||||||
db.record_user_activity(t7..t8, &[(user_1, project_1)])
|
db.record_user_activity(t7..t8, &[(user_ids[0], project_1)])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -344,8 +302,8 @@ async fn test_user_activity() {
|
||||||
db.get_top_users_activity_summary(t0..t6, 10).await.unwrap(),
|
db.get_top_users_activity_summary(t0..t6, 10).await.unwrap(),
|
||||||
&[
|
&[
|
||||||
UserActivitySummary {
|
UserActivitySummary {
|
||||||
id: user_1,
|
id: user_ids[0],
|
||||||
github_login: "u1".to_string(),
|
github_login: "user0".to_string(),
|
||||||
project_activity: vec![
|
project_activity: vec![
|
||||||
ProjectActivitySummary {
|
ProjectActivitySummary {
|
||||||
id: project_1,
|
id: project_1,
|
||||||
|
@ -360,8 +318,8 @@ async fn test_user_activity() {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
UserActivitySummary {
|
UserActivitySummary {
|
||||||
id: user_2,
|
id: user_ids[1],
|
||||||
github_login: "u2".to_string(),
|
github_login: "user1".to_string(),
|
||||||
project_activity: vec![ProjectActivitySummary {
|
project_activity: vec![ProjectActivitySummary {
|
||||||
id: project_2,
|
id: project_2,
|
||||||
duration: Duration::from_secs(50),
|
duration: Duration::from_secs(50),
|
||||||
|
@ -369,8 +327,8 @@ async fn test_user_activity() {
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
UserActivitySummary {
|
UserActivitySummary {
|
||||||
id: user_3,
|
id: user_ids[2],
|
||||||
github_login: "u3".to_string(),
|
github_login: "user2".to_string(),
|
||||||
project_activity: vec![ProjectActivitySummary {
|
project_activity: vec![ProjectActivitySummary {
|
||||||
id: project_1,
|
id: project_1,
|
||||||
duration: Duration::from_secs(15),
|
duration: Duration::from_secs(15),
|
||||||
|
@ -442,7 +400,9 @@ async fn test_user_activity() {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_user_activity_timeline(t3..t6, user_1).await.unwrap(),
|
db.get_user_activity_timeline(t3..t6, user_ids[0])
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
&[
|
&[
|
||||||
UserActivityPeriod {
|
UserActivityPeriod {
|
||||||
project_id: project_1,
|
project_id: project_1,
|
||||||
|
@ -459,7 +419,9 @@ async fn test_user_activity() {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_user_activity_timeline(t0..t8, user_1).await.unwrap(),
|
db.get_user_activity_timeline(t0..t8, user_ids[0])
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
&[
|
&[
|
||||||
UserActivityPeriod {
|
UserActivityPeriod {
|
||||||
project_id: project_2,
|
project_id: project_2,
|
||||||
|
@ -501,7 +463,8 @@ async fn test_recent_channel_messages() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
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 {
|
||||||
|
@ -545,7 +508,8 @@ async fn test_channel_message_nonces() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
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();
|
||||||
|
|
||||||
|
@ -587,7 +551,8 @@ async fn test_create_access_tokens() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
|
|
||||||
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();
|
||||||
|
@ -678,42 +643,27 @@ async fn test_add_contacts() {
|
||||||
] {
|
] {
|
||||||
let db = test_db.db();
|
let db = test_db.db();
|
||||||
|
|
||||||
let user_1 = db
|
let mut user_ids = Vec::new();
|
||||||
.create_user(
|
for i in 0..3 {
|
||||||
"u1@example.com",
|
user_ids.push(
|
||||||
false,
|
db.create_user(
|
||||||
NewUserParams {
|
&format!("user{i}@example.com"),
|
||||||
github_login: "u1".into(),
|
false,
|
||||||
github_user_id: 0,
|
NewUserParams {
|
||||||
invite_count: 0,
|
github_login: format!("user{i}"),
|
||||||
},
|
github_user_id: i,
|
||||||
)
|
invite_count: 0,
|
||||||
.await
|
},
|
||||||
.unwrap();
|
)
|
||||||
let user_2 = db
|
.await
|
||||||
.create_user(
|
.unwrap()
|
||||||
"u2@example.com",
|
.user_id,
|
||||||
false,
|
);
|
||||||
NewUserParams {
|
}
|
||||||
github_login: "u2".into(),
|
|
||||||
github_user_id: 1,
|
let user_1 = user_ids[0];
|
||||||
invite_count: 0,
|
let user_2 = user_ids[1];
|
||||||
},
|
let user_3 = user_ids[2];
|
||||||
)
|
|
||||||
.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!(
|
||||||
|
@ -927,12 +877,12 @@ 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
|
let NewUserResult { user_id: user1, .. } = db
|
||||||
.create_user(
|
.create_user(
|
||||||
"u1@example.com",
|
"user1@example.com",
|
||||||
false,
|
false,
|
||||||
NewUserParams {
|
NewUserParams {
|
||||||
github_login: "u1".into(),
|
github_login: "user1".into(),
|
||||||
github_user_id: 0,
|
github_user_id: 0,
|
||||||
invite_count: 0,
|
invite_count: 0,
|
||||||
},
|
},
|
||||||
|
@ -954,13 +904,14 @@ async fn test_invite_codes() {
|
||||||
|
|
||||||
// User 2 redeems the invite code and becomes a contact of user 1.
|
// User 2 redeems the invite code and becomes a contact of user 1.
|
||||||
let user2_invite = db
|
let user2_invite = db
|
||||||
.create_invite_from_code(&invite_code, "u2@example.com", Some("user-2-device-id"))
|
.create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let NewUserResult {
|
let NewUserResult {
|
||||||
user_id: user2,
|
user_id: user2,
|
||||||
inviting_user_id,
|
inviting_user_id,
|
||||||
signup_device_id,
|
signup_device_id,
|
||||||
|
metrics_id,
|
||||||
} = db
|
} = db
|
||||||
.create_user_from_invite(
|
.create_user_from_invite(
|
||||||
&user2_invite,
|
&user2_invite,
|
||||||
|
@ -976,6 +927,7 @@ async fn test_invite_codes() {
|
||||||
assert_eq!(invite_count, 1);
|
assert_eq!(invite_count, 1);
|
||||||
assert_eq!(inviting_user_id, Some(user1));
|
assert_eq!(inviting_user_id, Some(user1));
|
||||||
assert_eq!(signup_device_id.unwrap(), "user-2-device-id");
|
assert_eq!(signup_device_id.unwrap(), "user-2-device-id");
|
||||||
|
assert_eq!(db.get_user_metrics_id(user2).await.unwrap(), metrics_id);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.get_contacts(user1).await.unwrap(),
|
db.get_contacts(user1).await.unwrap(),
|
||||||
[
|
[
|
||||||
|
@ -1009,13 +961,14 @@ async fn test_invite_codes() {
|
||||||
|
|
||||||
// User 3 redeems the invite code and becomes a contact of user 1.
|
// User 3 redeems the invite code and becomes a contact of user 1.
|
||||||
let user3_invite = db
|
let user3_invite = db
|
||||||
.create_invite_from_code(&invite_code, "u3@example.com", None)
|
.create_invite_from_code(&invite_code, "user3@example.com", None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let NewUserResult {
|
let NewUserResult {
|
||||||
user_id: user3,
|
user_id: user3,
|
||||||
inviting_user_id,
|
inviting_user_id,
|
||||||
signup_device_id,
|
signup_device_id,
|
||||||
|
..
|
||||||
} = db
|
} = db
|
||||||
.create_user_from_invite(
|
.create_user_from_invite(
|
||||||
&user3_invite,
|
&user3_invite,
|
||||||
|
@ -1067,7 +1020,7 @@ async fn test_invite_codes() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Trying to reedem the code for the third time results in an error.
|
// Trying to reedem the code for the third time results in an error.
|
||||||
db.create_invite_from_code(&invite_code, "u4@example.com", Some("user-4-device-id"))
|
db.create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
|
@ -1079,7 +1032,7 @@ async fn test_invite_codes() {
|
||||||
|
|
||||||
// User 4 can now redeem the invite code and becomes a contact of user 1.
|
// User 4 can now redeem the invite code and becomes a contact of user 1.
|
||||||
let user4_invite = db
|
let user4_invite = db
|
||||||
.create_invite_from_code(&invite_code, "u4@example.com", Some("user-4-device-id"))
|
.create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let user4 = db
|
let user4 = db
|
||||||
|
@ -1137,7 +1090,7 @@ async fn test_invite_codes() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// An existing user cannot redeem invite codes.
|
// An existing user cannot redeem invite codes.
|
||||||
db.create_invite_from_code(&invite_code, "u2@example.com", Some("user-2-device-id"))
|
db.create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
let (_, invite_count) = db.get_invite_code_for_user(user1).await.unwrap().unwrap();
|
let (_, invite_count) = db.get_invite_code_for_user(user1).await.unwrap().unwrap();
|
||||||
|
@ -1232,6 +1185,7 @@ async fn test_signups() {
|
||||||
user_id,
|
user_id,
|
||||||
inviting_user_id,
|
inviting_user_id,
|
||||||
signup_device_id,
|
signup_device_id,
|
||||||
|
..
|
||||||
} = db
|
} = db
|
||||||
.create_user_from_invite(
|
.create_user_from_invite(
|
||||||
&Invite {
|
&Invite {
|
||||||
|
@ -1284,6 +1238,51 @@ async fn test_signups() {
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn test_metrics_id() {
|
||||||
|
let postgres = TestDb::postgres().await;
|
||||||
|
let db = postgres.db();
|
||||||
|
|
||||||
|
let NewUserResult {
|
||||||
|
user_id: user1,
|
||||||
|
metrics_id: metrics_id1,
|
||||||
|
..
|
||||||
|
} = db
|
||||||
|
.create_user(
|
||||||
|
"person1@example.com",
|
||||||
|
false,
|
||||||
|
NewUserParams {
|
||||||
|
github_login: "person1".into(),
|
||||||
|
github_user_id: 101,
|
||||||
|
invite_count: 5,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let NewUserResult {
|
||||||
|
user_id: user2,
|
||||||
|
metrics_id: metrics_id2,
|
||||||
|
..
|
||||||
|
} = db
|
||||||
|
.create_user(
|
||||||
|
"person2@example.com",
|
||||||
|
false,
|
||||||
|
NewUserParams {
|
||||||
|
github_login: "person2".into(),
|
||||||
|
github_user_id: 102,
|
||||||
|
invite_count: 5,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(db.get_user_metrics_id(user1).await.unwrap(), metrics_id1);
|
||||||
|
assert_eq!(db.get_user_metrics_id(user2).await.unwrap(), metrics_id2);
|
||||||
|
assert_eq!(metrics_id1.len(), 36);
|
||||||
|
assert_eq!(metrics_id2.len(), 36);
|
||||||
|
assert_ne!(metrics_id1, metrics_id2);
|
||||||
|
}
|
||||||
|
|
||||||
fn build_background_executor() -> Arc<Background> {
|
fn build_background_executor() -> Arc<Background> {
|
||||||
Deterministic::new(0).build_background()
|
Deterministic::new(0).build_background()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4663,7 +4663,8 @@ async fn test_random_collaboration(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
let mut available_guests = vec![
|
let mut available_guests = vec![
|
||||||
"guest-1".to_string(),
|
"guest-1".to_string(),
|
||||||
"guest-2".to_string(),
|
"guest-2".to_string(),
|
||||||
|
@ -4683,7 +4684,8 @@ async fn test_random_collaboration(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
.user_id;
|
||||||
assert_eq!(*username, format!("guest-{}", guest_user_id));
|
assert_eq!(*username, format!("guest-{}", guest_user_id));
|
||||||
server
|
server
|
||||||
.app_state
|
.app_state
|
||||||
|
@ -5206,6 +5208,7 @@ impl TestServer {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.user_id
|
||||||
};
|
};
|
||||||
let client_name = name.to_string();
|
let client_name = name.to_string();
|
||||||
let mut client = cx.read(|cx| Client::new(http.clone(), cx));
|
let mut client = cx.read(|cx| Client::new(http.clone(), cx));
|
||||||
|
|
|
@ -205,7 +205,8 @@ impl Server {
|
||||||
.add_request_handler(Server::follow)
|
.add_request_handler(Server::follow)
|
||||||
.add_message_handler(Server::unfollow)
|
.add_message_handler(Server::unfollow)
|
||||||
.add_message_handler(Server::update_followers)
|
.add_message_handler(Server::update_followers)
|
||||||
.add_request_handler(Server::get_channel_messages);
|
.add_request_handler(Server::get_channel_messages)
|
||||||
|
.add_request_handler(Server::get_private_user_info);
|
||||||
|
|
||||||
Arc::new(server)
|
Arc::new(server)
|
||||||
}
|
}
|
||||||
|
@ -1727,6 +1728,20 @@ impl Server {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_private_user_info(
|
||||||
|
self: Arc<Self>,
|
||||||
|
request: TypedEnvelope<proto::GetPrivateUserInfo>,
|
||||||
|
response: Response<proto::GetPrivateUserInfo>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let user_id = self
|
||||||
|
.store()
|
||||||
|
.await
|
||||||
|
.user_id_for_connection(request.sender_id)?;
|
||||||
|
let metrics_id = self.app_state.db.get_user_metrics_id(user_id).await?;
|
||||||
|
response.send(proto::GetPrivateUserInfoResponse { metrics_id })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn store(&self) -> StoreGuard<'_> {
|
pub(crate) async fn store(&self) -> StoreGuard<'_> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
tokio::task::yield_now().await;
|
tokio::task::yield_now().await;
|
||||||
|
|
|
@ -108,6 +108,9 @@ message Envelope {
|
||||||
FollowResponse follow_response = 93;
|
FollowResponse follow_response = 93;
|
||||||
UpdateFollowers update_followers = 94;
|
UpdateFollowers update_followers = 94;
|
||||||
Unfollow unfollow = 95;
|
Unfollow unfollow = 95;
|
||||||
|
|
||||||
|
GetPrivateUserInfo get_private_user_info = 96;
|
||||||
|
GetPrivateUserInfoResponse get_private_user_info_response = 97;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,6 +751,12 @@ message Unfollow {
|
||||||
uint32 leader_id = 2;
|
uint32 leader_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetPrivateUserInfo {}
|
||||||
|
|
||||||
|
message GetPrivateUserInfoResponse {
|
||||||
|
string metrics_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Entities
|
// Entities
|
||||||
|
|
||||||
message UpdateActiveView {
|
message UpdateActiveView {
|
||||||
|
|
|
@ -167,6 +167,8 @@ messages!(
|
||||||
(UpdateProject, Foreground),
|
(UpdateProject, Foreground),
|
||||||
(UpdateWorktree, Foreground),
|
(UpdateWorktree, Foreground),
|
||||||
(UpdateWorktreeExtensions, Background),
|
(UpdateWorktreeExtensions, Background),
|
||||||
|
(GetPrivateUserInfo, Foreground),
|
||||||
|
(GetPrivateUserInfoResponse, Foreground),
|
||||||
);
|
);
|
||||||
|
|
||||||
request_messages!(
|
request_messages!(
|
||||||
|
@ -189,6 +191,7 @@ request_messages!(
|
||||||
(GetTypeDefinition, GetTypeDefinitionResponse),
|
(GetTypeDefinition, GetTypeDefinitionResponse),
|
||||||
(GetDocumentHighlights, GetDocumentHighlightsResponse),
|
(GetDocumentHighlights, GetDocumentHighlightsResponse),
|
||||||
(GetReferences, GetReferencesResponse),
|
(GetReferences, GetReferencesResponse),
|
||||||
|
(GetPrivateUserInfo, GetPrivateUserInfoResponse),
|
||||||
(GetProjectSymbols, GetProjectSymbolsResponse),
|
(GetProjectSymbols, GetProjectSymbolsResponse),
|
||||||
(FuzzySearchUsers, UsersResponse),
|
(FuzzySearchUsers, UsersResponse),
|
||||||
(GetUsers, UsersResponse),
|
(GetUsers, UsersResponse),
|
||||||
|
|
Loading…
Reference in a new issue