Files
digital-psychology/apps/api/internal/repository/crisis_repo.go
T
jackyu66gitandCursor 62cd8c45dd chore: 合入 stash Ops hardening 与 migration 000041
Ask/catalog 权限与审计加固、量表读权限统一,以及未提交的 ops hardening 变更。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 01:46:34 +08:00

103 lines
2.8 KiB
Go

package repository
import (
"context"
"errors"
"strings"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
// CrisisPolicyRow is CrisisCare CrisisPolicy catalog.
type CrisisPolicyRow struct {
ID uuid.UUID `json:"id"`
Code string `json:"code"`
Title string `json:"title"`
Severity string `json:"severity"`
Pattern string `json:"pattern"`
Action string `json:"action"`
HelplineText *string `json:"helpline_text,omitempty"`
Active bool `json:"active"`
System bool `json:"system"`
UpdatedAt time.Time `json:"updated_at"`
}
// CrisisMatch is one evaluate hit.
type CrisisMatch struct {
Code string `json:"code"`
Title string `json:"title"`
Severity string `json:"severity"`
Action string `json:"action"`
HelplineText *string `json:"helpline_text,omitempty"`
}
// ListCrisisPolicies returns policies active-first.
func (r *AdminRepo) ListCrisisPolicies(ctx context.Context) ([]CrisisPolicyRow, error) {
rows, err := r.Pool.Query(ctx, `
SELECT id, code, title, severity, pattern, action, helpline_text, active, system, updated_at
FROM crisis_policies
ORDER BY active DESC, severity DESC, code ASC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []CrisisPolicyRow
for rows.Next() {
var p CrisisPolicyRow
if err := rows.Scan(
&p.ID, &p.Code, &p.Title, &p.Severity, &p.Pattern, &p.Action, &p.HelplineText,
&p.Active, &p.System, &p.UpdatedAt,
); err != nil {
return nil, err
}
out = append(out, p)
}
return out, rows.Err()
}
// GetCrisisPolicy loads one policy.
func (r *AdminRepo) GetCrisisPolicy(ctx context.Context, id uuid.UUID) (*CrisisPolicyRow, error) {
var p CrisisPolicyRow
err := r.Pool.QueryRow(ctx, `
SELECT id, code, title, severity, pattern, action, helpline_text, active, system, updated_at
FROM crisis_policies WHERE id=$1`, id,
).Scan(
&p.ID, &p.Code, &p.Title, &p.Severity, &p.Pattern, &p.Action, &p.HelplineText,
&p.Active, &p.System, &p.UpdatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if err != nil {
return nil, err
}
return &p, nil
}
// EvaluateCrisisPolicies runs substring match preview (ops only).
func (r *AdminRepo) EvaluateCrisisPolicies(ctx context.Context, text string) ([]CrisisMatch, error) {
policies, err := r.ListCrisisPolicies(ctx)
if err != nil {
return nil, err
}
lower := strings.ToLower(text)
var out []CrisisMatch
for _, p := range policies {
if !p.Active || p.Pattern == "" {
continue
}
if strings.Contains(lower, strings.ToLower(p.Pattern)) {
out = append(out, CrisisMatch{
Code: p.Code, Title: p.Title, Severity: p.Severity,
Action: p.Action, HelplineText: p.HelplineText,
})
}
}
if out == nil {
out = []CrisisMatch{}
}
return out, nil
}