package db import "encoding/json" func (d *DB) ListRulesForMailbox(mailboxID int64) ([]MailboxFilterRule, error) { rows, err := d.Query(`SELECT id, mailbox_id, priority, condition_field, condition_op, condition_value, action, action_value, is_active, conditions_json, match_type, created_at FROM esrv_mailbox_filter_rules WHERE mailbox_id = ? ORDER BY priority ASC, id ASC`, mailboxID) if err != nil { return nil, err } defer rows.Close() var out []MailboxFilterRule for rows.Next() { var r MailboxFilterRule var createdAt string if err := rows.Scan(&r.ID, &r.MailboxID, &r.Priority, &r.ConditionField, &r.ConditionOp, &r.ConditionValue, &r.Action, &r.ActionValue, &r.IsActive, &r.ConditionsJSON, &r.MatchType, &createdAt); err != nil { return nil, err } r.CreatedAt, _ = parseTime(createdAt) out = append(out, r) } return out, rows.Err() } // CreateRule creates a single-condition rule — a thin wrapper over CreateRuleMulti // for the common one-condition case (and for existing callers/tests written before // multi-condition rules existed). func (d *DB) CreateRule(mailboxID int64, priority int, field, op, value, action, actionValue string) (int64, error) { return d.CreateRuleMulti(mailboxID, priority, []RuleCondition{{Field: field, Op: op, Value: value}}, "all", action, actionValue) } // CreateRuleMulti creates a rule with one or more conditions combined per matchType // ("all"=AND, "any"=OR, defaulting to "all" for anything else). The first condition // also mirrors into the legacy condition_field/op/value columns so old code paths // reading them directly still see something sane. func (d *DB) CreateRuleMulti(mailboxID int64, priority int, conditions []RuleCondition, matchType, action, actionValue string) (int64, error) { if matchType != "any" { matchType = "all" } conditionsJSON, err := json.Marshal(conditions) if err != nil { return 0, err } first := conditions[0] res, err := d.Exec(`INSERT INTO esrv_mailbox_filter_rules (mailbox_id, priority, condition_field, condition_op, condition_value, action, action_value, conditions_json, match_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, mailboxID, priority, first.Field, first.Op, first.Value, action, actionValue, string(conditionsJSON), matchType) if err != nil { return 0, err } return res.LastInsertId() } // RemoveRule deletes a rule, scoped to mailboxID (mirrors RemoveAppPassword/RemoveAlias). func (d *DB) RemoveRule(id, mailboxID int64) error { _, err := d.Exec(`DELETE FROM esrv_mailbox_filter_rules WHERE id = ? AND mailbox_id = ?`, id, mailboxID) return err }