collab: Add GET /users/look_up
endpoint (#31059)
This PR adds a new `GET /users/look_up` endpoint for retrieving users by various identifiers. This endpoint can look up users by the following identifiers: - Zed user ID - Stripe Customer ID - Stripe Subscription ID - Email address - GitHub login Release Notes: - N/A
This commit is contained in:
parent
3b1f6eaab8
commit
3ee56c196c
2 changed files with 96 additions and 0 deletions
|
@ -5,6 +5,7 @@ pub mod extensions;
|
||||||
pub mod ips_file;
|
pub mod ips_file;
|
||||||
pub mod slack;
|
pub mod slack;
|
||||||
|
|
||||||
|
use crate::db::Database;
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState, Error, Result, auth,
|
AppState, Error, Result, auth,
|
||||||
db::{User, UserId},
|
db::{User, UserId},
|
||||||
|
@ -97,6 +98,7 @@ impl std::fmt::Display for SystemIdHeader {
|
||||||
pub fn routes(rpc_server: Arc<rpc::Server>) -> Router<(), Body> {
|
pub fn routes(rpc_server: Arc<rpc::Server>) -> Router<(), Body> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/user", get(get_authenticated_user))
|
.route("/user", get(get_authenticated_user))
|
||||||
|
.route("/users/look_up", get(look_up_user))
|
||||||
.route("/users/:id/access_tokens", post(create_access_token))
|
.route("/users/:id/access_tokens", post(create_access_token))
|
||||||
.route("/rpc_server_snapshot", get(get_rpc_server_snapshot))
|
.route("/rpc_server_snapshot", get(get_rpc_server_snapshot))
|
||||||
.merge(billing::router())
|
.merge(billing::router())
|
||||||
|
@ -181,6 +183,87 @@ async fn get_authenticated_user(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct LookUpUserParams {
|
||||||
|
identifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct LookUpUserResponse {
|
||||||
|
user: Option<User>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn look_up_user(
|
||||||
|
Query(params): Query<LookUpUserParams>,
|
||||||
|
Extension(app): Extension<Arc<AppState>>,
|
||||||
|
) -> Result<Json<LookUpUserResponse>> {
|
||||||
|
let user = resolve_identifier_to_user(&app.db, ¶ms.identifier).await?;
|
||||||
|
let user = if let Some(user) = user {
|
||||||
|
match user {
|
||||||
|
UserOrId::User(user) => Some(user),
|
||||||
|
UserOrId::Id(id) => app.db.get_user_by_id(id).await?,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Json(LookUpUserResponse { user }))
|
||||||
|
}
|
||||||
|
|
||||||
|
enum UserOrId {
|
||||||
|
User(User),
|
||||||
|
Id(UserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn resolve_identifier_to_user(
|
||||||
|
db: &Arc<Database>,
|
||||||
|
identifier: &str,
|
||||||
|
) -> Result<Option<UserOrId>> {
|
||||||
|
if let Some(identifier) = identifier.parse::<i32>().ok() {
|
||||||
|
let user = db.get_user_by_id(UserId(identifier)).await?;
|
||||||
|
|
||||||
|
return Ok(user.map(UserOrId::User));
|
||||||
|
}
|
||||||
|
|
||||||
|
if identifier.starts_with("cus_") {
|
||||||
|
let billing_customer = db
|
||||||
|
.get_billing_customer_by_stripe_customer_id(&identifier)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
return Ok(billing_customer.map(|billing_customer| UserOrId::Id(billing_customer.user_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if identifier.starts_with("sub_") {
|
||||||
|
let billing_subscription = db
|
||||||
|
.get_billing_subscription_by_stripe_subscription_id(&identifier)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(billing_subscription) = billing_subscription {
|
||||||
|
let billing_customer = db
|
||||||
|
.get_billing_customer_by_id(billing_subscription.billing_customer_id)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
billing_customer.map(|billing_customer| UserOrId::Id(billing_customer.user_id))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if identifier.contains('@') {
|
||||||
|
let user = db.get_user_by_email(identifier).await?;
|
||||||
|
|
||||||
|
return Ok(user.map(UserOrId::User));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(user) = db.get_user_by_github_login(identifier).await? {
|
||||||
|
return Ok(Some(UserOrId::User(user)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct CreateUserParams {
|
struct CreateUserParams {
|
||||||
github_user_id: i32,
|
github_user_id: i32,
|
||||||
|
|
|
@ -57,6 +57,19 @@ impl Database {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_billing_customer_by_id(
|
||||||
|
&self,
|
||||||
|
id: BillingCustomerId,
|
||||||
|
) -> Result<Option<billing_customer::Model>> {
|
||||||
|
self.transaction(|tx| async move {
|
||||||
|
Ok(billing_customer::Entity::find()
|
||||||
|
.filter(billing_customer::Column::Id.eq(id))
|
||||||
|
.one(&*tx)
|
||||||
|
.await?)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the billing customer for the user with the specified ID.
|
/// Returns the billing customer for the user with the specified ID.
|
||||||
pub async fn get_billing_customer_by_user_id(
|
pub async fn get_billing_customer_by_user_id(
|
||||||
&self,
|
&self,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue