feat: add redeem code affiliate rebate, batch concurrency API, and markdown page rendering

1. Redeem code affiliate rebate: balance-type redeem codes now trigger
   invite rebate for the inviter. Payment fulfillment uses context key
   to prevent double-rebate.

2. Batch concurrency update: new POST /admin/users/batch-concurrency
   endpoint supporting mode=set/add with all=true for all users.

3. Markdown page rendering: new GET /api/v1/pages/:slug API serves local
   .md files. Custom menu items with url="md:slug" render markdown with
   collapsible TOC sidebar, scroll spy, and copy buttons on code blocks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael-Jetson
2026-05-05 02:42:56 -07:00
parent a1106e8167
commit 4cbd4932a0
25 changed files with 666 additions and 18 deletions

View File

@@ -737,6 +737,37 @@ func (r *userRepository) UpdateConcurrency(ctx context.Context, id int64, amount
return nil
}
func (r *userRepository) BatchSetConcurrency(ctx context.Context, userIDs []int64, value int) (int, error) {
if len(userIDs) == 0 {
return 0, nil
}
if value < 0 {
value = 0
}
res, err := r.sql.ExecContext(ctx,
"UPDATE users SET concurrency = $1, updated_at = NOW() WHERE id = ANY($2) AND deleted_at IS NULL",
value, pq.Array(userIDs))
if err != nil {
return 0, fmt.Errorf("batch set concurrency: %w", err)
}
affected, _ := res.RowsAffected()
return int(affected), nil
}
func (r *userRepository) BatchAddConcurrency(ctx context.Context, userIDs []int64, delta int) (int, error) {
if len(userIDs) == 0 {
return 0, nil
}
res, err := r.sql.ExecContext(ctx,
"UPDATE users SET concurrency = GREATEST(concurrency + $1, 0), updated_at = NOW() WHERE id = ANY($2) AND deleted_at IS NULL",
delta, pq.Array(userIDs))
if err != nil {
return 0, fmt.Errorf("batch add concurrency: %w", err)
}
affected, _ := res.RowsAffected()
return int(affected), nil
}
func (r *userRepository) ExistsByEmail(ctx context.Context, email string) (bool, error) {
return r.client.User.Query().Where(userEmailLookupPredicate(email)).Exist(ctx)
}