chore: initial commit of ai site platform

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-07-31 10:31:17 +08:00
commit 4ca82fb58a
203 changed files with 45745 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
package audit
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"sync"
"time"
)
type Entry struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
Action string `json:"action"`
Detail string `json:"detail"`
CreatedAt time.Time `json:"created_at"`
}
type Store interface {
Log(ctx context.Context, tenantID, userID int64, action, detail string) error
List(ctx context.Context, tenantID int64, limit, offset int) ([]Entry, int, error)
}
type MemoryStore struct {
mu sync.Mutex
seq int64
rows []Entry
}
func NewMemoryStore() *MemoryStore {
return &MemoryStore{}
}
func (s *MemoryStore) Log(_ context.Context, tenantID, userID int64, action, detail string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.seq++
s.rows = append(s.rows, Entry{
ID: s.seq, TenantID: tenantID, UserID: userID,
Action: action, Detail: detail, CreatedAt: time.Now().UTC(),
})
return nil
}
func (s *MemoryStore) List(_ context.Context, tenantID int64, limit, offset int) ([]Entry, int, error) {
s.mu.Lock()
defer s.mu.Unlock()
if limit <= 0 {
limit = 50
}
filtered := make([]Entry, 0)
for i := len(s.rows) - 1; i >= 0; i-- {
if s.rows[i].TenantID == tenantID {
filtered = append(filtered, s.rows[i])
}
}
total := len(filtered)
if offset >= total {
return []Entry{}, total, nil
}
end := offset + limit
if end > total {
end = total
}
return filtered[offset:end], total, nil
}
type PostgresStore struct {
DB *sql.DB
}
func NewPostgresStore(db *sql.DB) *PostgresStore {
return &PostgresStore{DB: db}
}
func (s *PostgresStore) Log(ctx context.Context, tenantID, userID int64, action, detail string) error {
_, err := s.DB.ExecContext(ctx, `
INSERT INTO platform_meta.audit_logs(tenant_id, user_id, action, detail)
VALUES($1,$2,$3,$4)`, tenantID, userID, action, detail)
return err
}
func (s *PostgresStore) List(ctx context.Context, tenantID int64, limit, offset int) ([]Entry, int, error) {
if limit <= 0 {
limit = 50
}
var total int
if err := s.DB.QueryRowContext(ctx,
`SELECT COUNT(1) FROM platform_meta.audit_logs WHERE tenant_id=$1`, tenantID,
).Scan(&total); err != nil {
return nil, 0, err
}
rows, err := s.DB.QueryContext(ctx, `
SELECT id, tenant_id, user_id, action, detail, created_at
FROM platform_meta.audit_logs
WHERE tenant_id=$1
ORDER BY id DESC
LIMIT $2 OFFSET $3`, tenantID, limit, offset)
if err != nil {
return nil, 0, err
}
defer rows.Close()
out := make([]Entry, 0)
for rows.Next() {
var e Entry
if err := rows.Scan(&e.ID, &e.TenantID, &e.UserID, &e.Action, &e.Detail, &e.CreatedAt); err != nil {
return nil, 0, err
}
out = append(out, e)
}
return out, total, rows.Err()
}
func DetailJSON(v any) string {
b, err := json.Marshal(v)
if err != nil {
return fmt.Sprint(v)
}
return string(b)
}