stash/pkg/studio/update.go

135 lines
2.9 KiB
Go

package studio
import (
"context"
"errors"
"fmt"
"github.com/stashapp/stash/pkg/models"
)
var (
ErrStudioOwnAncestor = errors.New("studio cannot be an ancestor of itself")
)
type NameExistsError struct {
Name string
}
func (e *NameExistsError) Error() string {
return fmt.Sprintf("studio with name '%s' already exists", e.Name)
}
type NameUsedByAliasError struct {
Name string
OtherStudio string
}
func (e *NameUsedByAliasError) Error() string {
return fmt.Sprintf("name '%s' is used as alias for '%s'", e.Name, e.OtherStudio)
}
// EnsureStudioNameUnique returns an error if the studio name provided
// is used as a name or alias of another existing tag.
func EnsureStudioNameUnique(ctx context.Context, id int, name string, qb models.StudioQueryer) error {
// ensure name is unique
sameNameStudio, err := ByName(ctx, qb, name)
if err != nil {
return err
}
if sameNameStudio != nil && id != sameNameStudio.ID {
return &NameExistsError{
Name: name,
}
}
// query by alias
sameNameStudio, err = ByAlias(ctx, qb, name)
if err != nil {
return err
}
if sameNameStudio != nil && id != sameNameStudio.ID {
return &NameUsedByAliasError{
Name: name,
OtherStudio: sameNameStudio.Name,
}
}
return nil
}
func EnsureAliasesUnique(ctx context.Context, id int, aliases []string, qb models.StudioQueryer) error {
for _, a := range aliases {
if err := EnsureStudioNameUnique(ctx, id, a, qb); err != nil {
return err
}
}
return nil
}
type ValidateModifyReader interface {
models.StudioGetter
models.StudioQueryer
models.AliasLoader
}
// Checks to make sure that:
// 1. The studio exists locally
// 2. The studio is not its own ancestor
// 3. The studio's aliases are unique
func ValidateModify(ctx context.Context, s models.StudioPartial, qb ValidateModifyReader) error {
existing, err := qb.Find(ctx, s.ID)
if err != nil {
return err
}
if existing == nil {
return fmt.Errorf("studio with id %d not found", s.ID)
}
newParentID := s.ParentID.Ptr()
if newParentID != nil {
if err := validateParent(ctx, s.ID, *newParentID, qb); err != nil {
return err
}
}
if s.Aliases != nil {
if err := existing.LoadAliases(ctx, qb); err != nil {
return err
}
effectiveAliases := s.Aliases.EffectiveValues(existing.Aliases.List())
if err := EnsureAliasesUnique(ctx, s.ID, effectiveAliases, qb); err != nil {
return err
}
}
return nil
}
func validateParent(ctx context.Context, studioID int, newParentID int, qb models.StudioGetter) error {
if newParentID == studioID {
return ErrStudioOwnAncestor
}
// ensure there is no cyclic dependency
parentStudio, err := qb.Find(ctx, newParentID)
if err != nil {
return fmt.Errorf("error finding parent studio: %v", err)
}
if parentStudio == nil {
return fmt.Errorf("studio with id %d not found", newParentID)
}
if parentStudio.ParentID != nil {
return validateParent(ctx, studioID, *parentStudio.ParentID, qb)
}
return nil
}