collab.go

  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.ValidateHandle(username); err != nil {
 22		return err
 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 handle_id = (
 32						SELECT id FROM handles WHERE handle = ?
 33					)
 34				),
 35				(
 36					SELECT id FROM repos WHERE name = ?
 37				),
 38				CURRENT_TIMESTAMP
 39			);`)
 40	_, err := tx.ExecContext(ctx, query, level, username, repo)
 41	return err
 42}
 43
 44// GetCollabByUsernameAndRepo implements store.CollaboratorStore.
 45func (*collabStore) GetCollabByUsernameAndRepo(ctx context.Context, tx db.Handler, username string, repo string) (models.Collab, error) {
 46	var m models.Collab
 47
 48	username = strings.ToLower(username)
 49	if err := utils.ValidateHandle(username); err != nil {
 50		return models.Collab{}, err
 51	}
 52
 53	repo = utils.SanitizeRepo(repo)
 54
 55	err := tx.GetContext(ctx, &m, tx.Rebind(`
 56		SELECT
 57			collabs.*
 58		FROM
 59			collabs
 60		INNER JOIN users ON users.id = collabs.user_id
 61		INNER JOIN handles ON handles.id = users.handle_id
 62		INNER JOIN repos ON repos.id = collabs.repo_id
 63		WHERE
 64			handles.handle = ? AND repos.name = ?
 65	`), username, repo)
 66
 67	return m, err
 68}
 69
 70// ListCollabsByRepo implements store.CollaboratorStore.
 71func (*collabStore) ListCollabsByRepo(ctx context.Context, tx db.Handler, repo string) ([]models.Collab, error) {
 72	var m []models.Collab
 73
 74	repo = utils.SanitizeRepo(repo)
 75	query := tx.Rebind(`
 76		SELECT
 77			collabs.*
 78		FROM
 79			collabs
 80		INNER JOIN repos ON repos.id = collabs.repo_id
 81		WHERE
 82			repos.name = ?
 83	`)
 84
 85	err := tx.SelectContext(ctx, &m, query, repo)
 86	return m, err
 87}
 88
 89// ListCollabsByRepoAsUsers implements store.CollaboratorStore.
 90func (*collabStore) ListCollabsByRepoAsUsers(ctx context.Context, tx db.Handler, repo string) ([]models.User, error) {
 91	var m []models.User
 92
 93	repo = utils.SanitizeRepo(repo)
 94	query := tx.Rebind(`
 95		SELECT
 96			users.*
 97		FROM
 98			users
 99		INNER JOIN collabs ON collabs.user_id = users.id
100		INNER JOIN repos ON repos.id = collabs.repo_id
101		WHERE
102			repos.name = ?
103	`)
104
105	err := tx.SelectContext(ctx, &m, query, repo)
106	return m, err
107}
108
109// RemoveCollabByUsernameAndRepo implements store.CollaboratorStore.
110func (*collabStore) RemoveCollabByUsernameAndRepo(ctx context.Context, tx db.Handler, username string, repo string) error {
111	username = strings.ToLower(username)
112	if err := utils.ValidateHandle(username); err != nil {
113		return err
114	}
115
116	repo = utils.SanitizeRepo(repo)
117	query := tx.Rebind(`
118		DELETE FROM
119			collabs
120		WHERE
121			user_id = (
122				SELECT id FROM users WHERE handle_id = (
123					SELECT id FROM handles WHERE handle = ?
124				)
125			) AND repo_id = (
126				SELECT id FROM repos WHERE name = ?
127			)
128	`)
129	_, err := tx.ExecContext(ctx, query, username, repo)
130	return err
131}