1package database
2
3import (
4 "context"
5 "strings"
6
7 "github.com/charmbracelet/soft-serve/pkg/access"
8 "github.com/charmbracelet/soft-serve/pkg/db"
9 "github.com/charmbracelet/soft-serve/pkg/db/models"
10 "github.com/charmbracelet/soft-serve/pkg/store"
11 "github.com/charmbracelet/soft-serve/pkg/utils"
12)
13
14type collabStore struct{}
15
16var _ store.CollaboratorStore = (*collabStore)(nil)
17
18// AddCollabByUsernameAndRepo implements store.CollaboratorStore.
19func (*collabStore) AddCollabByUsernameAndRepo(ctx context.Context, tx db.Handler, username string, repo string, level access.AccessLevel) error {
20 username = strings.ToLower(username)
21 if err := utils.ValidateUsername(username); err != nil {
22 return err //nolint:wrapcheck
23 }
24
25 repo = utils.SanitizeRepo(repo)
26
27 query := tx.Rebind(`INSERT INTO collabs (access_level, user_id, repo_id, updated_at)
28 VALUES (
29 ?,
30 (
31 SELECT id FROM users WHERE username = ?
32 ),
33 (
34 SELECT id FROM repos WHERE name = ?
35 ),
36 CURRENT_TIMESTAMP
37 );`)
38 _, err := tx.ExecContext(ctx, query, level, username, repo)
39 return err //nolint:wrapcheck
40}
41
42// GetCollabByUsernameAndRepo implements store.CollaboratorStore.
43func (*collabStore) GetCollabByUsernameAndRepo(ctx context.Context, tx db.Handler, username string, repo string) (models.Collab, error) {
44 var m models.Collab
45
46 username = strings.ToLower(username)
47 if err := utils.ValidateUsername(username); err != nil {
48 return models.Collab{}, err //nolint:wrapcheck
49 }
50
51 repo = utils.SanitizeRepo(repo)
52
53 err := tx.GetContext(ctx, &m, tx.Rebind(`
54 SELECT
55 collabs.*
56 FROM
57 collabs
58 INNER JOIN users ON users.id = collabs.user_id
59 INNER JOIN repos ON repos.id = collabs.repo_id
60 WHERE
61 users.username = ? AND repos.name = ?
62 `), username, repo)
63
64 return m, err //nolint:wrapcheck
65}
66
67// ListCollabsByRepo implements store.CollaboratorStore.
68func (*collabStore) ListCollabsByRepo(ctx context.Context, tx db.Handler, repo string) ([]models.Collab, error) {
69 var m []models.Collab
70
71 repo = utils.SanitizeRepo(repo)
72 query := tx.Rebind(`
73 SELECT
74 collabs.*
75 FROM
76 collabs
77 INNER JOIN repos ON repos.id = collabs.repo_id
78 WHERE
79 repos.name = ?
80 `)
81
82 err := tx.SelectContext(ctx, &m, query, repo)
83 return m, err //nolint:wrapcheck
84}
85
86// ListCollabsByRepoAsUsers implements store.CollaboratorStore.
87func (*collabStore) ListCollabsByRepoAsUsers(ctx context.Context, tx db.Handler, repo string) ([]models.User, error) {
88 var m []models.User
89
90 repo = utils.SanitizeRepo(repo)
91 query := tx.Rebind(`
92 SELECT
93 users.*
94 FROM
95 users
96 INNER JOIN collabs ON collabs.user_id = users.id
97 INNER JOIN repos ON repos.id = collabs.repo_id
98 WHERE
99 repos.name = ?
100 `)
101
102 err := tx.SelectContext(ctx, &m, query, repo)
103 return m, err //nolint:wrapcheck
104}
105
106// RemoveCollabByUsernameAndRepo implements store.CollaboratorStore.
107func (*collabStore) RemoveCollabByUsernameAndRepo(ctx context.Context, tx db.Handler, username string, repo string) error {
108 username = strings.ToLower(username)
109 if err := utils.ValidateUsername(username); err != nil {
110 return err //nolint:wrapcheck
111 }
112
113 repo = utils.SanitizeRepo(repo)
114 query := tx.Rebind(`
115 DELETE FROM
116 collabs
117 WHERE
118 user_id = (
119 SELECT id FROM users WHERE username = ?
120 ) AND repo_id = (
121 SELECT id FROM repos WHERE name = ?
122 )
123 `)
124 _, err := tx.ExecContext(ctx, query, username, repo)
125 return err //nolint:wrapcheck
126}