* chore: upgrade axum 0.7 to 0.8 and related dependencies Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add route reachability tests for ~80 previously untested endpoints Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: switch feature-gated trigger handlers from axum::async_trait to async_trait crate Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update new trash routes to axum 0.8 path syntax Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to latest EE commit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: upgrade route tests to assert 2xx responses with proper data setup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: restore npm_proxy and ai_routes tests using local echo servers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: gate workspace fork test behind enterprise feature flag Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add ~40 more endpoint tests (jobs authed, health, favorites, ACLs, reachability) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review findings from axum 0.8 upgrade - Use cookie value_trimmed() instead of value() for cookie 0.18 compat - Update comments still referencing old :workspace_id syntax Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 61ae055ea31481f1899953e9d5f65566b8c707b1 This commit updates the EE repository reference after PR #486 was merged in windmill-ee-private. Previous ee-repo-ref: 0059d175a6fdddf52998b183bf91059b224704ac New ee-repo-ref: 61ae055ea31481f1899953e9d5f65566b8c707b1 Automated by sync-ee-ref workflow. * test: add test for new get_imports endpoint Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove unused import in raw_apps test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
138 lines
3.8 KiB
Rust
138 lines
3.8 KiB
Rust
/*
|
|
* Author: Ruben Fiszel
|
|
* Copyright: Windmill Labs, Inc 2024
|
|
* This file and its contents are licensed under the AGPLv3 License.
|
|
* Please see the included NOTICE for copyright information and
|
|
* LICENSE-AGPL for a copy of the license.
|
|
*/
|
|
|
|
use crate::{
|
|
db::{ApiAuthed, DB},
|
|
users::{maybe_refresh_folders, require_owner_of_path},
|
|
};
|
|
|
|
use axum::{
|
|
extract::{Extension, Path},
|
|
routing::{delete, post},
|
|
Json, Router,
|
|
};
|
|
use hyper::StatusCode;
|
|
use serde::{Deserialize, Serialize};
|
|
use windmill_common::{db::UserDB, error::Result, utils::StripPath};
|
|
|
|
pub fn workspaced_service() -> Router {
|
|
Router::new()
|
|
.route("/create", post(create_draft))
|
|
.route("/delete/{kind}/{*path}", delete(delete_draft))
|
|
}
|
|
|
|
#[derive(sqlx::Type, Serialize, Deserialize, Debug, PartialEq, Clone)]
|
|
#[sqlx(type_name = "DRAFT_TYPE", rename_all = "lowercase")]
|
|
#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))]
|
|
pub enum DraftType {
|
|
Script,
|
|
Flow,
|
|
App,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct Draft {
|
|
pub path: String,
|
|
pub value: sqlx::types::Json<Box<serde_json::value::Value>>,
|
|
pub typ: DraftType,
|
|
}
|
|
|
|
pub async fn require_writer_of_path(
|
|
authed: &ApiAuthed,
|
|
path: &str,
|
|
w_id: &str,
|
|
db: DB,
|
|
kind: &DraftType,
|
|
) -> Result<()> {
|
|
if authed.is_admin {
|
|
return Ok(());
|
|
} else if require_owner_of_path(authed, path).is_ok() {
|
|
return Ok(());
|
|
} else {
|
|
match kind {
|
|
DraftType::Script => crate::scripts::require_is_writer(authed, path, w_id, db).await,
|
|
DraftType::Flow => crate::flows::require_is_writer(authed, path, w_id, db).await,
|
|
DraftType::App => crate::apps::require_is_writer(authed, path, w_id, db).await,
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn create_draft(
|
|
authed: ApiAuthed,
|
|
Extension(db): Extension<DB>,
|
|
Extension(user_db): Extension<UserDB>,
|
|
Path(w_id): Path<String>,
|
|
Json(draft): Json<Draft>,
|
|
) -> Result<(StatusCode, String)> {
|
|
let authed = maybe_refresh_folders(&draft.path, &w_id, authed, &db).await;
|
|
|
|
let mut tx = user_db.begin(&authed).await?;
|
|
|
|
require_writer_of_path(&authed, &draft.path, &w_id, db, &draft.typ).await?;
|
|
|
|
sqlx::query!(
|
|
"INSERT INTO draft
|
|
(workspace_id, path, value, typ)
|
|
VALUES ($1, $2, $3::text::json, $4)
|
|
ON CONFLICT (workspace_id, path, typ) DO UPDATE SET value = EXCLUDED.value",
|
|
&w_id,
|
|
draft.path,
|
|
//to preserve key orders
|
|
serde_json::to_string(&draft.value).unwrap(),
|
|
draft.typ as DraftType,
|
|
)
|
|
.execute(&mut *tx)
|
|
.await?;
|
|
|
|
tx.commit().await?;
|
|
|
|
Ok((StatusCode::CREATED, format!("draft {} created", draft.path)))
|
|
}
|
|
|
|
async fn delete_draft(
|
|
authed: ApiAuthed,
|
|
Extension(user_db): Extension<UserDB>,
|
|
Path((w_id, kind, path)): Path<(String, DraftType, StripPath)>,
|
|
) -> Result<String> {
|
|
let mut tx = user_db.begin(&authed).await?;
|
|
|
|
sqlx::query!(
|
|
"DELETE FROM draft WHERE path = $1 AND typ = $2 AND workspace_id = $3",
|
|
path.to_path(),
|
|
kind as DraftType,
|
|
w_id
|
|
)
|
|
.execute(&mut *tx)
|
|
.await?;
|
|
tx.commit().await?;
|
|
|
|
Ok(format!("deleted draft"))
|
|
}
|
|
|
|
// async fn get_draft(
|
|
// authed: ApiAuthed,
|
|
// Extension(user_db): Extension<UserDB>,
|
|
// Path((w_id, path)): Path<(String, StripPath)>,
|
|
// ) -> JsonResult<Draft> {
|
|
// let path = path.to_path();
|
|
// let mut tx = user_db.begin(&authed).await?;
|
|
|
|
// let script_o = sqlx::query_as!(
|
|
// Draft,
|
|
// r#"SELECT path, value, typ as "typ: DraftType" FROM draft WHERE path = $1 AND workspace_id = $2"#,
|
|
// path,
|
|
// w_id
|
|
// )
|
|
// .fetch_optional(&mut *tx)
|
|
// .await?;
|
|
// tx.commit().await?;
|
|
|
|
// let draft = not_found_if_none(script_o, "draft", path)?;
|
|
// Ok(Json(draft))
|
|
// }
|