feat: introduce CourseEditorLayout and AppHeader, add organization domain migration, and update Docker configurations and auth scripts

This commit is contained in:
2025-12-29 18:00:34 -03:00
parent 3a02ecb757
commit ad56d8a81c
30 changed files with 558 additions and 405 deletions
+5
View File
@@ -0,0 +1,5 @@
target
**/*.rs.bk
.env
.env.*
! .env.example
@@ -0,0 +1,2 @@
-- Migration: Add domain to organizations
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS domain VARCHAR(255) UNIQUE;
+47
View File
@@ -1474,3 +1474,50 @@ pub async fn update_user(
Ok(StatusCode::OK)
}
// Organizations Management (Plural/Admin)
pub async fn get_organizations(
claims: common::auth::Claims,
State(pool): State<PgPool>,
) -> Result<Json<Vec<Organization>>, StatusCode> {
if claims.role != "admin" {
return Err(StatusCode::FORBIDDEN);
}
let orgs = sqlx::query_as::<_, Organization>("SELECT * FROM organizations ORDER BY created_at DESC")
.fetch_all(&pool)
.await
.map_err(|e| {
tracing::error!("Failed to fetch organizations: {}", e);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(orgs))
}
pub async fn create_organization(
claims: common::auth::Claims,
State(pool): State<PgPool>,
Json(payload): Json<serde_json::Value>,
) -> Result<Json<Organization>, StatusCode> {
if claims.role != "admin" {
return Err(StatusCode::FORBIDDEN);
}
let name = payload.get("name").and_then(|v| v.as_str()).ok_or(StatusCode::BAD_REQUEST)?;
let domain = payload.get("domain").and_then(|v| v.as_str());
let org = sqlx::query_as::<_, Organization>(
"INSERT INTO organizations (name, domain) VALUES ($1, $2) RETURNING *"
)
.bind(name)
.bind(domain)
.fetch_one(&pool)
.await
.map_err(|e| {
tracing::error!("Failed to create organization: {}", e);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(org))
}
+1
View File
@@ -86,6 +86,7 @@ async fn main() {
.route("/users/{id}", axum::routing::put(handlers::update_user))
.route("/audit-logs", get(handlers::get_audit_logs))
.route("/assets/upload", post(handlers::upload_asset))
.route("/organizations", get(handlers::get_organizations).post(handlers::create_organization))
.route("/organization", get(handlers::get_organization))
.route(
"/organizations/{id}/logo",