Files
aiaa-notification-server/internal/store/channel.go
T
ryan 39f3774940 feat: 配置列表分页与钉钉机器人分钟级排队限流
统一 sources/templates/channels/rules 列表为分页响应,避免配置增多时全量返回;按钉钉 access_token 限制每分钟发送并在超限时等待下一分钟,降低触发官方封禁风险。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 00:34:26 +08:00

97 lines
3.3 KiB
Go

package store
import (
"context"
"encoding/json"
"fmt"
"aiaa-notification-service/internal/model"
)
func (s *Store) CreateChannel(ctx context.Context, ch *model.Channel) error {
configJSON, err := json.Marshal(ch.Config)
if err != nil {
return fmt.Errorf("marshal channel config: %w", err)
}
query := `INSERT INTO notification_channel (name, type, config, status) VALUES (?, ?, ?, ?)`
result, err := s.DB.ExecContext(ctx, query, ch.Name, ch.Type, configJSON, ch.Status)
if err != nil {
return fmt.Errorf("create channel: %w", err)
}
id, _ := result.LastInsertId()
ch.ID = int(id)
return nil
}
func (s *Store) GetChannel(ctx context.Context, id int) (*model.Channel, error) {
var ch model.Channel
var configBytes []byte
row := s.DB.QueryRowContext(ctx, `SELECT id, name, type, config, status, created_at, updated_at FROM notification_channel WHERE id = ?`, id)
if err := row.Scan(&ch.ID, &ch.Name, &ch.Type, &configBytes, &ch.Status, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
return nil, fmt.Errorf("get channel %d: %w", id, err)
}
raw := json.RawMessage(configBytes)
ch.Config = &raw
return &ch, nil
}
func (s *Store) GetChannelByName(ctx context.Context, name string) (*model.Channel, error) {
var ch model.Channel
var configBytes []byte
row := s.DB.QueryRowContext(ctx, `SELECT id, name, type, config, status, created_at, updated_at FROM notification_channel WHERE name = ?`, name)
if err := row.Scan(&ch.ID, &ch.Name, &ch.Type, &configBytes, &ch.Status, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
return nil, fmt.Errorf("get channel by name %s: %w", name, err)
}
raw := json.RawMessage(configBytes)
ch.Config = &raw
return &ch, nil
}
func (s *Store) ListChannels(ctx context.Context, page PageFilter) ([]model.Channel, int, error) {
var count int
if err := s.DB.GetContext(ctx, &count, `SELECT COUNT(*) FROM notification_channel`); err != nil {
return nil, 0, fmt.Errorf("count channels: %w", err)
}
page.Normalize()
rows, err := s.DB.QueryContext(ctx, `SELECT id, name, type, config, status, created_at, updated_at FROM notification_channel ORDER BY id LIMIT ? OFFSET ?`, page.PageSize, page.Offset())
if err != nil {
return nil, 0, fmt.Errorf("list channels: %w", err)
}
defer rows.Close()
channels := make([]model.Channel, 0)
for rows.Next() {
var ch model.Channel
var configBytes []byte
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Type, &configBytes, &ch.Status, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
return nil, 0, fmt.Errorf("scan channel: %w", err)
}
raw := json.RawMessage(configBytes)
ch.Config = &raw
channels = append(channels, ch)
}
return channels, count, rows.Err()
}
func (s *Store) UpdateChannel(ctx context.Context, id int, ch *model.Channel) error {
configJSON, err := json.Marshal(ch.Config)
if err != nil {
return fmt.Errorf("marshal channel config: %w", err)
}
query := `UPDATE notification_channel SET name=?, type=?, config=?, status=? WHERE id=?`
_, err = s.DB.ExecContext(ctx, query, ch.Name, ch.Type, configJSON, ch.Status, id)
if err != nil {
return fmt.Errorf("update channel %d: %w", id, err)
}
return nil
}
func (s *Store) DeleteChannel(ctx context.Context, id int) error {
_, err := s.DB.ExecContext(ctx, `DELETE FROM notification_channel WHERE id = ?`, id)
if err != nil {
return fmt.Errorf("delete channel %d: %w", id, err)
}
return nil
}