feat: P1 合盘/星座/问答与测测完整设计包及模拟器取证工具
落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
const imageCardDailyFree = 3
|
||||
|
||||
// ImageCardRepo tracks daily draw quotas.
|
||||
type ImageCardRepo struct {
|
||||
Pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
// UsedToday returns how many free draws used today.
|
||||
func (r *ImageCardRepo) UsedToday(ctx context.Context, userID uuid.UUID, day time.Time) (int, error) {
|
||||
var n int
|
||||
err := r.Pool.QueryRow(ctx, `
|
||||
SELECT used FROM image_card_quotas
|
||||
WHERE user_id=$1 AND day=$2::date`,
|
||||
userID, day.Format("2006-01-02"),
|
||||
).Scan(&n)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return 0, nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// TryConsume increments today's used count when under free limit.
|
||||
// Returns remaining after consume. ErrQuotaExhausted when free tier is out.
|
||||
func (r *ImageCardRepo) TryConsume(ctx context.Context, userID uuid.UUID, day time.Time) (remaining int, err error) {
|
||||
dayStr := day.Format("2006-01-02")
|
||||
var used int
|
||||
err = r.Pool.QueryRow(ctx, `
|
||||
INSERT INTO image_card_quotas(user_id, day, used)
|
||||
VALUES ($1, $2::date, 1)
|
||||
ON CONFLICT (user_id, day) DO UPDATE
|
||||
SET used = image_card_quotas.used + 1
|
||||
WHERE image_card_quotas.used < $3
|
||||
RETURNING used`,
|
||||
userID, dayStr, imageCardDailyFree,
|
||||
).Scan(&used)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return 0, ErrQuotaExhausted
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return imageCardDailyFree - used, nil
|
||||
}
|
||||
|
||||
// RemainingToday without consuming.
|
||||
func (r *ImageCardRepo) RemainingToday(ctx context.Context, userID uuid.UUID, day time.Time, unlimited bool) (int, error) {
|
||||
if unlimited {
|
||||
return 99, nil
|
||||
}
|
||||
used, err := r.UsedToday(ctx, userID, day)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
left := imageCardDailyFree - used
|
||||
if left < 0 {
|
||||
left = 0
|
||||
}
|
||||
return left, nil
|
||||
}
|
||||
|
||||
// DailyFreeLimit is the free-tier cap.
|
||||
func DailyFreeLimit() int { return imageCardDailyFree }
|
||||
|
||||
// ErrQuotaExhausted means free daily draws are used up.
|
||||
var ErrQuotaExhausted = errors.New("今日免费次数已用完")
|
||||
Reference in New Issue
Block a user