mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: kinds that cannot move skip the move lookup, and the move wording needs read
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
05e4fb9de8
commit
b6da6410e1
@@ -413,9 +413,14 @@ async fn update_draft(
|
||||
// legacy row too, since the same rename carried it — and the draft whose presence
|
||||
// means this path is still the write's own.
|
||||
let owner: Option<&str> = (!legacy_delete).then_some(email.as_str());
|
||||
// The caller's own draft-only move outranks the move of the deployed item.
|
||||
let moved_to = sqlx::query_scalar!(
|
||||
r#"SELECT m.new_path FROM draft_move m
|
||||
// The caller's own draft-only move outranks the move of the deployed item. Only the
|
||||
// kinds whose value carries a deploy target are ever recorded as moved, so for the
|
||||
// rest this would be a guaranteed-empty query on the autosave hot path.
|
||||
let moved_to = match kind.typed_path_field() {
|
||||
None => None,
|
||||
Some(_) => {
|
||||
sqlx::query_scalar!(
|
||||
r#"SELECT m.new_path FROM draft_move m
|
||||
WHERE m.workspace_id = $1 AND m.typ = $2 AND m.old_path = $3
|
||||
AND (m.email IS NULL OR m.email = $4)
|
||||
AND NOT EXISTS (
|
||||
@@ -425,13 +430,15 @@ async fn update_draft(
|
||||
)
|
||||
ORDER BY m.email IS NULL
|
||||
LIMIT 1"#,
|
||||
&w_id,
|
||||
kind as UserDraftItemKind,
|
||||
url_path,
|
||||
owner,
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
&w_id,
|
||||
kind as UserDraftItemKind,
|
||||
url_path,
|
||||
owner,
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
let path: &str = moved_to.as_deref().unwrap_or(url_path);
|
||||
|
||||
// Everything past here writes, so the gate applies from here on. Answered
|
||||
@@ -439,9 +446,18 @@ async fn update_draft(
|
||||
// cannot see.
|
||||
if !is_own_discard {
|
||||
match require_can_write_path(&authed, &db, &user_db, &w_id, kind, path).await {
|
||||
Err(Error::NotAuthorized(_)) if moved_to.is_some() => {
|
||||
// Naming the move is for whoever was editing the item: it tells them why a
|
||||
// save they were already making stopped landing. Someone who cannot read the
|
||||
// path they addressed gets the plain denial, or the wording itself would
|
||||
// answer whether an item was moved away from a path they only guessed at.
|
||||
Err(Error::NotAuthorized(e)) if moved_to.is_some() => {
|
||||
return Err(Error::NotAuthorized(
|
||||
"this draft's item was moved to a path you cannot write".to_string(),
|
||||
match require_can_read_path(&authed, &user_db, &w_id, kind, url_path).await {
|
||||
Ok(()) => {
|
||||
"this draft's item was moved to a path you cannot write".to_string()
|
||||
}
|
||||
Err(_) => e,
|
||||
},
|
||||
));
|
||||
}
|
||||
other => other?,
|
||||
|
||||
@@ -350,7 +350,11 @@
|
||||
// a move keeps its old save time while the move mints a fresh deploy, so
|
||||
// the timestamps alone would call every carried draft stale.
|
||||
draftBaseHash = backendScript.draft_base
|
||||
deployedHeadHash = backendScript.hash as string | undefined
|
||||
// A draft-only script has no deployed hash to be behind: what comes back
|
||||
// under `hash` is then the draft's own value, not a head.
|
||||
deployedHeadHash = backendScript.no_deployed
|
||||
? undefined
|
||||
: (backendScript.hash as string | undefined)
|
||||
const effectiveScript: EditableScript = draftFromBackend
|
||||
? { ...deployedScript, ...draftFromBackend }
|
||||
: (deployedScript as EditableScript)
|
||||
|
||||
Reference in New Issue
Block a user