package storage import ( "database/sql" "time" ) // ScheduledJob represents a cron-based scheduled scan job. type ScheduledJob struct { ID int64 Name string CronExpr string ScanCommand string NotifyTelegram bool Enabled bool LastRun *time.Time NextRun *time.Time CreatedAt time.Time } // SaveScheduledJob inserts a new scheduled job. Returns the new row ID. func (db *DB) SaveScheduledJob(j ScheduledJob) (int64, error) { res, err := db.sql.Exec( `INSERT INTO scheduled_jobs (name, cron_expr, scan_command, notify_telegram, enabled) VALUES (?, ?, ?, ?, ?)`, j.Name, j.CronExpr, j.ScanCommand, j.NotifyTelegram, j.Enabled, ) if err != nil { return 0, err } return res.LastInsertId() } // ListScheduledJobs returns all scheduled jobs. func (db *DB) ListScheduledJobs() ([]ScheduledJob, error) { rows, err := db.sql.Query( `SELECT id, name, cron_expr, scan_command, notify_telegram, enabled, last_run, next_run, created_at FROM scheduled_jobs ORDER BY id`, ) if err != nil { return nil, err } defer rows.Close() var jobs []ScheduledJob for rows.Next() { var j ScheduledJob var lastRun, nextRun sql.NullTime if err := rows.Scan(&j.ID, &j.Name, &j.CronExpr, &j.ScanCommand, &j.NotifyTelegram, &j.Enabled, &lastRun, &nextRun, &j.CreatedAt); err != nil { return nil, err } if lastRun.Valid { j.LastRun = &lastRun.Time } if nextRun.Valid { j.NextRun = &nextRun.Time } jobs = append(jobs, j) } return jobs, rows.Err() } // GetScheduledJob returns a single scheduled job by name. func (db *DB) GetScheduledJob(name string) (*ScheduledJob, error) { var j ScheduledJob var lastRun, nextRun sql.NullTime err := db.sql.QueryRow( `SELECT id, name, cron_expr, scan_command, notify_telegram, enabled, last_run, next_run, created_at FROM scheduled_jobs WHERE name = ?`, name, ).Scan(&j.ID, &j.Name, &j.CronExpr, &j.ScanCommand, &j.NotifyTelegram, &j.Enabled, &lastRun, &nextRun, &j.CreatedAt) if err != nil { return nil, err } if lastRun.Valid { j.LastRun = &lastRun.Time } if nextRun.Valid { j.NextRun = &nextRun.Time } return &j, nil } // DeleteScheduledJob removes a scheduled job by name. Returns rows affected. func (db *DB) DeleteScheduledJob(name string) (int64, error) { res, err := db.sql.Exec(`DELETE FROM scheduled_jobs WHERE name = ?`, name) if err != nil { return 0, err } return res.RowsAffected() } // UpdateJobLastRun updates the last_run and next_run timestamps for a job. func (db *DB) UpdateJobLastRun(name string, lastRun time.Time, nextRun *time.Time) error { var nr sql.NullTime if nextRun != nil { nr = sql.NullTime{Time: *nextRun, Valid: true} } _, err := db.sql.Exec( `UPDATE scheduled_jobs SET last_run = ?, next_run = ? WHERE name = ?`, lastRun, nr, name, ) return err } // SetJobEnabled updates the enabled flag for a scheduled job. func (db *DB) SetJobEnabled(name string, enabled bool) error { _, err := db.sql.Exec(`UPDATE scheduled_jobs SET enabled = ? WHERE name = ?`, enabled, name) return err }