linting, tenant slug -> name
This commit is contained in:
+76
-76
@@ -39,23 +39,23 @@ enum Command {
|
||||
username: String,
|
||||
},
|
||||
CreateTenant {
|
||||
slug: String,
|
||||
name: String,
|
||||
storage_root: Option<String>,
|
||||
quickwit_index: Option<String>,
|
||||
},
|
||||
DeleteTenant {
|
||||
slug: String,
|
||||
name: String,
|
||||
},
|
||||
AddUserToTenant {
|
||||
username: String,
|
||||
slug: String,
|
||||
name: String,
|
||||
},
|
||||
RemoveUserFromTenant {
|
||||
username: String,
|
||||
slug: String,
|
||||
name: String,
|
||||
},
|
||||
ReanalyzeDocuments {
|
||||
slug: String,
|
||||
name: String,
|
||||
},
|
||||
ListTenants,
|
||||
DeleteAssets(String),
|
||||
@@ -70,15 +70,15 @@ impl Command {
|
||||
set-password <username> <password>\n\
|
||||
list-users\n\
|
||||
delete-user <username>\n\
|
||||
create-tenant <slug> [storage_root] [quickwit_index]\n\
|
||||
delete-tenant <slug>\n\
|
||||
add-user-to-tenant <username> <slug>\n\
|
||||
remove-user-from-tenant <username> <slug>\n\
|
||||
reanalyze-documents <slug>\n\
|
||||
create-tenant <name> [storage_root] [quickwit_index]\n\
|
||||
delete-tenant <name>\n\
|
||||
add-user-to-tenant <username> <name>\n\
|
||||
remove-user-from-tenant <username> <name>\n\
|
||||
reanalyze-documents <name>\n\
|
||||
list-tenants\n\
|
||||
delete-assets <slug>\n\
|
||||
quickwit-create-index <slug>\n\
|
||||
quickwit-delete-index <slug>"
|
||||
delete-assets <name>\n\
|
||||
quickwit-create-index <name>\n\
|
||||
quickwit-delete-index <name>"
|
||||
}
|
||||
|
||||
fn parse() -> Result<Self> {
|
||||
@@ -97,33 +97,33 @@ impl Command {
|
||||
username: args.next().ok_or_else(|| anyhow!("username required"))?,
|
||||
}),
|
||||
Some("create-tenant") => Ok(Self::CreateTenant {
|
||||
slug: args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
name: args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
storage_root: args.next(),
|
||||
quickwit_index: args.next(),
|
||||
}),
|
||||
Some("delete-tenant") => Ok(Self::DeleteTenant {
|
||||
slug: args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
name: args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
}),
|
||||
Some("add-user-to-tenant") => Ok(Self::AddUserToTenant {
|
||||
username: args.next().ok_or_else(|| anyhow!("username required"))?,
|
||||
slug: args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
name: args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
}),
|
||||
Some("remove-user-from-tenant") => Ok(Self::RemoveUserFromTenant {
|
||||
username: args.next().ok_or_else(|| anyhow!("username required"))?,
|
||||
slug: args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
name: args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
}),
|
||||
Some("reanalyze-documents") => Ok(Self::ReanalyzeDocuments {
|
||||
slug: args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
name: args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
}),
|
||||
Some("list-tenants") => Ok(Self::ListTenants),
|
||||
Some("delete-assets") => Ok(Self::DeleteAssets(
|
||||
args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
)),
|
||||
Some("quickwit-create-index") => Ok(Self::QuickwitCreate(
|
||||
args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
)),
|
||||
Some("quickwit-delete-index") => Ok(Self::QuickwitDelete(
|
||||
args.next().ok_or_else(|| anyhow!("tenant slug required"))?,
|
||||
args.next().ok_or_else(|| anyhow!("tenant name required"))?,
|
||||
)),
|
||||
_ => Err(anyhow!(Self::usage())),
|
||||
}
|
||||
@@ -143,23 +143,23 @@ async fn main() -> Result<()> {
|
||||
Command::ListUsers => list_users(&pool)?,
|
||||
Command::DeleteUser { username } => delete_user(&pool, &username)?,
|
||||
Command::CreateTenant {
|
||||
slug,
|
||||
name,
|
||||
storage_root,
|
||||
quickwit_index,
|
||||
} => create_tenant(&pool, &slug, storage_root, quickwit_index)?,
|
||||
Command::DeleteTenant { slug } => delete_tenant(&pool, &slug)?,
|
||||
Command::AddUserToTenant { username, slug } => add_user_to_tenant(&pool, &username, &slug)?,
|
||||
Command::RemoveUserFromTenant { username, slug } => {
|
||||
remove_user_from_tenant(&pool, &username, &slug)?
|
||||
} => create_tenant(&pool, &name, storage_root, quickwit_index)?,
|
||||
Command::DeleteTenant { name } => delete_tenant(&pool, &name)?,
|
||||
Command::AddUserToTenant { username, name } => add_user_to_tenant(&pool, &username, &name)?,
|
||||
Command::RemoveUserFromTenant { username, name } => {
|
||||
remove_user_from_tenant(&pool, &username, &name)?
|
||||
}
|
||||
Command::ReanalyzeDocuments { slug } => reanalyze_documents(&pool, &slug)?,
|
||||
Command::ReanalyzeDocuments { name } => reanalyze_documents(&pool, &name)?,
|
||||
Command::ListTenants => list_tenants(&pool)?,
|
||||
Command::DeleteAssets(slug) => delete_assets_for_tenant(&config, &pool, &slug).await?,
|
||||
Command::QuickwitCreate(slug) => {
|
||||
quickwit_index(&config, &pool, &slug, Method::POST).await?
|
||||
Command::DeleteAssets(name) => delete_assets_for_tenant(&config, &pool, &name).await?,
|
||||
Command::QuickwitCreate(name) => {
|
||||
quickwit_index(&config, &pool, &name, Method::POST).await?
|
||||
}
|
||||
Command::QuickwitDelete(slug) => {
|
||||
quickwit_index(&config, &pool, &slug, Method::DELETE).await?
|
||||
Command::QuickwitDelete(name) => {
|
||||
quickwit_index(&config, &pool, &name, Method::DELETE).await?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,8 +229,8 @@ fn list_users(pool: &PgPool) -> Result<()> {
|
||||
let memberships: Vec<String> = user_memberships::table
|
||||
.inner_join(tenants::table)
|
||||
.filter(user_memberships::user_id.eq(user.id))
|
||||
.select(tenants::slug)
|
||||
.order(tenants::slug.asc())
|
||||
.select(tenants::name)
|
||||
.order(tenants::name.asc())
|
||||
.load(&mut conn)?;
|
||||
|
||||
if memberships.is_empty() {
|
||||
@@ -267,14 +267,14 @@ fn delete_user(pool: &PgPool, username: &str) -> Result<()> {
|
||||
|
||||
fn create_tenant(
|
||||
pool: &PgPool,
|
||||
slug: &str,
|
||||
name: &str,
|
||||
storage_root_arg: Option<String>,
|
||||
quickwit_index_arg: Option<String>,
|
||||
) -> Result<()> {
|
||||
let service = TenantService::new(pool.clone());
|
||||
let tenant = service
|
||||
.create_tenant(
|
||||
slug,
|
||||
name,
|
||||
storage_root_arg.as_deref(),
|
||||
quickwit_index_arg.as_deref(),
|
||||
TenantStatus::Creating,
|
||||
@@ -288,7 +288,7 @@ fn create_tenant(
|
||||
|
||||
println!(
|
||||
"created tenant '{}' with id {}, storage_root '{}', quickwit_index '{}', status '{}'",
|
||||
tenant.slug,
|
||||
tenant.name,
|
||||
tenant.id,
|
||||
storage_root,
|
||||
quickwit_index,
|
||||
@@ -297,29 +297,29 @@ fn create_tenant(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_tenant(pool: &PgPool, slug: &str) -> Result<()> {
|
||||
fn delete_tenant(pool: &PgPool, name: &str) -> Result<()> {
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(slug))
|
||||
.filter(tenants::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", name))?;
|
||||
|
||||
let member_exists: bool = select(exists(
|
||||
user_memberships::table.filter(user_memberships::tenant_id.eq(tenant.id)),
|
||||
))
|
||||
.get_result(&mut conn)?;
|
||||
if member_exists {
|
||||
bail!("tenant '{}' still has user memberships", slug);
|
||||
bail!("tenant '{}' still has user memberships", name);
|
||||
}
|
||||
|
||||
diesel::delete(tenants::table.filter(tenants::id.eq(tenant.id))).execute(&mut conn)?;
|
||||
println!("deleted tenant '{}'", slug);
|
||||
println!("deleted tenant '{}'", name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_user_to_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<()> {
|
||||
fn add_user_to_tenant(pool: &PgPool, username: &str, name: &str) -> Result<()> {
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
|
||||
let user: User = users::table
|
||||
@@ -329,10 +329,10 @@ fn add_user_to_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<()> {
|
||||
.ok_or_else(|| anyhow!("user '{}' not found", username))?;
|
||||
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(slug))
|
||||
.filter(tenants::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", name))?;
|
||||
|
||||
let membership = NewUserMembership {
|
||||
id: Uuid::new_v4(),
|
||||
@@ -346,11 +346,11 @@ fn add_user_to_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<()> {
|
||||
.do_nothing()
|
||||
.execute(&mut conn)?;
|
||||
|
||||
println!("added user '{}' to tenant '{}'", username, slug);
|
||||
println!("added user '{}' to tenant '{}'", username, name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_user_from_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<()> {
|
||||
fn remove_user_from_tenant(pool: &PgPool, username: &str, name: &str) -> Result<()> {
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
|
||||
let user: User = users::table
|
||||
@@ -360,10 +360,10 @@ fn remove_user_from_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<
|
||||
.ok_or_else(|| anyhow!("user '{}' not found", username))?;
|
||||
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(slug))
|
||||
.filter(tenants::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", name))?;
|
||||
|
||||
let removed = diesel::delete(
|
||||
user_memberships::table
|
||||
@@ -373,21 +373,21 @@ fn remove_user_from_tenant(pool: &PgPool, username: &str, slug: &str) -> Result<
|
||||
.execute(&mut conn)?;
|
||||
|
||||
if removed == 0 {
|
||||
println!("user '{}' was not a member of tenant '{}'", username, slug);
|
||||
println!("user '{}' was not a member of tenant '{}'", username, name);
|
||||
} else {
|
||||
println!("removed user '{}' from tenant '{}'", username, slug);
|
||||
println!("removed user '{}' from tenant '{}'", username, name);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reanalyze_documents(pool: &PgPool, slug: &str) -> Result<()> {
|
||||
fn reanalyze_documents(pool: &PgPool, name: &str) -> Result<()> {
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(slug))
|
||||
.filter(tenants::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", name))?;
|
||||
|
||||
let targets: Vec<(Uuid, Uuid)> = documents::table
|
||||
.filter(documents::tenant_id.eq(tenant.id))
|
||||
@@ -396,7 +396,7 @@ fn reanalyze_documents(pool: &PgPool, slug: &str) -> Result<()> {
|
||||
.load(&mut conn)?;
|
||||
|
||||
if targets.is_empty() {
|
||||
println!("tenant '{}' has no active documents", slug);
|
||||
println!("tenant '{}' has no active documents", name);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ fn reanalyze_documents(pool: &PgPool, slug: &str) -> Result<()> {
|
||||
|
||||
println!(
|
||||
"queued {} documents for re-analysis in tenant '{}'",
|
||||
queued, slug
|
||||
queued, name
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -427,7 +427,7 @@ fn reanalyze_documents(pool: &PgPool, slug: &str) -> Result<()> {
|
||||
fn list_tenants(pool: &PgPool) -> Result<()> {
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
let tenants: Vec<Tenant> = tenants::table
|
||||
.order(tenants::slug.asc())
|
||||
.order(tenants::name.asc())
|
||||
.load(&mut conn)
|
||||
.context("failed to load tenants")?;
|
||||
|
||||
@@ -437,7 +437,7 @@ fn list_tenants(pool: &PgPool) -> Result<()> {
|
||||
}
|
||||
|
||||
for tenant in tenants {
|
||||
println!("{} ({})", tenant.slug, tenant.id);
|
||||
println!("{} ({})", tenant.name, tenant.id);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -446,7 +446,7 @@ fn list_tenants(pool: &PgPool) -> Result<()> {
|
||||
async fn delete_assets_for_tenant(
|
||||
config: &AppConfig,
|
||||
pool: &PgPool,
|
||||
tenant_slug: &str,
|
||||
tenant_name: &str,
|
||||
) -> Result<()> {
|
||||
let s3_client = s3::build_client(config).await?;
|
||||
let storage: Arc<dyn ObjectStorage> =
|
||||
@@ -454,28 +454,28 @@ async fn delete_assets_for_tenant(
|
||||
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(tenant_slug))
|
||||
.filter(tenants::name.eq(tenant_name))
|
||||
.first(&mut conn)
|
||||
.optional()
|
||||
.context("failed to load tenant")?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", tenant_slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", tenant_name))?;
|
||||
|
||||
let tenant_storage = TenantStorage::new(Arc::clone(&storage), &tenant)
|
||||
.with_context(|| format!("missing storage root for tenant {}", tenant.slug))?;
|
||||
.with_context(|| format!("missing storage root for tenant {}", tenant.name))?;
|
||||
|
||||
let assets: Vec<DocumentAsset> = document_assets::table
|
||||
.filter(document_assets::tenant_id.eq(tenant.id))
|
||||
.load(&mut conn)
|
||||
.with_context(|| format!("failed to load assets for tenant {}", tenant.slug))?;
|
||||
.with_context(|| format!("failed to load assets for tenant {}", tenant.name))?;
|
||||
|
||||
if assets.is_empty() {
|
||||
println!("Tenant {}: no assets", tenant.slug);
|
||||
println!("Tenant {}: no assets", tenant.name);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!(
|
||||
"Tenant {} ({}): deleting {} assets…",
|
||||
tenant.slug,
|
||||
tenant.name,
|
||||
tenant.id,
|
||||
assets.len()
|
||||
);
|
||||
@@ -486,13 +486,13 @@ async fn delete_assets_for_tenant(
|
||||
.filter(document_asset_objects::tenant_id.eq(tenant.id))
|
||||
.filter(document_asset_objects::asset_id.eq_any(&asset_ids))
|
||||
.load(&mut conn)
|
||||
.with_context(|| format!("failed to load asset objects for tenant {}", tenant.slug))?;
|
||||
.with_context(|| format!("failed to load asset objects for tenant {}", tenant.name))?;
|
||||
|
||||
for object in &objects {
|
||||
if let Err(err) = tenant_storage.delete_object(&object.s3_key).await {
|
||||
eprintln!(
|
||||
"Failed to delete object {} (tenant {}): {err}",
|
||||
object.s3_key, tenant.slug
|
||||
object.s3_key, tenant.name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -503,20 +503,20 @@ async fn delete_assets_for_tenant(
|
||||
.filter(document_asset_objects::asset_id.eq_any(&asset_ids)),
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.with_context(|| format!("failed to remove asset objects for tenant {}", tenant.slug))?;
|
||||
.with_context(|| format!("failed to remove asset objects for tenant {}", tenant.name))?;
|
||||
|
||||
diesel::delete(document_assets::table.filter(document_assets::tenant_id.eq(tenant.id)))
|
||||
.execute(&mut conn)
|
||||
.with_context(|| format!("failed to remove asset records for tenant {}", tenant.slug))?;
|
||||
.with_context(|| format!("failed to remove asset records for tenant {}", tenant.name))?;
|
||||
|
||||
println!("Tenant {}: asset records deleted.", tenant.slug);
|
||||
println!("Tenant {}: asset records deleted.", tenant.name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn quickwit_index(
|
||||
config: &AppConfig,
|
||||
pool: &PgPool,
|
||||
slug: &str,
|
||||
name: &str,
|
||||
method: Method,
|
||||
) -> Result<()> {
|
||||
let endpoint = config
|
||||
@@ -526,11 +526,11 @@ async fn quickwit_index(
|
||||
|
||||
let mut conn = pool.get().context("failed to get database connection")?;
|
||||
let tenant: Tenant = tenants::table
|
||||
.filter(tenants::slug.eq(slug))
|
||||
.filter(tenants::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()
|
||||
.context("failed to query tenants")?
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", slug))?;
|
||||
.ok_or_else(|| anyhow!("tenant '{}' not found", name))?;
|
||||
|
||||
let client = Client::new();
|
||||
let index_id = format!("documents-{}", tenant.id);
|
||||
@@ -549,7 +549,7 @@ async fn quickwit_index(
|
||||
|
||||
println!(
|
||||
"Tenant '{}' quickwit index set to '{}'.",
|
||||
tenant.slug, index_id
|
||||
tenant.name, index_id
|
||||
);
|
||||
}
|
||||
Method::DELETE => {
|
||||
@@ -566,7 +566,7 @@ async fn quickwit_index(
|
||||
.execute(&mut conn)
|
||||
.context("failed to clear tenant quickwit_index")?;
|
||||
|
||||
println!("Tenant '{}' quickwit index cleared.", tenant.slug);
|
||||
println!("Tenant '{}' quickwit index cleared.", tenant.name);
|
||||
}
|
||||
status => {
|
||||
let body = response.text().await.unwrap_or_default();
|
||||
|
||||
@@ -54,8 +54,8 @@ pub struct AppConfig {
|
||||
pub quickwit_endpoint: Option<String>,
|
||||
#[serde(default)]
|
||||
pub quickwit_index: Option<String>,
|
||||
#[serde(default = "default_tenant_slug")]
|
||||
pub default_tenant_slug: String,
|
||||
#[serde(default = "default_tenant_name")]
|
||||
pub default_tenant_name: String,
|
||||
#[serde(default = "default_worker_max_document_bytes")]
|
||||
pub worker_max_document_bytes: u64,
|
||||
#[serde(default)]
|
||||
@@ -171,7 +171,7 @@ fn default_aws_region() -> String {
|
||||
"us-east-1".to_string()
|
||||
}
|
||||
|
||||
fn default_tenant_slug() -> String {
|
||||
fn default_tenant_name() -> String {
|
||||
"admin".to_string()
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ impl FromSql<TenantStatusSql, Pg> for TenantStatus {
|
||||
#[diesel(primary_key(id))]
|
||||
pub struct Tenant {
|
||||
pub id: Uuid,
|
||||
pub slug: String,
|
||||
pub name: String,
|
||||
pub storage_root: Option<String>,
|
||||
pub quickwit_index: Option<String>,
|
||||
pub config: Value,
|
||||
|
||||
@@ -684,7 +684,7 @@ pub mod schemas {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
#[schema(nullable)]
|
||||
pub preferred_tenant_slug: Option<String>,
|
||||
pub preferred_tenant_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
@@ -704,7 +704,7 @@ pub mod schemas {
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct TenantSnippet {
|
||||
pub id: Uuid,
|
||||
pub slug: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
|
||||
+14
-20
@@ -41,7 +41,7 @@ pub struct LoginRequest {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
#[serde(default)]
|
||||
pub preferred_tenant_slug: Option<String>,
|
||||
pub preferred_tenant_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -61,7 +61,7 @@ pub struct LoginResponse {
|
||||
#[derive(Serialize)]
|
||||
pub struct TenantSnippet {
|
||||
pub id: Uuid,
|
||||
pub slug: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -109,9 +109,9 @@ pub async fn signup(
|
||||
|
||||
insert_user(&mut conn, user_id, username, &password_hash)?;
|
||||
|
||||
let tenant_slug = username.to_lowercase();
|
||||
let tenant_name = username.to_string();
|
||||
let tenant = state.tenants.create_tenant(
|
||||
&tenant_slug,
|
||||
&tenant_name,
|
||||
None,
|
||||
None,
|
||||
TenantStatus::Creating,
|
||||
@@ -147,13 +147,7 @@ pub async fn login(
|
||||
return Err(AppError::unauthorized());
|
||||
}
|
||||
|
||||
let preferred_slug = payload
|
||||
.preferred_tenant_slug
|
||||
.as_ref()
|
||||
.map(|slug| slug.trim().to_string())
|
||||
.filter(|slug| !slug.is_empty());
|
||||
|
||||
complete_login(&state, &mut conn, &user, preferred_slug)
|
||||
complete_login(&state, &mut conn, &user, payload.preferred_tenant_id)
|
||||
}
|
||||
|
||||
pub async fn refresh(
|
||||
@@ -323,10 +317,10 @@ pub async fn list_tenants(
|
||||
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))
|
||||
.select((tenant_dsl::id, tenant_dsl::name))
|
||||
.load::<(Uuid, String)>(&mut conn)?
|
||||
.into_iter()
|
||||
.map(|(id, slug)| TenantSnippet { id, slug })
|
||||
.map(|(id, name)| TenantSnippet { id, name })
|
||||
.collect();
|
||||
|
||||
Ok(Json(TenantListResponse { tenants }))
|
||||
@@ -424,7 +418,7 @@ fn complete_login(
|
||||
state: &AppState,
|
||||
conn: &mut PgConnection,
|
||||
user: &User,
|
||||
preferred_slug: Option<String>,
|
||||
preferred_tenant_id: Option<Uuid>,
|
||||
) -> AppResult<Response> {
|
||||
let memberships: Vec<(UserMembership, Tenant)> = memberships_dsl::user_memberships
|
||||
.inner_join(tenant_dsl::tenants)
|
||||
@@ -435,10 +429,10 @@ fn complete_login(
|
||||
return Err(AppError::unauthorized());
|
||||
}
|
||||
|
||||
if let Some(ref slug) = preferred_slug {
|
||||
if let Some(preferred_id) = preferred_tenant_id {
|
||||
if let Some((_, tenant)) = memberships
|
||||
.iter()
|
||||
.find(|(_, tenant)| tenant.slug.eq_ignore_ascii_case(slug))
|
||||
.find(|(_, tenant)| tenant.id == preferred_id)
|
||||
{
|
||||
return issue_session(state, conn, user, tenant.id);
|
||||
}
|
||||
@@ -457,7 +451,7 @@ fn complete_login(
|
||||
.into_iter()
|
||||
.map(|(_, tenant)| TenantSnippet {
|
||||
id: tenant.id,
|
||||
slug: tenant.slug,
|
||||
name: tenant.name,
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -480,9 +474,9 @@ fn issue_session(
|
||||
.generate_token(user.id, tenant_id, &user.username)
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
let tenant_slug: String = tenant_dsl::tenants
|
||||
let tenant_name: String = tenant_dsl::tenants
|
||||
.find(tenant_id)
|
||||
.select(tenant_dsl::slug)
|
||||
.select(tenant_dsl::name)
|
||||
.first(conn)
|
||||
.map_err(AppError::from)?;
|
||||
|
||||
@@ -509,7 +503,7 @@ fn issue_session(
|
||||
expires_in: state.config.jwt_expiry_minutes * 60,
|
||||
tenant: TenantSnippet {
|
||||
id: tenant_id,
|
||||
slug: tenant_slug,
|
||||
name: tenant_name,
|
||||
},
|
||||
})
|
||||
.into_response();
|
||||
|
||||
@@ -457,11 +457,11 @@ fn authenticate(state: &AppState, headers: &HeaderMap) -> Result<Option<WebDavCo
|
||||
.inner_join(tenant_dsl::tenants)
|
||||
.filter(memberships_dsl::user_id.eq(user.id))
|
||||
.filter(memberships_dsl::tenant_id.eq(token.tenant_id))
|
||||
.select((tenant_dsl::id, tenant_dsl::slug))
|
||||
.select((tenant_dsl::id, tenant_dsl::name))
|
||||
.first::<(Uuid, String)>(&mut conn)
|
||||
.optional()?;
|
||||
|
||||
let (tenant_id, _slug) = match tenant_row {
|
||||
let (tenant_id, _name) = match tenant_row {
|
||||
Some(row) => row,
|
||||
None => {
|
||||
tracing::warn!(
|
||||
|
||||
@@ -159,7 +159,7 @@ diesel::table! {
|
||||
|
||||
tenants (id) {
|
||||
id -> Uuid,
|
||||
slug -> Text,
|
||||
name -> Text,
|
||||
storage_root -> Nullable<Text>,
|
||||
quickwit_index -> Nullable<Text>,
|
||||
config -> Jsonb,
|
||||
|
||||
+15
-15
@@ -24,9 +24,9 @@ impl TenantRepository {
|
||||
dsl::tenants.find(tenant_id).first(conn).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn get_by_slug(conn: &mut PgConnection, slug: &str) -> AppResult<Tenant> {
|
||||
pub fn get_by_name(conn: &mut PgConnection, name: &str) -> AppResult<Tenant> {
|
||||
dsl::tenants
|
||||
.filter(dsl::slug.eq(slug))
|
||||
.filter(dsl::name.eq(name))
|
||||
.first(conn)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@@ -47,28 +47,28 @@ impl TenantService {
|
||||
Ok(tenant)
|
||||
}
|
||||
|
||||
pub fn get_by_slug(&self, slug: &str) -> AppResult<Tenant> {
|
||||
let slug_owned = slug.to_owned();
|
||||
let tenant = self.load(|conn| TenantRepository::get_by_slug(conn, &slug_owned))?;
|
||||
pub fn get_by_name(&self, name: &str) -> AppResult<Tenant> {
|
||||
let name_owned = name.to_owned();
|
||||
let tenant = self.load(|conn| TenantRepository::get_by_name(conn, &name_owned))?;
|
||||
Ok(tenant)
|
||||
}
|
||||
|
||||
pub fn tenant_id_for_slug(&self, slug: &str) -> AppResult<Uuid> {
|
||||
Ok(self.get_by_slug(slug)?.id)
|
||||
pub fn tenant_id_for_name(&self, name: &str) -> AppResult<Uuid> {
|
||||
Ok(self.get_by_name(name)?.id)
|
||||
}
|
||||
|
||||
pub fn create_tenant(
|
||||
&self,
|
||||
slug: &str,
|
||||
name: &str,
|
||||
storage_root: Option<&str>,
|
||||
quickwit_index: Option<&str>,
|
||||
status: TenantStatus,
|
||||
initial_members: &[Uuid],
|
||||
created_by: Option<Uuid>,
|
||||
) -> AppResult<Tenant> {
|
||||
let slug = slug.trim();
|
||||
if slug.is_empty() {
|
||||
return Err(AppError::bad_request("tenant slug must not be empty"));
|
||||
let name = name.trim();
|
||||
if name.is_empty() {
|
||||
return Err(AppError::bad_request("tenant name must not be empty"));
|
||||
}
|
||||
|
||||
let mut conn = self.pool.get().map_err(|err| {
|
||||
@@ -77,11 +77,11 @@ impl TenantService {
|
||||
})?;
|
||||
|
||||
let exists: bool =
|
||||
select(exists(dsl::tenants.filter(dsl::slug.eq(slug)))).get_result(&mut conn)?;
|
||||
select(exists(dsl::tenants.filter(dsl::name.eq(name)))).get_result(&mut conn)?;
|
||||
if exists {
|
||||
return Err(AppError::conflict(format!(
|
||||
"tenant '{}' already exists",
|
||||
slug
|
||||
name
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ impl TenantService {
|
||||
diesel::insert_into(dsl::tenants)
|
||||
.values((
|
||||
dsl::id.eq(id),
|
||||
dsl::slug.eq(slug),
|
||||
dsl::name.eq(name),
|
||||
dsl::storage_root.eq(Some(storage_root.clone())),
|
||||
dsl::quickwit_index.eq(Some(quickwit_index.clone())),
|
||||
dsl::config.eq(json!({})),
|
||||
@@ -150,7 +150,7 @@ impl FromRequestParts<AppState> for TenantContext {
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
let tenant = state
|
||||
.tenants
|
||||
.get_by_slug(&state.config.default_tenant_slug)?;
|
||||
.get_by_name(&state.config.default_tenant_name)?;
|
||||
Ok(Self { tenant })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user