internal/store/teams.go

4bfcb3893d5ad29d5c6ba0725fd2291d20003e30
gitbay/internal/store/teams.go history · blame · raw

151 lines · 3777 bytes

  1package store
  2
  3import (
  4	"database/sql"
  5	"errors"
  6	"fmt"
  7)
  8
  9type Team struct {
 10	ID    int64
 11	OrgID int64
 12	Name  string
 13}
 14
 15func (s *Store) CreateTeam(orgID int64, name string) (int64, error) {
 16	res, err := s.DB.Exec("INSERT INTO teams (org_id, name) VALUES (?, ?)", orgID, name)
 17	if err != nil {
 18		if isUniqueErr(err) {
 19			return 0, fmt.Errorf("team %q already exists", name)
 20		}
 21		return 0, err
 22	}
 23	return res.LastInsertId()
 24}
 25
 26func (s *Store) TeamByName(orgID int64, name string) (Team, error) {
 27	var t Team
 28	err := s.DB.QueryRow("SELECT id, org_id, name FROM teams WHERE org_id = ? AND name = ?",
 29		orgID, name).Scan(&t.ID, &t.OrgID, &t.Name)
 30	if errors.Is(err, sql.ErrNoRows) {
 31		return t, ErrNotFound
 32	}
 33	return t, err
 34}
 35
 36func (s *Store) DeleteTeam(teamID int64) error {
 37	res, err := s.DB.Exec("DELETE FROM teams WHERE id = ?", teamID)
 38	if err != nil {
 39		return err
 40	}
 41	if n, _ := res.RowsAffected(); n == 0 {
 42		return ErrNotFound
 43	}
 44	return nil
 45}
 46
 47func (s *Store) ListTeams(orgID int64) ([]Team, error) {
 48	rows, err := s.DB.Query("SELECT id, org_id, name FROM teams WHERE org_id = ? ORDER BY name", orgID)
 49	if err != nil {
 50		return nil, err
 51	}
 52	defer rows.Close()
 53	var out []Team
 54	for rows.Next() {
 55		var t Team
 56		if err := rows.Scan(&t.ID, &t.OrgID, &t.Name); err != nil {
 57			return nil, err
 58		}
 59		out = append(out, t)
 60	}
 61	return out, rows.Err()
 62}
 63
 64func (s *Store) AddTeamMember(teamID, userID int64) error {
 65	_, err := s.DB.Exec(
 66		"INSERT INTO team_members (team_id, user_id) VALUES (?, ?) ON CONFLICT DO NOTHING",
 67		teamID, userID)
 68	return err
 69}
 70
 71func (s *Store) RemoveTeamMember(teamID, userID int64) error {
 72	res, err := s.DB.Exec("DELETE FROM team_members WHERE team_id = ? AND user_id = ?", teamID, userID)
 73	if err != nil {
 74		return err
 75	}
 76	if n, _ := res.RowsAffected(); n == 0 {
 77		return ErrNotFound
 78	}
 79	return nil
 80}
 81
 82func (s *Store) TeamMembers(teamID int64) ([]string, error) {
 83	rows, err := s.DB.Query(`
 84		SELECT u.username FROM team_members tm JOIN users u ON u.id = tm.user_id
 85		WHERE tm.team_id = ? ORDER BY u.username`, teamID)
 86	if err != nil {
 87		return nil, err
 88	}
 89	defer rows.Close()
 90	var out []string
 91	for rows.Next() {
 92		var n string
 93		if err := rows.Scan(&n); err != nil {
 94			return nil, err
 95		}
 96		out = append(out, n)
 97	}
 98	return out, rows.Err()
 99}
100
101// GrantTeamRepo attaches (or updates) a team's role on a repo.
102func (s *Store) GrantTeamRepo(teamID, repoID int64, role string) error {
103	_, err := s.DB.Exec(`
104		INSERT INTO team_repos (team_id, repo_id, role) VALUES (?, ?, ?)
105		ON CONFLICT (team_id, repo_id) DO UPDATE SET role = excluded.role`,
106		teamID, repoID, role)
107	return err
108}
109
110func (s *Store) RevokeTeamRepo(teamID, repoID int64) error {
111	res, err := s.DB.Exec("DELETE FROM team_repos WHERE team_id = ? AND repo_id = ?", teamID, repoID)
112	if err != nil {
113		return err
114	}
115	if n, _ := res.RowsAffected(); n == 0 {
116		return ErrNotFound
117	}
118	return nil
119}
120
121type TeamGrant struct {
122	RepoPath string `json:"repo"`
123	Role     string `json:"role"`
124}
125
126func (s *Store) TeamGrants(teamID int64) ([]TeamGrant, error) {
127	rows, err := s.DB.Query(`
128		SELECT COALESCE(u.username, o.name) || '/' || r.name, tr.role
129		FROM team_repos tr JOIN repos r ON r.id = tr.repo_id
130		LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id
131		LEFT JOIN orgs  o ON r.owner_kind = 'org'  AND o.id = r.owner_id
132		WHERE tr.team_id = ? ORDER BY 1`, teamID)
133	if err != nil {
134		return nil, err
135	}
136	defer rows.Close()
137	var out []TeamGrant
138	for rows.Next() {
139		var g TeamGrant
140		if err := rows.Scan(&g.RepoPath, &g.Role); err != nil {
141			return nil, err
142		}
143		out = append(out, g)
144	}
145	return out, rows.Err()
146}
147
148func (s *Store) SetOrgMembersRole(orgID int64, role string) error {
149	_, err := s.DB.Exec("UPDATE orgs SET members_role = ? WHERE id = ?", role, orgID)
150	return err
151}