package mail import ( "context" "encoding/json" "errors" "github.com/jackc/pgx/v5" "github.com/ultisuite/ulti-backend/internal/mail/rules" ) func (s *Service) SimulateRule(ctx context.Context, externalID string, req *simulateRuleRequest) (any, error) { msg := &rules.Message{ ID: "simulation", From: req.Message.From, To: req.Message.To, Subject: req.Message.Subject, BodyText: req.Message.BodyText, HasAttachments: req.Message.HasAttachments, Labels: req.Message.Labels, } engine := rules.NewEngine(s.db) wf, conditions, actions, err := s.resolveSimulateRulePayload(ctx, externalID, req) if err != nil { return nil, err } if wf != nil && len(wf.Nodes) > 0 { var userID string _ = s.db.QueryRow(ctx, `SELECT id FROM users WHERE external_id = $1`, externalID).Scan(&userID) return engine.SimulateWorkflow(ctx, userID, wf, msg, &rules.EventContext{Type: rules.TriggerMessageReceived}), nil } return engine.SimulateRule(ctx, conditions, actions, msg), nil } func (s *Service) resolveSimulateRulePayload(ctx context.Context, externalID string, req *simulateRuleRequest) (*rules.Workflow, []rules.Condition, []rules.Action, error) { if req.RuleID != "" { var condJSON, actJSON, wfJSON []byte err := s.db.QueryRow(ctx, ` SELECT conditions, actions, workflow FROM mail_rules WHERE id = $1 AND user_id = (SELECT id FROM users WHERE external_id = $2) `, req.RuleID, externalID).Scan(&condJSON, &actJSON, &wfJSON) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, nil, nil, ErrNotFound } return nil, nil, nil, err } wf, err := rules.ParseWorkflow(wfJSON) if err != nil { return nil, nil, nil, err } if wf != nil && len(wf.Nodes) > 0 { return wf, nil, nil, nil } conditions, actions, err := unmarshalRuleConditionsActions(condJSON, actJSON) return nil, conditions, actions, err } if req.Rule.Workflow != nil { wfJSON, err := json.Marshal(req.Rule.Workflow) if err != nil { return nil, nil, nil, err } wf, err := rules.ParseWorkflow(wfJSON) if err != nil { return nil, nil, nil, err } if wf != nil && len(wf.Nodes) > 0 { return wf, nil, nil, nil } } condJSON, err := json.Marshal(req.Rule.Conditions) if err != nil { return nil, nil, nil, err } actJSON, err := json.Marshal(req.Rule.Actions) if err != nil { return nil, nil, nil, err } conditions, actions, err := unmarshalRuleConditionsActions(condJSON, actJSON) return nil, conditions, actions, err } func unmarshalRuleConditionsActions(condJSON, actJSON []byte) ([]rules.Condition, []rules.Action, error) { var conditions []rules.Condition var actions []rules.Action if err := json.Unmarshal(condJSON, &conditions); err != nil { return nil, nil, err } if err := json.Unmarshal(actJSON, &actions); err != nil { return nil, nil, err } return conditions, actions, nil }