forked from wrenn/wrenn
Admin panel now includes a Teams page with paginated listing of all teams (including soft-deleted), BYOC enable with confirmation dialog, and team deletion with active capsule warnings. Shows member count, owner info, active capsules, and channel count per team.
410 lines
10 KiB
Go
410 lines
10 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: teams.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const countTeamsAdmin = `-- name: CountTeamsAdmin :one
|
|
SELECT COUNT(*)::int AS total
|
|
FROM teams
|
|
WHERE id != '00000000-0000-0000-0000-000000000000'
|
|
`
|
|
|
|
func (q *Queries) CountTeamsAdmin(ctx context.Context) (int32, error) {
|
|
row := q.db.QueryRow(ctx, countTeamsAdmin)
|
|
var total int32
|
|
err := row.Scan(&total)
|
|
return total, err
|
|
}
|
|
|
|
const deleteTeamMember = `-- name: DeleteTeamMember :exec
|
|
DELETE FROM users_teams WHERE team_id = $1 AND user_id = $2
|
|
`
|
|
|
|
type DeleteTeamMemberParams struct {
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
}
|
|
|
|
func (q *Queries) DeleteTeamMember(ctx context.Context, arg DeleteTeamMemberParams) error {
|
|
_, err := q.db.Exec(ctx, deleteTeamMember, arg.TeamID, arg.UserID)
|
|
return err
|
|
}
|
|
|
|
const getBYOCTeams = `-- name: GetBYOCTeams :many
|
|
SELECT id, name, slug, is_byoc, created_at, deleted_at FROM teams WHERE is_byoc = TRUE AND deleted_at IS NULL ORDER BY created_at
|
|
`
|
|
|
|
func (q *Queries) GetBYOCTeams(ctx context.Context) ([]Team, error) {
|
|
rows, err := q.db.Query(ctx, getBYOCTeams)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Team
|
|
for rows.Next() {
|
|
var i Team
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getDefaultTeamForUser = `-- name: GetDefaultTeamForUser :one
|
|
SELECT t.id, t.name, t.slug, t.is_byoc, t.created_at, t.deleted_at FROM teams t
|
|
JOIN users_teams ut ON ut.team_id = t.id
|
|
WHERE ut.user_id = $1 AND ut.is_default = TRUE AND t.deleted_at IS NULL
|
|
LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetDefaultTeamForUser(ctx context.Context, userID pgtype.UUID) (Team, error) {
|
|
row := q.db.QueryRow(ctx, getDefaultTeamForUser, userID)
|
|
var i Team
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getTeam = `-- name: GetTeam :one
|
|
SELECT id, name, slug, is_byoc, created_at, deleted_at FROM teams WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) GetTeam(ctx context.Context, id pgtype.UUID) (Team, error) {
|
|
row := q.db.QueryRow(ctx, getTeam, id)
|
|
var i Team
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getTeamBySlug = `-- name: GetTeamBySlug :one
|
|
SELECT id, name, slug, is_byoc, created_at, deleted_at FROM teams WHERE slug = $1 AND deleted_at IS NULL
|
|
`
|
|
|
|
func (q *Queries) GetTeamBySlug(ctx context.Context, slug string) (Team, error) {
|
|
row := q.db.QueryRow(ctx, getTeamBySlug, slug)
|
|
var i Team
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getTeamMembers = `-- name: GetTeamMembers :many
|
|
SELECT u.id, u.name, u.email, ut.role, ut.created_at AS joined_at
|
|
FROM users_teams ut
|
|
JOIN users u ON u.id = ut.user_id
|
|
WHERE ut.team_id = $1
|
|
ORDER BY ut.created_at
|
|
`
|
|
|
|
type GetTeamMembersRow struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
Role string `json:"role"`
|
|
JoinedAt pgtype.Timestamptz `json:"joined_at"`
|
|
}
|
|
|
|
func (q *Queries) GetTeamMembers(ctx context.Context, teamID pgtype.UUID) ([]GetTeamMembersRow, error) {
|
|
rows, err := q.db.Query(ctx, getTeamMembers, teamID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTeamMembersRow
|
|
for rows.Next() {
|
|
var i GetTeamMembersRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Email,
|
|
&i.Role,
|
|
&i.JoinedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getTeamMembership = `-- name: GetTeamMembership :one
|
|
SELECT user_id, team_id, is_default, role, created_at FROM users_teams WHERE user_id = $1 AND team_id = $2
|
|
`
|
|
|
|
type GetTeamMembershipParams struct {
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
}
|
|
|
|
func (q *Queries) GetTeamMembership(ctx context.Context, arg GetTeamMembershipParams) (UsersTeam, error) {
|
|
row := q.db.QueryRow(ctx, getTeamMembership, arg.UserID, arg.TeamID)
|
|
var i UsersTeam
|
|
err := row.Scan(
|
|
&i.UserID,
|
|
&i.TeamID,
|
|
&i.IsDefault,
|
|
&i.Role,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getTeamsForUser = `-- name: GetTeamsForUser :many
|
|
SELECT t.id, t.name, t.slug, t.is_byoc, t.created_at, t.deleted_at, ut.role
|
|
FROM teams t
|
|
JOIN users_teams ut ON ut.team_id = t.id
|
|
WHERE ut.user_id = $1 AND t.deleted_at IS NULL
|
|
ORDER BY ut.created_at
|
|
`
|
|
|
|
type GetTeamsForUserRow struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
Slug string `json:"slug"`
|
|
IsByoc bool `json:"is_byoc"`
|
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
|
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
func (q *Queries) GetTeamsForUser(ctx context.Context, userID pgtype.UUID) ([]GetTeamsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, getTeamsForUser, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTeamsForUserRow
|
|
for rows.Next() {
|
|
var i GetTeamsForUserRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
&i.Role,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const insertTeam = `-- name: InsertTeam :one
|
|
INSERT INTO teams (id, name, slug)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id, name, slug, is_byoc, created_at, deleted_at
|
|
`
|
|
|
|
type InsertTeamParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
Slug string `json:"slug"`
|
|
}
|
|
|
|
func (q *Queries) InsertTeam(ctx context.Context, arg InsertTeamParams) (Team, error) {
|
|
row := q.db.QueryRow(ctx, insertTeam, arg.ID, arg.Name, arg.Slug)
|
|
var i Team
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const insertTeamMember = `-- name: InsertTeamMember :exec
|
|
INSERT INTO users_teams (user_id, team_id, is_default, role)
|
|
VALUES ($1, $2, $3, $4)
|
|
`
|
|
|
|
type InsertTeamMemberParams struct {
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
IsDefault bool `json:"is_default"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
func (q *Queries) InsertTeamMember(ctx context.Context, arg InsertTeamMemberParams) error {
|
|
_, err := q.db.Exec(ctx, insertTeamMember,
|
|
arg.UserID,
|
|
arg.TeamID,
|
|
arg.IsDefault,
|
|
arg.Role,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const listTeamsAdmin = `-- name: ListTeamsAdmin :many
|
|
SELECT
|
|
t.id,
|
|
t.name,
|
|
t.slug,
|
|
t.is_byoc,
|
|
t.created_at,
|
|
t.deleted_at,
|
|
(SELECT COUNT(*) FROM users_teams ut WHERE ut.team_id = t.id)::int AS member_count,
|
|
COALESCE(owner_u.name, '') AS owner_name,
|
|
COALESCE(owner_u.email, '') AS owner_email,
|
|
(SELECT COUNT(*) FROM sandboxes s WHERE s.team_id = t.id AND s.status IN ('running', 'paused', 'starting'))::int AS active_sandbox_count,
|
|
(SELECT COUNT(*) FROM channels c WHERE c.team_id = t.id)::int AS channel_count
|
|
FROM teams t
|
|
LEFT JOIN users_teams owner_ut ON owner_ut.team_id = t.id AND owner_ut.role = 'owner'
|
|
LEFT JOIN users owner_u ON owner_u.id = owner_ut.user_id
|
|
WHERE t.id != '00000000-0000-0000-0000-000000000000'
|
|
ORDER BY t.deleted_at ASC NULLS FIRST, t.created_at DESC
|
|
LIMIT $1 OFFSET $2
|
|
`
|
|
|
|
type ListTeamsAdminParams struct {
|
|
Limit int32 `json:"limit"`
|
|
Offset int32 `json:"offset"`
|
|
}
|
|
|
|
type ListTeamsAdminRow struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
Slug string `json:"slug"`
|
|
IsByoc bool `json:"is_byoc"`
|
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
|
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
|
|
MemberCount int32 `json:"member_count"`
|
|
OwnerName string `json:"owner_name"`
|
|
OwnerEmail string `json:"owner_email"`
|
|
ActiveSandboxCount int32 `json:"active_sandbox_count"`
|
|
ChannelCount int32 `json:"channel_count"`
|
|
}
|
|
|
|
func (q *Queries) ListTeamsAdmin(ctx context.Context, arg ListTeamsAdminParams) ([]ListTeamsAdminRow, error) {
|
|
rows, err := q.db.Query(ctx, listTeamsAdmin, arg.Limit, arg.Offset)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListTeamsAdminRow
|
|
for rows.Next() {
|
|
var i ListTeamsAdminRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.Slug,
|
|
&i.IsByoc,
|
|
&i.CreatedAt,
|
|
&i.DeletedAt,
|
|
&i.MemberCount,
|
|
&i.OwnerName,
|
|
&i.OwnerEmail,
|
|
&i.ActiveSandboxCount,
|
|
&i.ChannelCount,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const setTeamBYOC = `-- name: SetTeamBYOC :exec
|
|
UPDATE teams SET is_byoc = $2 WHERE id = $1
|
|
`
|
|
|
|
type SetTeamBYOCParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
IsByoc bool `json:"is_byoc"`
|
|
}
|
|
|
|
func (q *Queries) SetTeamBYOC(ctx context.Context, arg SetTeamBYOCParams) error {
|
|
_, err := q.db.Exec(ctx, setTeamBYOC, arg.ID, arg.IsByoc)
|
|
return err
|
|
}
|
|
|
|
const softDeleteTeam = `-- name: SoftDeleteTeam :exec
|
|
UPDATE teams SET deleted_at = NOW() WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) SoftDeleteTeam(ctx context.Context, id pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, softDeleteTeam, id)
|
|
return err
|
|
}
|
|
|
|
const updateMemberRole = `-- name: UpdateMemberRole :exec
|
|
UPDATE users_teams SET role = $3 WHERE team_id = $1 AND user_id = $2
|
|
`
|
|
|
|
type UpdateMemberRoleParams struct {
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
func (q *Queries) UpdateMemberRole(ctx context.Context, arg UpdateMemberRoleParams) error {
|
|
_, err := q.db.Exec(ctx, updateMemberRole, arg.TeamID, arg.UserID, arg.Role)
|
|
return err
|
|
}
|
|
|
|
const updateTeamName = `-- name: UpdateTeamName :exec
|
|
UPDATE teams SET name = $2 WHERE id = $1 AND deleted_at IS NULL
|
|
`
|
|
|
|
type UpdateTeamNameParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
func (q *Queries) UpdateTeamName(ctx context.Context, arg UpdateTeamNameParams) error {
|
|
_, err := q.db.Exec(ctx, updateTeamName, arg.ID, arg.Name)
|
|
return err
|
|
}
|