From d2ee695d8bbcf73cf7c0a9247a91489535bbdefb Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sun, 2 Nov 2025 19:32:25 -0300 Subject: [PATCH] feat: add bot_id to system_automations and enhance schedule handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduced `bot_id` column in `system_automations` table (migration 6.0.0.sql) and updated the Diesel schema/model to include it. - Adjusted migrations to remove the hard‑coded “Update Summary” automation and only create an index on the `name` column. - Extended the `SET_SCHEDULE` keyword: - Added a second string argument for the script name. - Passed the invoking user's `bot_id` to the database layer. - Updated function signature to accept a full `UserSession` instead of discarding it. - Modified `execute_set_schedule` to store `bot_id`, script name, and activation flag; added conflict handling on `(bot_id, param)` to update schedule and reset trigger state. - Updated imports and logging to reflect new parameters. These changes enable per‑bot automation management, allow specifying the script to run, and improve idempotent schedule updates. --- migrations/6.0.0.sql | 1 + migrations/6.0.5.sql | 15 -------- migrations/6.0.9.sql | 11 ++++++ src/basic/keywords/set_schedule.rs | 38 ++++++++++++------- src/shared/models.rs | 2 + .../announcements.gbdialog/update-summary.bas | 2 + 6 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 migrations/6.0.9.sql diff --git a/migrations/6.0.0.sql b/migrations/6.0.0.sql index cd3f4839..ddb948d1 100644 --- a/migrations/6.0.0.sql +++ b/migrations/6.0.0.sql @@ -55,6 +55,7 @@ CREATE INDEX idx_organizations_slug ON public.organizations USING btree (slug); CREATE TABLE public.system_automations ( id uuid DEFAULT gen_random_uuid() NOT NULL, + bot_id uuid NOT NULL, kind int4 NOT NULL, "target" varchar(32) NULL, schedule bpchar(12) NULL, diff --git a/migrations/6.0.5.sql b/migrations/6.0.5.sql index cbbab1e5..f8f95200 100644 --- a/migrations/6.0.5.sql +++ b/migrations/6.0.5.sql @@ -6,20 +6,5 @@ -- Add name column to system_automations if it doesn't exist ALTER TABLE public.system_automations ADD COLUMN IF NOT EXISTS name VARCHAR(255); --- Insert update-summary automation (runs every minute) --- kind = 3 (Scheduled trigger) --- schedule format: minute hour day month weekday --- "* * * * *" = every minute -INSERT INTO public.system_automations (name, kind, target, param, schedule, is_active) -VALUES ( - 'Update Summary', - 0, - NULL, - 'update-summary.bas', - '* * * * *', - true -) -ON CONFLICT DO NOTHING; - -- Create index on name column for faster lookups CREATE INDEX IF NOT EXISTS idx_system_automations_name ON public.system_automations(name); diff --git a/migrations/6.0.9.sql b/migrations/6.0.9.sql new file mode 100644 index 00000000..38d646c9 --- /dev/null +++ b/migrations/6.0.9.sql @@ -0,0 +1,11 @@ +-- Migration 6.0.9: Add bot_id column to system_automations +-- Description: Introduces a bot_id column to associate automations with a specific bot. +-- The column is added as UUID and indexed for efficient queries. + +-- Add bot_id column if it does not exist +ALTER TABLE public.system_automations +ADD COLUMN IF NOT EXISTS bot_id UUID NOT NULL; + +-- Create an index on bot_id for faster lookups +CREATE INDEX IF NOT EXISTS idx_system_automations_bot_id +ON public.system_automations (bot_id); diff --git a/src/basic/keywords/set_schedule.rs b/src/basic/keywords/set_schedule.rs index f0bba130..fa70f9ed 100644 --- a/src/basic/keywords/set_schedule.rs +++ b/src/basic/keywords/set_schedule.rs @@ -3,22 +3,23 @@ use log::info; use rhai::Dynamic; use rhai::Engine; use serde_json::{json, Value}; +use uuid::Uuid; use crate::shared::models::TriggerKind; use crate::shared::models::UserSession; use crate::shared::state::AppState; -pub fn set_schedule_keyword(state: &AppState, _user: UserSession, engine: &mut Engine) { +pub fn set_schedule_keyword(state: &AppState, user: UserSession, engine: &mut Engine) { let state_clone = state.clone(); engine - .register_custom_syntax(&["SET_SCHEDULE", "$string$"], true, { + .register_custom_syntax(&["SET_SCHEDULE", "$string$", "$string$"], true, { move |context, inputs| { let cron = context.eval_expression_tree(&inputs[0])?.to_string(); - let param = format!("cron_{}.rhai", cron.replace(' ', "_")); + let script_name = context.eval_expression_tree(&inputs[1])?.to_string(); let mut conn = state_clone.conn.lock().unwrap(); - let result = execute_set_schedule(&mut *conn, &cron, ¶m) + let result = execute_set_schedule(&mut *conn, &cron, &script_name, user.bot_id) .map_err(|e| format!("DB error: {}", e))?; if let Some(rows_affected) = result.get("rows_affected") { @@ -34,29 +35,40 @@ pub fn set_schedule_keyword(state: &AppState, _user: UserSession, engine: &mut E pub fn execute_set_schedule( conn: &mut diesel::PgConnection, cron: &str, - param: &str, + script_name: &str, + bot_uuid: Uuid, ) -> Result> { info!( - "Starting execute_set_schedule with cron: {}, param: {}", - cron, param + "Starting execute_set_schedule with cron: {}, script: {}, bot_id: {:?}", + cron, script_name, bot_uuid ); - use crate::shared::models::system_automations; + use crate::shared::models::system_automations::dsl::*; let new_automation = ( - system_automations::kind.eq(TriggerKind::Scheduled as i32), - system_automations::schedule.eq(cron), - system_automations::param.eq(param), + bot_id.eq(bot_uuid), + kind.eq(TriggerKind::Scheduled as i32), + schedule.eq(cron), + param.eq(script_name), + is_active.eq(true), ); - let result = diesel::insert_into(system_automations::table) + let result = diesel::insert_into(system_automations) .values(&new_automation) + .on_conflict((bot_id, param)) + .do_update() + .set(( + schedule.eq(cron), + is_active.eq(true), + last_triggered.eq(None::>), + )) .execute(&mut *conn)?; Ok(json!({ "command": "set_schedule", "schedule": cron, - "param": param, + "script": script_name, + "bot_id": bot_uuid.to_string(), "rows_affected": result })) } diff --git a/src/shared/models.rs b/src/shared/models.rs index 92a1afb7..8859acab 100644 --- a/src/shared/models.rs +++ b/src/shared/models.rs @@ -65,6 +65,7 @@ impl TriggerKind { #[diesel(table_name = system_automations)] pub struct Automation { pub id: Uuid, + pub bot_id: Uuid, pub kind: i32, pub target: Option, pub schedule: Option, @@ -265,6 +266,7 @@ pub mod schema { diesel::table! { system_automations (id) { id -> Uuid, + bot_id -> Uuid, kind -> Int4, target -> Nullable, schedule -> Nullable, diff --git a/templates/announcements.gbai/announcements.gbdialog/update-summary.bas b/templates/announcements.gbai/announcements.gbdialog/update-summary.bas index d164e53a..d66a65f4 100644 --- a/templates/announcements.gbai/announcements.gbdialog/update-summary.bas +++ b/templates/announcements.gbai/announcements.gbdialog/update-summary.bas @@ -1,3 +1,5 @@ +SET_SCHEDULE "* * * * *" + let text = GET "announcements.gbkb/news/news.pdf" let resume = LLM "Resume this document, in a table (DO NOT THINK) no_think: " + text