Files
digital-psychology/apps/api/internal/repository/cms_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

119 lines
3.2 KiB
Go

package repository
import (
"context"
"errors"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
// BannerRow is OpsCMS Banner catalog row.
type BannerRow struct {
ID uuid.UUID `json:"id"`
Code string `json:"code"`
Title string `json:"title"`
Placement string `json:"placement"`
ImageURL *string `json:"image_url,omitempty"`
LinkPath *string `json:"link_path,omitempty"`
SortOrder int `json:"sort_order"`
Active bool `json:"active"`
System bool `json:"system"`
UpdatedAt time.Time `json:"updated_at"`
}
// ListBanners returns banner catalog.
func (r *AdminRepo) ListBanners(ctx context.Context) ([]BannerRow, error) {
rows, err := r.Pool.Query(ctx, `
SELECT id, code, title, placement, image_url, link_path, sort_order, active, system, updated_at
FROM ops_banners
ORDER BY active DESC, sort_order ASC, code ASC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []BannerRow
for rows.Next() {
var b BannerRow
if err := rows.Scan(
&b.ID, &b.Code, &b.Title, &b.Placement, &b.ImageURL, &b.LinkPath,
&b.SortOrder, &b.Active, &b.System, &b.UpdatedAt,
); err != nil {
return nil, err
}
out = append(out, b)
}
return out, rows.Err()
}
// GetBanner loads one banner by id.
func (r *AdminRepo) GetBanner(ctx context.Context, id uuid.UUID) (*BannerRow, error) {
var b BannerRow
err := r.Pool.QueryRow(ctx, `
SELECT id, code, title, placement, image_url, link_path, sort_order, active, system, updated_at
FROM ops_banners WHERE id=$1`, id,
).Scan(
&b.ID, &b.Code, &b.Title, &b.Placement, &b.ImageURL, &b.LinkPath,
&b.SortOrder, &b.Active, &b.System, &b.UpdatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if err != nil {
return nil, err
}
return &b, nil
}
// FeedSlotRow is OpsCMS FeedSlot catalog row.
type FeedSlotRow struct {
ID uuid.UUID `json:"id"`
Code string `json:"code"`
Title string `json:"title"`
SlotKey string `json:"slot_key"`
Placement string `json:"placement"`
Active bool `json:"active"`
System bool `json:"system"`
UpdatedAt time.Time `json:"updated_at"`
}
// ListFeedSlots returns feed slot catalog.
func (r *AdminRepo) ListFeedSlots(ctx context.Context) ([]FeedSlotRow, error) {
rows, err := r.Pool.Query(ctx, `
SELECT id, code, title, slot_key, placement, active, system, updated_at
FROM ops_feed_slots
ORDER BY active DESC, code ASC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []FeedSlotRow
for rows.Next() {
var s FeedSlotRow
if err := rows.Scan(
&s.ID, &s.Code, &s.Title, &s.SlotKey, &s.Placement, &s.Active, &s.System, &s.UpdatedAt,
); err != nil {
return nil, err
}
out = append(out, s)
}
return out, rows.Err()
}
// GetFeedSlot loads one feed slot by id.
func (r *AdminRepo) GetFeedSlot(ctx context.Context, id uuid.UUID) (*FeedSlotRow, error) {
var s FeedSlotRow
err := r.Pool.QueryRow(ctx, `
SELECT id, code, title, slot_key, placement, active, system, updated_at
FROM ops_feed_slots WHERE id=$1`, id,
).Scan(&s.ID, &s.Code, &s.Title, &s.SlotKey, &s.Placement, &s.Active, &s.System, &s.UpdatedAt)
if errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if err != nil {
return nil, err
}
return &s, nil
}