Changeset 0.9.0 (#50)
This commit is contained in:
198
server/store/postgres/team.go
Normal file
198
server/store/postgres/team.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
)
|
||||
|
||||
type TeamStore struct{}
|
||||
|
||||
func NewTeamStore() *TeamStore { return &TeamStore{} }
|
||||
|
||||
func (s *TeamStore) Create(ctx context.Context, t *models.Team) error {
|
||||
settingsJSON := ToJSON(t.Settings)
|
||||
return DB.QueryRowContext(ctx, `
|
||||
INSERT INTO teams (name, description, created_by, is_active, settings)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, created_at, updated_at`,
|
||||
t.Name, t.Description, t.CreatedBy, t.IsActive, settingsJSON,
|
||||
).Scan(&t.ID, &t.CreatedAt, &t.UpdatedAt)
|
||||
}
|
||||
|
||||
func (s *TeamStore) GetByID(ctx context.Context, id string) (*models.Team, error) {
|
||||
var t models.Team
|
||||
var settingsJSON []byte
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT id, name, description, created_by, is_active, settings, created_at, updated_at,
|
||||
(SELECT COUNT(*) FROM team_members WHERE team_id = teams.id) as member_count
|
||||
FROM teams WHERE id = $1`, id).Scan(
|
||||
&t.ID, &t.Name, &t.Description, &t.CreatedBy, &t.IsActive,
|
||||
&settingsJSON, &t.CreatedAt, &t.UpdatedAt, &t.MemberCount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal(settingsJSON, &t.Settings)
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (s *TeamStore) Update(ctx context.Context, id string, fields map[string]interface{}) error {
|
||||
b := NewUpdate("teams")
|
||||
for k, v := range fields {
|
||||
if k == "settings" {
|
||||
b.SetJSON(k, v)
|
||||
} else {
|
||||
b.Set(k, v)
|
||||
}
|
||||
}
|
||||
if !b.HasSets() {
|
||||
return nil
|
||||
}
|
||||
b.Where("id", id)
|
||||
_, err := b.Exec(DB)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TeamStore) Delete(ctx context.Context, id string) error {
|
||||
_, err := DB.ExecContext(ctx, "DELETE FROM teams WHERE id = $1", id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TeamStore) List(ctx context.Context) ([]models.Team, error) {
|
||||
rows, err := DB.QueryContext(ctx, `
|
||||
SELECT id, name, description, created_by, is_active, settings, created_at, updated_at,
|
||||
(SELECT COUNT(*) FROM team_members WHERE team_id = teams.id) as member_count
|
||||
FROM teams ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []models.Team
|
||||
for rows.Next() {
|
||||
var t models.Team
|
||||
var settingsJSON []byte
|
||||
err := rows.Scan(&t.ID, &t.Name, &t.Description, &t.CreatedBy, &t.IsActive,
|
||||
&settingsJSON, &t.CreatedAt, &t.UpdatedAt, &t.MemberCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal(settingsJSON, &t.Settings)
|
||||
result = append(result, t)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
// ── Members ─────────────────────────────────
|
||||
|
||||
func (s *TeamStore) AddMember(ctx context.Context, teamID, userID, role string) error {
|
||||
_, err := DB.ExecContext(ctx, `
|
||||
INSERT INTO team_members (team_id, user_id, role) VALUES ($1, $2, $3)
|
||||
ON CONFLICT (team_id, user_id) DO UPDATE SET role = $3`,
|
||||
teamID, userID, role)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TeamStore) RemoveMember(ctx context.Context, teamID, userID string) error {
|
||||
_, err := DB.ExecContext(ctx, "DELETE FROM team_members WHERE team_id = $1 AND user_id = $2",
|
||||
teamID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TeamStore) UpdateMemberRole(ctx context.Context, teamID, userID, role string) error {
|
||||
_, err := DB.ExecContext(ctx,
|
||||
"UPDATE team_members SET role = $1 WHERE team_id = $2 AND user_id = $3",
|
||||
role, teamID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TeamStore) ListMembers(ctx context.Context, teamID string) ([]models.TeamMember, error) {
|
||||
rows, err := DB.QueryContext(ctx, `
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.joined_at,
|
||||
u.email, COALESCE(u.display_name, ''), u.username, u.role as user_role
|
||||
FROM team_members tm
|
||||
JOIN users u ON u.id = tm.user_id
|
||||
WHERE tm.team_id = $1
|
||||
ORDER BY tm.role DESC, u.username`, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []models.TeamMember
|
||||
for rows.Next() {
|
||||
var m models.TeamMember
|
||||
err := rows.Scan(&m.ID, &m.TeamID, &m.UserID, &m.Role, &m.JoinedAt,
|
||||
&m.Email, &m.DisplayName, &m.Username, &m.UserRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, m)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *TeamStore) GetMember(ctx context.Context, teamID, userID string) (*models.TeamMember, error) {
|
||||
var m models.TeamMember
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.joined_at,
|
||||
u.email, COALESCE(u.display_name, ''), u.username, u.role as user_role
|
||||
FROM team_members tm
|
||||
JOIN users u ON u.id = tm.user_id
|
||||
WHERE tm.team_id = $1 AND tm.user_id = $2`, teamID, userID).Scan(
|
||||
&m.ID, &m.TeamID, &m.UserID, &m.Role, &m.JoinedAt,
|
||||
&m.Email, &m.DisplayName, &m.Username, &m.UserRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// GetUserTeamIDs returns all team IDs a user belongs to.
|
||||
func (s *TeamStore) GetUserTeamIDs(ctx context.Context, userID string) ([]string, error) {
|
||||
rows, err := DB.QueryContext(ctx,
|
||||
"SELECT team_id FROM team_members WHERE user_id = $1", userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var ids []string
|
||||
for rows.Next() {
|
||||
var id string
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids, rows.Err()
|
||||
}
|
||||
|
||||
func (s *TeamStore) IsTeamAdmin(ctx context.Context, teamID, userID string) (bool, error) {
|
||||
var role string
|
||||
err := DB.QueryRowContext(ctx,
|
||||
"SELECT role FROM team_members WHERE team_id = $1 AND user_id = $2",
|
||||
teamID, userID).Scan(&role)
|
||||
if err == sql.ErrNoRows {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return role == models.TeamRoleAdmin, nil
|
||||
}
|
||||
|
||||
func (s *TeamStore) IsMember(ctx context.Context, teamID, userID string) (bool, error) {
|
||||
var exists bool
|
||||
err := DB.QueryRowContext(ctx,
|
||||
"SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = $1 AND user_id = $2)",
|
||||
teamID, userID).Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
// unused but keeping for reference
|
||||
var _ = fmt.Sprintf
|
||||
Reference in New Issue
Block a user