245 lines
5.5 KiB
Go
245 lines
5.5 KiB
Go
package scopes
|
||
|
||
import (
|
||
"context"
|
||
"git.aiterp.net/stufflog3/stufflog3/entities"
|
||
"git.aiterp.net/stufflog3/stufflog3/internal/genutils"
|
||
"git.aiterp.net/stufflog3/stufflog3/models"
|
||
"git.aiterp.net/stufflog3/stufflog3/usecases/auth"
|
||
"strings"
|
||
)
|
||
|
||
type Service struct {
|
||
Auth *auth.Service
|
||
Repository Repository
|
||
StatsLister StatsLister
|
||
|
||
contextKey struct{ B int64 }
|
||
}
|
||
|
||
func (s *Service) CreateContext(ctx context.Context, userID string, scope Result) context.Context {
|
||
return context.WithValue(ctx, &s.contextKey, &Context{
|
||
scopesRepo: s.Repository,
|
||
statsRepo: s.StatsLister,
|
||
userID: userID,
|
||
|
||
ID: scope.ID,
|
||
Scope: scope,
|
||
|
||
service: s,
|
||
})
|
||
}
|
||
|
||
func (s *Service) CreateListContext(ctx context.Context, userID string, scopes []Result) context.Context {
|
||
contextData := &Context{
|
||
scopesRepo: s.Repository,
|
||
statsRepo: s.StatsLister,
|
||
userID: userID,
|
||
scopes: scopes,
|
||
scopesError: nil,
|
||
|
||
ID: -1,
|
||
Scope: Result{
|
||
Scope: entities.Scope{ID: -1},
|
||
Members: map[string]ResultMember{},
|
||
Stats: []ResultStat{},
|
||
},
|
||
|
||
service: s,
|
||
}
|
||
|
||
contextData.scopesOnce.Do(func() { /* a lot of nothing */ })
|
||
|
||
return context.WithValue(ctx, &s.contextKey, contextData)
|
||
}
|
||
|
||
func (s *Service) Context(ctx context.Context) *Context {
|
||
v := ctx.Value(&s.contextKey)
|
||
if v == nil {
|
||
return nil
|
||
}
|
||
|
||
return v.(*Context)
|
||
}
|
||
|
||
// Find finds a scope and its members, and returns it if the logged-in user is part of this list.
|
||
func (s *Service) Find(ctx context.Context, id int) (*Result, error) {
|
||
user := s.Auth.GetUser(ctx)
|
||
if user == nil {
|
||
return nil, models.PermissionDeniedError{}
|
||
}
|
||
|
||
scope, err := s.Repository.Find(ctx, id)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
members, err := s.Repository.ListMembers(ctx, scope.ID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
stats, err := s.StatsLister.List(ctx, scope.ID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
found := false
|
||
for _, member := range members {
|
||
if member.UserID == user.ID {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
return nil, models.NotFoundError("Scope")
|
||
}
|
||
|
||
return generateResult(*scope, members, stats), nil
|
||
}
|
||
|
||
// List lists a scope and their members, and returns it if the logged-in user is part of this list.
|
||
func (s *Service) List(ctx context.Context) ([]Result, error) {
|
||
user := s.Auth.GetUser(ctx)
|
||
if user == nil {
|
||
return nil, models.PermissionDeniedError{}
|
||
}
|
||
|
||
scopes, err := s.Repository.ListUser(ctx, user.ID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
ids := make([]int, 0, len(scopes))
|
||
for _, scope := range scopes {
|
||
ids = append(ids, scope.ID)
|
||
}
|
||
members, err := s.Repository.ListMembers(ctx, ids...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
stats, err := s.StatsLister.List(ctx, ids...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return genutils.Map(scopes, func(scope entities.Scope) Result {
|
||
return *generateResult(scope, members, stats)
|
||
}), nil
|
||
}
|
||
|
||
func (s *Service) Create(ctx context.Context, scope entities.Scope, ownerName string) (*Result, error) {
|
||
user := s.Auth.GetUser(ctx)
|
||
if user == nil {
|
||
return nil, models.PermissionDeniedError{}
|
||
}
|
||
|
||
scope.Name = strings.Trim(scope.Name, " \t\r\n")
|
||
if scope.Name == "" {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeInput",
|
||
Field: "name",
|
||
Problem: "Empty name provided",
|
||
}
|
||
}
|
||
|
||
scope.Abbreviation = strings.ToUpper(strings.Trim(scope.Abbreviation, " \t\r\n"))
|
||
if scope.Abbreviation == "" {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeInput",
|
||
Field: "abbreviation",
|
||
Problem: "Empty abbreviation provided",
|
||
}
|
||
}
|
||
if strings.ContainsAny(scope.Abbreviation, "\t \n\r\t") {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeInput",
|
||
Field: "abbreviation",
|
||
Problem: "Invalid abbreviation provided",
|
||
}
|
||
}
|
||
|
||
ownerName = strings.Trim(ownerName, " \t\r\n")
|
||
if ownerName == "" {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeInput",
|
||
Field: "ownerName",
|
||
Problem: "Empty owner name provided",
|
||
}
|
||
}
|
||
|
||
owner := entities.ScopeMember{
|
||
ScopeID: -1,
|
||
UserID: user.ID,
|
||
Name: ownerName,
|
||
Owner: true,
|
||
}
|
||
|
||
newScope, err := s.Repository.Create(ctx, scope, owner)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
owner.ScopeID = newScope.ID
|
||
|
||
return generateResult(*newScope, []entities.ScopeMember{owner}, []entities.Stat{}), nil
|
||
}
|
||
|
||
func (s *Service) Update(ctx context.Context, scopeId int, update models.ScopeUpdate) (*Result, error) {
|
||
user := s.Auth.GetUser(ctx)
|
||
if user == nil {
|
||
return nil, models.PermissionDeniedError{}
|
||
}
|
||
|
||
scope, err := s.Find(ctx, scopeId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if !scope.Members[user.ID].Owner {
|
||
return nil, models.ForbiddenError("You do not own the scope")
|
||
}
|
||
|
||
if update.Name != nil && *update.Name == "" {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeUpdate",
|
||
Field: "name",
|
||
Problem: "Empty name provided",
|
||
}
|
||
}
|
||
if update.Abbreviation != nil && *update.Abbreviation == "" {
|
||
return nil, models.BadInputError{
|
||
Object: "ScopeUpdate",
|
||
Field: "name",
|
||
Problem: "Empty name provided",
|
||
}
|
||
}
|
||
|
||
err = s.Repository.Update(ctx, scope.Scope, update)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
scope.ApplyUpdate(update)
|
||
|
||
return scope, nil
|
||
}
|
||
|
||
func (s *Service) Delete(ctx context.Context, scopeId int) (*Result, error) {
|
||
user := s.Auth.GetUser(ctx)
|
||
if user == nil {
|
||
return nil, models.PermissionDeniedError{}
|
||
}
|
||
|
||
scope, err := s.Find(ctx, scopeId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if !scope.Members[user.ID].Owner {
|
||
return nil, models.ForbiddenError("You do not own the scope")
|
||
}
|
||
|
||
err = s.Repository.Delete(ctx, scope.Scope)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return scope, nil
|
||
}
|