| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- package repository
- import (
- "context"
- "database/sql"
- "encoding/json"
- "errors"
- "fmt"
- "github.com/Wei-Shaw/sub2api/internal/service"
- )
- // This predicate is shared by list, detail, history and image reads. Visibility
- // is checked from current settings at request time, never from a cached snapshot.
- const publicIntelligentAccessSQL = `a.deleted_at IS NULL AND s.user_visible
- AND EXISTS(SELECT 1 FROM users u WHERE u.id=$1 AND u.status='active' AND u.deleted_at IS NULL
- AND EXISTS(SELECT 1 FROM account_groups ag JOIN groups g ON g.id=ag.group_id
- WHERE ag.account_id=a.id AND g.deleted_at IS NULL AND g.status='active'
- AND ((NOT g.is_exclusive AND NOT u.restrict_public_groups) OR EXISTS(SELECT 1 FROM user_allowed_groups ug WHERE ug.user_id=u.id AND ug.group_id=g.id))
- AND (g.subscription_type<>'subscription' OR EXISTS(SELECT 1 FROM user_subscriptions us WHERE us.user_id=u.id AND us.group_id=g.id AND us.status='active' AND us.expires_at>NOW() AND us.deleted_at IS NULL))))`
- const publicIntelligentColumns = `t.id,t.account_id,t.test_type,t.status,t.score,t.result,t.result_image,t.duration_ms,t.model,t.created_at,t.finished_at,t.evaluation`
- func scanPublicIntelligent(row intelligentScanner) (*service.PublicAccountTest, error) {
- p := &service.PublicAccountTest{}
- var raw []byte
- err := row.Scan(&p.ID, &p.AccountID, &p.TestType, &p.Status, &p.Score, &p.Result, &p.ResultImage, &p.DurationMS, &p.Model, &p.CreatedAt, &p.FinishedAt, &raw)
- if errors.Is(err, sql.ErrNoRows) {
- return nil, service.ErrIntelligentTestNotFound
- }
- if err == nil {
- var evaluation map[string]any
- if err = json.Unmarshal(raw, &evaluation); err == nil {
- p.Evaluation = service.PublicIntelligentAssessment(evaluation)
- }
- }
- return p, err
- }
- func (r *intelligentTestRepository) PublicGet(ctx context.Context, user, id int64) (*service.PublicAccountTest, error) {
- return scanPublicIntelligent(r.db.QueryRowContext(ctx, `SELECT `+publicIntelligentColumns+` FROM account_tests t JOIN accounts a ON a.id=t.account_id JOIN test_settings s ON s.test_type=t.test_type WHERE `+publicIntelligentAccessSQL+` AND t.id=$2 AND t.status NOT IN ('queued','running')`, user, id))
- }
- func (r *intelligentTestRepository) PublicRecords(ctx context.Context, user int64, f service.IntelligentTestFilter) (*service.PublicAccountTests, error) {
- out := &service.PublicAccountTests{Items: []service.PublicAccountTest{}, Page: f.Page, PageSize: f.PageSize}
- w := &intelligentWhere{parts: []string{publicIntelligentAccessSQL, `t.status NOT IN ('queued','running','cancelled')`}, args: []any{user}}
- if f.AccountID > 0 {
- w.add("t.account_id=$%d", f.AccountID)
- }
- if f.TestType != "" {
- w.add("t.test_type=$%d", f.TestType)
- }
- if f.Status != "" {
- w.add("t.status=$%d", f.Status)
- }
- if f.From != nil {
- w.add("t.created_at >= $%d", *f.From)
- }
- if f.To != nil {
- w.add("t.created_at <= $%d", *f.To)
- }
- base := ` FROM account_tests t JOIN accounts a ON a.id=t.account_id JOIN test_settings s ON s.test_type=t.test_type WHERE ` + w.sql()
- if err := r.db.QueryRowContext(ctx, `SELECT COUNT(*)`+base, w.args...).Scan(&out.Total); err != nil {
- return nil, err
- }
- args := append(append([]any{}, w.args...), f.PageSize, (f.Page-1)*f.PageSize)
- rows, err := r.db.QueryContext(ctx, `SELECT `+publicIntelligentColumns+base+fmt.Sprintf(` ORDER BY t.id DESC LIMIT $%d OFFSET $%d`, len(args)-1, len(args)), args...)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
- for rows.Next() {
- p, err := scanPublicIntelligent(rows)
- if err != nil {
- return nil, err
- }
- out.Items = append(out.Items, *p)
- }
- return out, rows.Err()
- }
- func (r *intelligentTestRepository) Capabilities(ctx context.Context, user int64, f service.IntelligentTestFilter) ([]service.AccountCapability, int64, error) {
- out := []service.AccountCapability{}
- w := &intelligentWhere{parts: []string{publicIntelligentAccessSQL, `t.status NOT IN ('queued','running','cancelled')`}, args: []any{user}}
- if f.AccountID > 0 {
- w.add("a.id=$%d", f.AccountID)
- }
- base := ` FROM account_tests t JOIN accounts a ON a.id=t.account_id JOIN test_settings s ON s.test_type=t.test_type WHERE ` + w.sql()
- var total int64
- if err := r.db.QueryRowContext(ctx, `SELECT COUNT(DISTINCT a.id)`+base, w.args...).Scan(&total); err != nil {
- return nil, 0, err
- }
- args := append(append([]any{}, w.args...), f.PageSize, (f.Page-1)*f.PageSize)
- rows, err := r.db.QueryContext(ctx, `SELECT DISTINCT a.id,a.platform,a.type`+base+fmt.Sprintf(` ORDER BY a.id DESC LIMIT $%d OFFSET $%d`, len(args)-1, len(args)), args...)
- if err != nil {
- return nil, 0, err
- }
- for rows.Next() {
- var item service.AccountCapability
- if err := rows.Scan(&item.AccountID, &item.Platform, &item.AccountType); err != nil {
- rows.Close()
- return nil, 0, err
- }
- item.Tests = []service.PublicAccountTest{}
- out = append(out, item)
- }
- err = rows.Err()
- rows.Close()
- if err != nil {
- return nil, 0, err
- }
- for i := range out {
- query := `SELECT DISTINCT ON(t.test_type) ` + publicIntelligentColumns + base + fmt.Sprintf(` AND a.id=$%d ORDER BY t.test_type,t.id DESC`, len(w.args)+1)
- queryArgs := append(append([]any{}, w.args...), out[i].AccountID)
- tests, err := r.db.QueryContext(ctx, query, queryArgs...)
- if err != nil {
- return nil, 0, err
- }
- for tests.Next() {
- p, err := scanPublicIntelligent(tests)
- if err != nil {
- tests.Close()
- return nil, 0, err
- }
- out[i].Tests = append(out[i].Tests, *p)
- }
- err = tests.Err()
- tests.Close()
- if err != nil {
- return nil, 0, err
- }
- }
- return out, total, nil
- }
|