This commit is contained in:
2025-10-27 11:32:22 +01:00
parent 84a3a9a5b5
commit 82aa8948cf
7 changed files with 180 additions and 22 deletions
+8 -1
View File
@@ -539,6 +539,7 @@ pub mod schemas {
pub access_token: String,
pub token_type: String,
pub expires_in: i64,
pub tenant: TenantSnippet,
}
#[derive(Serialize, Deserialize, ToSchema)]
@@ -547,9 +548,15 @@ pub mod schemas {
pub slug: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct TenantSnippet {
pub id: Uuid,
pub slug: String,
}
#[derive(Serialize, Deserialize, ToSchema)]
pub struct TenantSelectionResponse {
pub selection_token: String,
pub access_token: String,
pub tenants: Vec<TenantSummary>,
}
+56 -2
View File
@@ -43,6 +43,7 @@ pub struct LoginResponse {
pub access_token: String,
pub token_type: String,
pub expires_in: i64,
pub tenant: TenantSnippet,
}
#[derive(Serialize)]
@@ -51,12 +52,23 @@ pub struct TenantSummary {
pub slug: String,
}
#[derive(Serialize)]
pub struct TenantSnippet {
pub id: Uuid,
pub slug: String,
}
#[derive(Serialize)]
pub struct TenantSelectionResponse {
pub selection_token: String,
pub access_token: String,
pub tenants: Vec<TenantSummary>,
}
#[derive(Serialize)]
pub struct TenantListResponse {
pub tenants: Vec<TenantSnippet>,
}
#[derive(Deserialize)]
pub struct TenantSelectionRequest {
pub tenant_id: Uuid,
@@ -121,7 +133,7 @@ pub async fn login(
.collect();
let response = Json(TenantSelectionResponse {
selection_token,
access_token: selection_token,
tenants,
})
.into_response();
@@ -250,6 +262,38 @@ pub async fn me(user: AuthenticatedUser) -> Json<AuthenticatedUser> {
Json(user)
}
pub async fn list_tenants(
State(state): State<AppState>,
auth: Option<TypedHeader<Authorization<Bearer>>>,
) -> AppResult<Json<TenantListResponse>> {
let bearer = auth.ok_or_else(AppError::unauthorized)?;
let token = bearer.token();
let user_id = match state.jwt.verify_token(token) {
Ok(claims) => claims.sub,
Err(_) => {
let claims = state
.jwt
.verify_tenant_selector_token(token)
.map_err(|_| AppError::unauthorized())?;
claims.sub
}
};
let mut conn = state.db_unscoped()?;
let tenants = memberships_dsl::user_memberships
.inner_join(tenant_dsl::tenants)
.filter(memberships_dsl::user_id.eq(user_id))
.select((tenant_dsl::id, tenant_dsl::slug))
.load::<(Uuid, String)>(&mut conn)?
.into_iter()
.map(|(id, slug)| TenantSnippet { id, slug })
.collect();
Ok(Json(TenantListResponse { tenants }))
}
fn issue_session(
state: &AppState,
conn: &mut PgConnection,
@@ -262,6 +306,12 @@ fn issue_session(
.generate_token(user.id, tenant_id, &user.username)
.map_err(AppError::from)?;
let tenant_slug: String = tenant_dsl::tenants
.find(tenant_id)
.select(tenant_dsl::slug)
.first(conn)
.map_err(AppError::from)?;
let refresh_value = generate_refresh_token();
let refresh_hash = hash_refresh_token(&refresh_value);
let refresh_expires_at = now + ChronoDuration::days(state.config.refresh_token_expiry_days);
@@ -283,6 +333,10 @@ fn issue_session(
access_token,
token_type: "Bearer".to_string(),
expires_in: state.config.jwt_expiry_minutes * 60,
tenant: TenantSnippet {
id: tenant_id,
slug: tenant_slug,
},
})
.into_response();
+1 -4
View File
@@ -411,10 +411,7 @@ pub async fn list_documents(
.filter(|s| !s.is_empty())
.map(|s| s.to_owned());
let mut include_descendants = include_descendants.unwrap_or_else(|| folder_id.is_some());
if search_text.is_some() || tags_param.is_some() || correspondents_param.is_some() {
include_descendants = true;
}
let include_descendants = include_descendants.unwrap_or(true);
match (folder_id, include_descendants) {
(Some(folder_id), true) => {
+1
View File
@@ -54,6 +54,7 @@ pub fn create_router(state: AppState) -> Router<()> {
.route("/refresh", post(auth::refresh))
.route("/logout", post(auth::logout))
.route("/select-tenant", post(auth::select_tenant))
.route("/tenants", get(auth::list_tenants))
.route("/me", get(auth::me));
let documents_routes = Router::new()
+2 -2
View File
@@ -328,7 +328,7 @@ impl TestApp {
#[derive(Deserialize)]
struct TenantSelectionResponse {
selection_token: String,
access_token: String,
tenants: Vec<TenantSummary>,
}
@@ -350,7 +350,7 @@ impl TestApp {
&SelectTenantPayload {
tenant_id: target_tenant,
},
Some(&selection.selection_token),
Some(&selection.access_token),
)
.await?;