You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
6.1 KiB
278 lines
6.1 KiB
package mysql
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"git.aiterp.net/stufflog3/stufflog3-api/internal/database/mysql/mysqlcore"
|
|
"git.aiterp.net/stufflog3/stufflog3-api/internal/models"
|
|
"git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors"
|
|
"golang.org/x/sync/errgroup"
|
|
"sort"
|
|
)
|
|
|
|
type scopeRepository struct {
|
|
db *sql.DB
|
|
q *mysqlcore.Queries
|
|
}
|
|
|
|
func (r *scopeRepository) Find(ctx context.Context, id int, full bool) (*models.Scope, error) {
|
|
scope, err := r.q.GetScope(ctx, id)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, slerrors.NotFound("Scope")
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
res := &models.Scope{
|
|
ScopeEntry: models.ScopeEntry{
|
|
ID: scope.ID,
|
|
Name: scope.Name,
|
|
Abbreviation: scope.Abbreviation,
|
|
},
|
|
Members: []models.ScopeMember{},
|
|
Projects: []models.ProjectEntry{},
|
|
Stats: []models.Stat{},
|
|
StatusLabels: make(map[models.Status]string),
|
|
}
|
|
|
|
eg, ctx := errgroup.WithContext(ctx)
|
|
|
|
if full {
|
|
eg.Go(func() error {
|
|
projects, err := r.q.ListProjectEntries(ctx, id)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return err
|
|
}
|
|
|
|
for _, project := range projects {
|
|
res.Projects = append(res.Projects, models.ProjectEntry{
|
|
ID: project.ID,
|
|
OwnerID: project.AuthorID,
|
|
CreatedTime: project.CreatedTime,
|
|
Name: project.Name,
|
|
Status: models.Status(project.Status),
|
|
})
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
eg.Go(func() error {
|
|
stats, err := r.q.ListStats(ctx, id)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return err
|
|
}
|
|
|
|
for _, stat := range stats {
|
|
var amounts map[string]int
|
|
if stat.AllowedAmounts.Valid {
|
|
amounts = make(map[string]int)
|
|
err := json.Unmarshal(stat.AllowedAmounts.RawMessage, &amounts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
res.Stats = append(res.Stats, models.Stat{
|
|
StatEntry: models.StatEntry{
|
|
ID: stat.ID,
|
|
Name: stat.Name,
|
|
Weight: stat.Weight,
|
|
},
|
|
Description: stat.Description,
|
|
AllowedAmounts: amounts,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
eg.Go(func() error {
|
|
members, err := r.q.ListScopeMembers(ctx, id)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return err
|
|
}
|
|
|
|
for _, member := range members {
|
|
res.Members = append(res.Members, models.ScopeMember{
|
|
ID: member.UserID,
|
|
Name: member.Name,
|
|
Owner: member.Owner,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
err = eg.Wait()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (r *scopeRepository) List(ctx context.Context) ([]models.ScopeEntry, error) {
|
|
scopes, err := r.q.ListScopes(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res := make([]models.ScopeEntry, 0, len(scopes))
|
|
for _, scope := range scopes {
|
|
res = append(res, models.ScopeEntry{
|
|
ID: scope.ID,
|
|
Name: scope.Name,
|
|
Abbreviation: scope.Abbreviation,
|
|
})
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (r *scopeRepository) ListByUser(ctx context.Context, userID string) ([]models.ScopeEntry, error) {
|
|
scopes, err := r.q.ListScopesByUser(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res := make([]models.ScopeEntry, 0, len(scopes))
|
|
for _, scope := range scopes {
|
|
res = append(res, models.ScopeEntry{
|
|
ID: scope.ID,
|
|
Name: scope.Name,
|
|
Abbreviation: scope.Abbreviation,
|
|
})
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (r *scopeRepository) Create(ctx context.Context, scope models.ScopeEntry, owner models.ScopeMember) (*models.Scope, error) {
|
|
tx, err := r.db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
q := r.q.WithTx(tx)
|
|
res, err := q.InsertScope(ctx, mysqlcore.InsertScopeParams(scope))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
id, err := res.LastInsertId()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = q.UpdateScopeMember(ctx, mysqlcore.UpdateScopeMemberParams{
|
|
ScopeID: int(id),
|
|
UserID: owner.ID,
|
|
Name: owner.Name,
|
|
Owner: true,
|
|
})
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &models.Scope{
|
|
ScopeEntry: models.ScopeEntry{
|
|
ID: int(id),
|
|
Name: scope.Name,
|
|
Abbreviation: scope.Abbreviation,
|
|
},
|
|
DisplayName: owner.Name,
|
|
Members: []models.ScopeMember{
|
|
{
|
|
ID: owner.ID,
|
|
Name: owner.Name,
|
|
Owner: true,
|
|
},
|
|
},
|
|
Projects: []models.ProjectEntry{},
|
|
Stats: []models.Stat{},
|
|
}, nil
|
|
}
|
|
|
|
func (r *scopeRepository) Update(ctx context.Context, scope models.ScopeEntry) error {
|
|
return mysqlcore.New(r.db).UpdateScope(ctx, mysqlcore.UpdateScopeParams{
|
|
Name: scope.Name,
|
|
Abbreviation: scope.Abbreviation,
|
|
ID: scope.ID,
|
|
})
|
|
}
|
|
|
|
func (r *scopeRepository) Delete(ctx context.Context, scope models.Scope) error {
|
|
tx, err := r.db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
q := r.q.WithTx(tx)
|
|
err = q.DeleteAllScopeMembers(ctx, scope.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = q.DeleteScope(ctx, scope.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (r *scopeRepository) UpdateMember(ctx context.Context, scope models.Scope, member models.ScopeMember) (*models.Scope, error) {
|
|
err := mysqlcore.New(r.db).UpdateScopeMember(ctx, mysqlcore.UpdateScopeMemberParams{
|
|
ScopeID: scope.ID,
|
|
UserID: member.ID,
|
|
Name: member.Name,
|
|
Owner: member.Owner,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
found := false
|
|
scope.Members = append(scope.Members[:0:0], scope.Members...)
|
|
for i, member2 := range scope.Members {
|
|
if member2.ID == member.ID {
|
|
scope.Members[i] = member2
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
scope.Members = append(scope.Members, member)
|
|
sort.Slice(scope.Members, func(i, j int) bool {
|
|
return scope.Members[i].Name < scope.Members[j].Name
|
|
})
|
|
}
|
|
|
|
return &scope, nil
|
|
}
|
|
|
|
func (r *scopeRepository) DeleteMember(ctx context.Context, scope models.Scope, userID string) (*models.Scope, error) {
|
|
err := mysqlcore.New(r.db).DeleteScopeMember(ctx, mysqlcore.DeleteScopeMemberParams{
|
|
ScopeID: scope.ID,
|
|
UserID: userID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newMembers := make([]models.ScopeMember, 0, len(scope.Members)-1)
|
|
for _, member := range scope.Members {
|
|
if member.ID != userID {
|
|
newMembers = append(newMembers, member)
|
|
}
|
|
}
|
|
scope.Members = newMembers
|
|
|
|
return &scope, nil
|
|
}
|