first commit
This commit is contained in:
115
internal/user/repo_query.go
Normal file
115
internal/user/repo_query.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ListFilter struct {
|
||||
ActiveOnly bool
|
||||
Search string
|
||||
Limit int
|
||||
}
|
||||
|
||||
func (r *Repo) List(ctx context.Context, f ListFilter) ([]*User, error) {
|
||||
q := `SELECT ` + userCols + ` FROM users WHERE 1=1`
|
||||
args := []any{}
|
||||
if f.ActiveOnly {
|
||||
q += ` AND is_active = 1`
|
||||
}
|
||||
if f.Search != "" {
|
||||
q += ` AND (username LIKE ? COLLATE NOCASE OR pubkey LIKE ?)`
|
||||
args = append(args, "%"+f.Search+"%", "%"+f.Search+"%")
|
||||
}
|
||||
q += ` ORDER BY created_at DESC`
|
||||
if f.Limit > 0 {
|
||||
q += ` LIMIT ?`
|
||||
args = append(args, f.Limit)
|
||||
}
|
||||
rows, err := r.db.QueryContext(ctx, q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.collect(rows)
|
||||
}
|
||||
|
||||
func (r *Repo) ActiveByName(ctx context.Context) (map[string]string, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `SELECT username, pubkey FROM users WHERE is_active = 1`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
out := map[string]string{}
|
||||
for rows.Next() {
|
||||
var u, p string
|
||||
if err := rows.Scan(&u, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[u] = p
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repo) collect(rows interface {
|
||||
Next() bool
|
||||
Scan(...any) error
|
||||
Err() error
|
||||
Close() error
|
||||
}) ([]*User, error) {
|
||||
defer rows.Close()
|
||||
out := []*User{}
|
||||
for rows.Next() {
|
||||
u, err := scanUser(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, u)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repo) ListPendingReminders(ctx context.Context, days int, now time.Time) ([]*User, error) {
|
||||
low := now.Add(time.Duration(days)*24*time.Hour - 12*time.Hour).UTC().Format(time.RFC3339)
|
||||
high := now.Add(time.Duration(days)*24*time.Hour + 12*time.Hour).UTC().Format(time.RFC3339)
|
||||
rows, err := r.db.QueryContext(ctx, `SELECT `+userCols+` FROM users
|
||||
WHERE is_active = 1
|
||||
AND subscription_type = 'yearly'
|
||||
AND expires_at BETWEEN ? AND ?
|
||||
AND (expiring_reminder_sent_at IS NULL OR expiring_reminder_sent_at < ?)`,
|
||||
low, high, now.Add(-23*time.Hour).UTC().Format(time.RFC3339))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.collect(rows)
|
||||
}
|
||||
|
||||
func (r *Repo) ListExpired(ctx context.Context, now time.Time) ([]*User, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `SELECT `+userCols+` FROM users
|
||||
WHERE is_active = 1 AND subscription_type = 'yearly' AND expires_at < ?`,
|
||||
now.UTC().Format(time.RFC3339))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.collect(rows)
|
||||
}
|
||||
|
||||
func (r *Repo) ListGraceExpired(ctx context.Context, cutoff time.Time) ([]*User, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `SELECT `+userCols+` FROM users
|
||||
WHERE is_active = 0 AND deactivated_at IS NOT NULL AND deactivated_at < ?`,
|
||||
cutoff.UTC().Format(time.RFC3339))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.collect(rows)
|
||||
}
|
||||
|
||||
func (r *Repo) ListForSync(ctx context.Context, staleBefore time.Time) ([]*User, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `SELECT `+userCols+` FROM users
|
||||
WHERE is_active = 1 AND manual_username = 0
|
||||
AND (last_synced_at IS NULL OR last_synced_at < ?)`,
|
||||
staleBefore.UTC().Format(time.RFC3339))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.collect(rows)
|
||||
}
|
||||
Reference in New Issue
Block a user