diff --git a/client/src/pages/view.rs b/client/src/pages/view.rs index 4df1243..ec48a03 100644 --- a/client/src/pages/view.rs +++ b/client/src/pages/view.rs @@ -439,7 +439,7 @@ pub fn ViewPage() -> impl IntoView { let slug_clone = slug(); let username_clone = username(); spawn_local(async move { - let url = format!("{}/api/project/{}/embed-key", api_base(), slug_clone); + let url = format!("{}/api/project/{}/{}/embed-key", api_base(), username_clone, slug_clone); match Request::get(&url).credentials(RequestCredentials::Include).send().await { Ok(resp) => { match resp.json::().await { @@ -492,7 +492,7 @@ pub fn ViewPage() -> impl IntoView { let slug_clone = slug(); let username_clone = username(); spawn_local(async move { - let url = format!("{}/api/project/{}/embed-key", api_base(), slug_clone); + let url = format!("{}/api/project/{}/{}/embed-key", api_base(), username_clone, slug_clone); match Request::get(&url).credentials(RequestCredentials::Include).send().await { Ok(resp) => { match resp.json::().await { diff --git a/server/src/handlers/project.rs b/server/src/handlers/project.rs index 3f39912..67988eb 100644 --- a/server/src/handlers/project.rs +++ b/server/src/handlers/project.rs @@ -148,12 +148,12 @@ pub fn routes() -> Router { Router::new() .route("/api/my-projects", get(list_user_projects)) .route("/api/project/:username/:slug", get(get_project)) - .route("/api/project/:slug", delete(delete_project)) - .route("/api/project/:slug/embed-key", get(get_embed_key)) + .route("/api/project/:username/:slug/embed-key", get(get_embed_key)) .route( "/api/project/:slug/whitelist", get(get_whitelist).post(add_to_whitelist).delete(remove_from_whitelist), ) + .route("/api/project/:slug", delete(delete_project)) .route("/api/search-projects", get(search_projects)) .route("/api/publish", post(publish_handler)) .route("/e/:token", get(resolve_secret_embed)) // Secret Embed Route @@ -749,7 +749,7 @@ pub async fn remove_from_whitelist( pub async fn get_embed_key( State(state): State, session: Session, - Path(slug): Path, + Path((username, slug)): Path<(String, String)>, ) -> Result, (StatusCode, String)> { // 1. Verify user is authenticated let user: Option = session @@ -758,12 +758,13 @@ pub async fn get_embed_key( .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Session Error: {}", e)))?; let user = user.ok_or((StatusCode::UNAUTHORIZED, "Unauthorized".to_string()))?; - // 2. Fetch project and verify ownership + // 2. Fetch project and verify ownership (case-insensitive for username/slug) let row_result = sqlx::query_as::<_, (i64, i64, Option)>( "SELECT id, owner_id, embed_key \ FROM projects \ - WHERE LOWER(slug) = LOWER($1)" + WHERE LOWER(owner_username) = LOWER($1) AND LOWER(slug) = LOWER($2)" ) + .bind(&username) .bind(&slug) .fetch_optional(&state.db) .await