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