nquest/pkg/service/team.go

210 lines
4.3 KiB
Go
Raw Normal View History

2023-11-01 23:21:12 +03:00
package service
import (
"context"
"errors"
"slices"
"time"
2023-11-01 23:21:12 +03:00
"gitrepo.ru/neonxp/nquest/pkg/models"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
var (
ErrTeamNotFound = errors.New("team not found")
)
type Team struct {
DB *gorm.DB
User *User
2023-11-01 23:21:12 +03:00
}
// NewTeam returns new Team.
func NewTeam(db *gorm.DB, user *User) *Team {
2023-11-01 23:21:12 +03:00
return &Team{
DB: db,
User: user,
}
}
func (ts *Team) GetByID(ctx context.Context, id uint) (*models.Team, error) {
t := new(models.Team)
err := ts.DB.
WithContext(ctx).
Preload("Members").
Preload("Members.User").
Preload("Requests").
Preload("Requests.User").
First(t, id).
Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrTeamNotFound
}
return nil, err
2023-11-01 23:21:12 +03:00
}
return t, nil
2023-11-01 23:21:12 +03:00
}
func (ts *Team) List(ctx context.Context) ([]*models.Team, error) {
teams := []*models.Team{}
return teams, ts.DB.WithContext(ctx).Preload("Members").Find(&teams).Error
}
func (ts *Team) Create(ctx context.Context, name string, user *models.User) (*models.Team, error) {
t := &models.Team{
Name: name,
Members: []*models.TeamMember{{
User: user,
Role: models.Captain,
}},
}
db := ts.DB.WithContext(ctx)
if err := db.Delete(&models.TeamRequest{}, `user_id = ?`, user.ID).Error; err != nil {
return t, err
}
return t, db.Create(t).Error
}
func (ts *Team) Delete(ctx context.Context, id uint) error {
if err := ts.DB.WithContext(ctx).Delete(&models.Team{}, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrTeamNotFound
}
return err
}
return nil
}
func (ts *Team) Request(ctx context.Context, teamID uint, user *models.User) error {
team, err := ts.GetByID(ctx, teamID)
if err != nil {
return err
}
2023-11-01 23:21:12 +03:00
return ts.DB.
WithContext(ctx).
Clauses(clause.OnConflict{DoNothing: true}).
Create(&models.TeamRequest{
Team: team,
User: user,
}).
Error
}
func (ts *Team) UpdateMembers(
ctx context.Context,
teamID uint,
newMembers []int,
) error {
team, err := ts.GetByID(ctx, teamID)
if err != nil {
return err
}
2023-11-01 23:21:12 +03:00
newMembersList := make([]*models.TeamMember, 0, len(newMembers))
2023-11-01 23:21:12 +03:00
for _, tm := range team.Members {
idx, ok := slices.BinarySearch(newMembers, int(tm.UserID))
if ok {
newMembers = slices.Delete(newMembers, idx, idx)
newMembersList = append(newMembersList, tm)
continue
}
if err := ts.DB.WithContext(ctx).Delete(tm).Error; err != nil {
return err
}
2023-11-01 23:21:12 +03:00
}
for _, userID := range newMembers {
_, found := slices.BinarySearchFunc(team.Members, userID, func(tm *models.TeamMember, i int) int {
return int(tm.UserID) - i
})
if found {
continue
}
user, err := ts.User.GetUserByID(ctx, uint(userID))
if err != nil {
return err
}
newMembersList = append(newMembersList, &models.TeamMember{
TeamID: teamID,
Team: team,
UserID: user.ID,
User: user,
Role: models.Member,
CreatedAt: time.Now(),
})
}
team.Members = newMembersList
return ts.DB.
WithContext(ctx).
Session(&gorm.Session{FullSaveAssociations: true}).
Updates(team).
Error
2023-11-01 23:21:12 +03:00
}
func (ts *Team) ApproveRequest(ctx context.Context, teamID int, userID uint, approve bool) error {
team, err := ts.GetByID(ctx, uint(teamID))
if err != nil {
return err
}
idx, found := slices.BinarySearchFunc(team.Requests, userID, func(tr *models.TeamRequest, i uint) int {
return int(tr.UserID - i)
})
if !found {
return nil
}
request := team.Requests[idx]
2023-11-01 23:21:12 +03:00
team.Requests = slices.DeleteFunc(team.Requests, func(tr *models.TeamRequest) bool {
return tr.UserID == uint(userID)
2023-11-01 23:21:12 +03:00
})
if err := ts.DB.WithContext(ctx).Delete(request).Error; err != nil {
2023-11-01 23:21:12 +03:00
return err
}
if approve {
team.Members = append(team.Members, &models.TeamMember{
Team: team,
TeamID: uint(teamID),
UserID: uint(userID),
Role: models.Member,
CreatedAt: time.Now(),
})
return ts.DB.WithContext(ctx).Save(team).Error
}
return nil
2023-11-01 23:21:12 +03:00
}
func (ts *Team) DeleteMember(ctx context.Context, teamID int, userID uint) error {
team, err := ts.GetByID(ctx, uint(teamID))
if err != nil {
return err
}
idx, found := slices.BinarySearchFunc(team.Members, userID, func(tm *models.TeamMember, u uint) int {
return int(tm.UserID - u)
})
if !found {
return nil
}
member := team.Members[idx]
return ts.DB.WithContext(ctx).Delete(member).Error
2023-11-01 23:21:12 +03:00
}