From 22cda312cf7e663a75f4462d5da2b2a12f459c7c Mon Sep 17 00:00:00 2001 From: root Date: Wed, 1 Jul 2026 13:40:37 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20remove=20whitelist=20do=20PATCH=20?= =?UTF-8?q?=E2=80=94=20Supabase=20valida=20colunas;=20adiciona=20edited=5F?= =?UTF-8?q?at/edited=5Fby=20no=20payload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/plugins/supabase.rs | 35 +++++++------------------------ src/index.html | 4 +++- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src-tauri/src/plugins/supabase.rs b/src-tauri/src/plugins/supabase.rs index 22e0471..4441fdc 100644 --- a/src-tauri/src/plugins/supabase.rs +++ b/src-tauri/src/plugins/supabase.rs @@ -250,32 +250,13 @@ impl SupabaseClient { /// Atualiza campos específicos de um fechamento pelo id_fechamento. pub fn atualizar_fechamento(&self, id_fechamento: &str, updates: &serde_json::Value) -> Result { - // Whitelist: só colunas que existem na tabela fechamentos_web. - // Campos de lista (vales, despesas, sangrias, etc.) vivem no JSONB `dados` - // e são tratados separadamente via salvar_listas / carregar_listas. - static ALLOWED: &[&str] = &[ - "data", "loja", "turno", "operador", - "saldo_troco", "saldo_credito", "saldo_debito", "saldo_alimentacao", - "saldo_vales", "saldo_areceber", - "total_cartao_credito", "total_cartao_debito", "total_cartao_alimentacao", - "total_cartao_pix", "total_pixcnpj", - "total_sangrias", "total_despesas", "total_vales", - "total_areceber", "total_cancelamentos", - "fechamento_dinheiro", "fechamento_cartoes", "fechamento_areceber", - "clientes", "frango", "vendas", "saldo_esperado", - "observacoes", "edited_at", "edited_by", - ]; + // Sem whitelist — o frontend envia só o que o usuário editou. + // O Supabase/Postgres valida as colunas existentes. + // edited_at é atualizado pelo frontend no objeto updates. + let map = updates.as_object().cloned().unwrap_or_default(); - let filtered: serde_json::Map = updates - .as_object() - .cloned() - .unwrap_or_default() - .into_iter() - .filter(|(k, _)| ALLOWED.contains(&k.as_str())) - .collect(); - - if filtered.is_empty() { - return Err(SupabaseError::Api("Nenhum campo válido para atualizar".into())); + if map.is_empty() { + return Err(SupabaseError::Api("Nenhum campo para atualizar".into())); } let url = format!( @@ -284,14 +265,14 @@ impl SupabaseClient { urlencoding::encode(id_fechamento) ); - log::info!("[PATCH] url={} body={:#?}", url, filtered); + log::info!("[PATCH] url={} body={:#?}", url, map); let resp = self .http .patch(&url) .headers(self.headers(true)) .header("Prefer", "return=representation") - .json(&filtered) + .json(&map) .send()?; let status = resp.status(); diff --git a/src/index.html b/src/index.html index 1060230..1a69eaf 100644 --- a/src/index.html +++ b/src/index.html @@ -3113,7 +3113,9 @@ window.salvarEdicaoConsulta = async function() { frango: parseInt(inp('edit-frango') || '0'), vendas: p(inp('edit-vendas')), saldo_esperado: p(inp('edit-esperado')), - observacoes: inp('edit-obs') + observacoes: inp('edit-obs'), + edited_at: new Date().toISOString(), + edited_by: full.operador || '', }; const hasTauri = !!(window.__TAURI__ && window.__TAURI__.core);