internal/store/quotas.go

3bcdce33fb9a2309312854331359d376171c7368
gitbay/internal/store/quotas.go history · blame · raw

82 lines · 2046 bytes

 1package store
 2
 3import (
 4	"database/sql"
 5	"time"
 6)
 7
 8// UserLimits is an account's quota overrides; nil means the configured
 9// default applies.
10type UserLimits struct {
11	Repos *int64
12	Bytes *int64
13}
14
15func (s *Store) UserLimits(userID int64) (UserLimits, error) {
16	var repos, bytes sql.NullInt64
17	err := s.DB.QueryRow("SELECT repo_limit, byte_limit FROM users WHERE id = ?", userID).Scan(&repos, &bytes)
18	if err != nil {
19		return UserLimits{}, err
20	}
21	var l UserLimits
22	if repos.Valid {
23		l.Repos = &repos.Int64
24	}
25	if bytes.Valid {
26		l.Bytes = &bytes.Int64
27	}
28	return l, nil
29}
30
31// SetUserLimits writes the overrides; a nil field clears back to default.
32func (s *Store) SetUserLimits(userID int64, l UserLimits) error {
33	var repos, bytes any
34	if l.Repos != nil {
35		repos = *l.Repos
36	}
37	if l.Bytes != nil {
38		bytes = *l.Bytes
39	}
40	res, err := s.DB.Exec("UPDATE users SET repo_limit = ?, byte_limit = ? WHERE id = ?", repos, bytes, userID)
41	if err != nil {
42		return err
43	}
44	if n, _ := res.RowsAffected(); n == 0 {
45		return ErrNotFound
46	}
47	return nil
48}
49
50// ReapPendingUsers deletes self-registered accounts still unverified
51// after maxAge. A pending account owns nothing (it cannot create a
52// repository before verifying), so DeleteUser has nothing to refuse; an
53// account that somehow anchors content is left alone and reported.
54func (s *Store) ReapPendingUsers(maxAge time.Duration) ([]string, error) {
55	cutoff := fmtTime(time.Now().Add(-maxAge))
56	rows, err := s.DB.Query("SELECT id, username FROM users WHERE pending = 1 AND created_at < ?", cutoff)
57	if err != nil {
58		return nil, err
59	}
60	type row struct {
61		id   int64
62		name string
63	}
64	var stale []row
65	for rows.Next() {
66		var r row
67		if err := rows.Scan(&r.id, &r.name); err != nil {
68			rows.Close()
69			return nil, err
70		}
71		stale = append(stale, r)
72	}
73	rows.Close()
74	var removed []string
75	for _, r := range stale {
76		if err := s.DeleteUser(r.id); err == nil {
77			removed = append(removed, r.name)
78			s.Audit(0, "pending.expired", map[string]any{"user": r.name})
79		}
80	}
81	return removed, nil
82}