mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-04 16:03:06 +00:00
feat(backend): check of no path conflict between flow and flow's primary schedules
This commit is contained in:
@@ -167,6 +167,27 @@
|
||||
"nullable": []
|
||||
}
|
||||
},
|
||||
"0d6412bc3ebb1d58bdd9cbcef774dacf9016fa402af5c1b4e339b9a3d7163d5e": {
|
||||
"query": "SELECT EXISTS (SELECT 1 FROM schedule WHERE path = $1 AND workspace_id = $2 AND path != script_path)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
"0dd3fe3ddf9cb72760687d2ee0950afdcce2d54721bfe8dba008b15e4b581956": {
|
||||
"query": "DELETE FROM account WHERE id = $1 AND workspace_id = $2",
|
||||
"describe": {
|
||||
@@ -2909,6 +2930,27 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"e262f83b672a558092dc959b28a919f18e44b2a0d03b27b0ddba99896940c6d3": {
|
||||
"query": "SELECT EXISTS (SELECT 1 FROM flow WHERE path = $1 AND workspace_id = $2)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
"e3eeda2e19bfbfd5aadd71c40774f7e93c8479a777fdb2828607b1db36361726": {
|
||||
"query": "INSERT INTO usr_to_group\n VALUES ($1, 'all', $2)",
|
||||
"describe": {
|
||||
|
||||
+27
-2
@@ -16,12 +16,12 @@ use axum::{
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sql_builder::SqlBuilder;
|
||||
use sqlx::FromRow;
|
||||
use sqlx::{FromRow, Postgres, Transaction};
|
||||
|
||||
use crate::{
|
||||
audit::{audit_log, ActionKind},
|
||||
db::{UserDB, DB},
|
||||
error::{Error, JsonResult, Result},
|
||||
error::{self, Error, JsonResult, Result},
|
||||
jobs::RawCode,
|
||||
scripts::Schema,
|
||||
users::Authed,
|
||||
@@ -171,6 +171,8 @@ async fn create_flow(
|
||||
// cron::Schedule::from_str(&ns.schedule).map_err(|e| error::Error::BadRequest(e.to_string()))?;
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
check_schedule_conflict(&mut tx, &w_id, &nf.path).await?;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::text::json)",
|
||||
w_id,
|
||||
@@ -205,6 +207,27 @@ async fn create_flow(
|
||||
Ok(nf.path.to_string())
|
||||
}
|
||||
|
||||
async fn check_schedule_conflict<'c>(
|
||||
tx: &mut Transaction<'c, Postgres>,
|
||||
w_id: &str,
|
||||
path: &str,
|
||||
) -> error::Result<()> {
|
||||
let exists_flow = sqlx::query_scalar!(
|
||||
"SELECT EXISTS (SELECT 1 FROM schedule WHERE path = $1 AND workspace_id = $2 AND path != script_path)",
|
||||
path,
|
||||
w_id
|
||||
)
|
||||
.fetch_one(tx)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if exists_flow {
|
||||
return Err(error::Error::BadConfig(format!(
|
||||
"A flow cannot have the same path as a schedule if the schedule does not trigger that same flow: {path}",
|
||||
)));
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_flow(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
@@ -214,6 +237,8 @@ async fn update_flow(
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
let flow_path = flow_path.to_path();
|
||||
check_schedule_conflict(&mut tx, &w_id, flow_path).await?;
|
||||
|
||||
let schema = nf.schema.map(|x| x.0);
|
||||
let flow = sqlx::query_scalar!(
|
||||
"UPDATE flow SET path = $1, summary = $2, description = $3, value = $4, edited_by = $5, edited_at = $6, schema = $7 WHERE path = $8 AND workspace_id = $9 RETURNING path",
|
||||
|
||||
@@ -129,6 +129,8 @@ async fn create_schedule(
|
||||
cron::Schedule::from_str(&ns.schedule).map_err(|e| error::Error::BadRequest(e.to_string()))?;
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
check_flow_conflict(&mut tx, &w_id, &ns.path, ns.is_flow, &ns.script_path).await?;
|
||||
|
||||
let schedule = sqlx::query_as!(Schedule,
|
||||
"INSERT INTO schedule (workspace_id, path, schedule, offset_, edited_by, script_path, is_flow, args) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *",
|
||||
w_id,
|
||||
@@ -167,6 +169,32 @@ async fn create_schedule(
|
||||
Ok(ns.path.to_string())
|
||||
}
|
||||
|
||||
async fn check_flow_conflict<'c>(
|
||||
tx: &mut Transaction<'c, Postgres>,
|
||||
w_id: &str,
|
||||
path: &str,
|
||||
is_flow: bool,
|
||||
script_path: &str,
|
||||
) -> error::Result<()> {
|
||||
if path != script_path || !is_flow {
|
||||
let exists_flow = sqlx::query_scalar!(
|
||||
"SELECT EXISTS (SELECT 1 FROM flow WHERE path = $1 AND workspace_id = $2)",
|
||||
path,
|
||||
w_id
|
||||
)
|
||||
.fetch_one(tx)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if exists_flow {
|
||||
return Err(error::Error::BadConfig(format!(
|
||||
"If a schedule has the same path as or a flow, it must be its primary schedule and hence can only trigger it.
|
||||
However the provided path is: {script_path} and is_flow is: {is_flow}",
|
||||
)));
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EditSchedule {
|
||||
pub schedule: String,
|
||||
@@ -194,6 +222,8 @@ async fn edit_schedule(
|
||||
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
check_flow_conflict(&mut tx, &w_id, &path, es.is_flow, &es.script_path).await?;
|
||||
|
||||
clear_schedule(&mut tx, path).await?;
|
||||
let schedule = sqlx::query_as!(Schedule,
|
||||
"UPDATE schedule SET schedule = $1, script_path = $2, is_flow = $3, args = $4 WHERE path = $5 AND workspace_id = $6 RETURNING *",
|
||||
|
||||
Reference in New Issue
Block a user