Tag aliases (#1412)

* Add Tag Update/UpdateFull
* Tag alias implementation
* Refactor tag page
* Add aliases in UI
* Include tag aliases in q filter
* Include aliases in tag select
* Add aliases to auto-tagger
* Use aliases in scraper
* Add tag aliases for filename parser
This commit is contained in:
WithoutPants
2021-05-26 14:36:05 +10:00
committed by GitHub
parent 9b57fbbf50
commit c70faa2a53
48 changed files with 1303 additions and 315 deletions

View File

@@ -10,6 +10,17 @@ import (
"github.com/stashapp/stash/pkg/models"
)
func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) (ret []string, err error) {
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
ret, err = repo.Tag().GetAliases(obj.ID)
return err
}); err != nil {
return nil, err
}
return ret, err
}
func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
var count int
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {

View File

@@ -6,8 +6,8 @@ import (
"strconv"
"time"
"github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/tag"
"github.com/stashapp/stash/pkg/utils"
)
@@ -31,24 +31,34 @@ func (r *mutationResolver) TagCreate(ctx context.Context, input models.TagCreate
}
}
// Start the transaction and save the tag
var tag *models.Tag
// Start the transaction and save the t
var t *models.Tag
if err := r.withTxn(ctx, func(repo models.Repository) error {
qb := repo.Tag()
// ensure name is unique
if err := manager.EnsureTagNameUnique(newTag, qb); err != nil {
if err := tag.EnsureTagNameUnique(0, newTag.Name, qb); err != nil {
return err
}
tag, err = qb.Create(newTag)
t, err = qb.Create(newTag)
if err != nil {
return err
}
// update image table
if len(imageData) > 0 {
if err := qb.UpdateImage(tag.ID, imageData); err != nil {
if err := qb.UpdateImage(t.ID, imageData); err != nil {
return err
}
}
if len(input.Aliases) > 0 {
if err := tag.EnsureAliasesUnique(t.ID, input.Aliases, qb); err != nil {
return err
}
if err := qb.UpdateAliases(t.ID, input.Aliases); err != nil {
return err
}
}
@@ -58,7 +68,7 @@ func (r *mutationResolver) TagCreate(ctx context.Context, input models.TagCreate
return nil, err
}
return tag, nil
return t, nil
}
func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdateInput) (*models.Tag, error) {
@@ -68,12 +78,6 @@ func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdate
return nil, err
}
updatedTag := models.Tag{
ID: tagID,
Name: input.Name,
UpdatedAt: models.SQLiteTimestamp{Timestamp: time.Now()},
}
var imageData []byte
translator := changesetTranslator{
@@ -90,39 +94,56 @@ func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdate
}
// Start the transaction and save the tag
var tag *models.Tag
var t *models.Tag
if err := r.withTxn(ctx, func(repo models.Repository) error {
qb := repo.Tag()
// ensure name is unique
existing, err := qb.Find(tagID)
t, err = qb.Find(tagID)
if err != nil {
return err
}
if existing == nil {
if t == nil {
return fmt.Errorf("Tag with ID %d not found", tagID)
}
if existing.Name != updatedTag.Name {
if err := manager.EnsureTagNameUnique(updatedTag, qb); err != nil {
return err
}
updatedTag := models.TagPartial{
ID: tagID,
UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()},
}
tag, err = qb.Update(updatedTag)
if input.Name != nil && t.Name != *input.Name {
if err := tag.EnsureTagNameUnique(tagID, *input.Name, qb); err != nil {
return err
}
updatedTag.Name = input.Name
}
t, err = qb.Update(updatedTag)
if err != nil {
return err
}
// update image table
if len(imageData) > 0 {
if err := qb.UpdateImage(tag.ID, imageData); err != nil {
if err := qb.UpdateImage(tagID, imageData); err != nil {
return err
}
} else if imageIncluded {
// must be unsetting
if err := qb.DestroyImage(tag.ID); err != nil {
if err := qb.DestroyImage(tagID); err != nil {
return err
}
}
if translator.hasField("aliases") {
if err := tag.EnsureAliasesUnique(tagID, input.Aliases, qb); err != nil {
return err
}
if err := qb.UpdateAliases(tagID, input.Aliases); err != nil {
return err
}
}
@@ -132,7 +153,7 @@ func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdate
return nil, err
}
return tag, nil
return t, nil
}
func (r *mutationResolver) TagDestroy(ctx context.Context, input models.TagDestroyInput) (bool, error) {

View File

@@ -30,11 +30,38 @@ func TestTagCreate(t *testing.T) {
r := newResolver()
tagRW := r.txnManager.(*mocks.TransactionManager).Tag().(*mocks.TagReaderWriter)
tagRW.On("FindByName", existingTagName, true).Return(&models.Tag{
ID: existingTagID,
Name: existingTagName,
}, nil).Once()
tagRW.On("FindByName", errTagName, true).Return(nil, nil).Once()
pp := 1
findFilter := &models.FindFilterType{
PerPage: &pp,
}
tagFilterForName := func(n string) *models.TagFilterType {
return &models.TagFilterType{
Name: &models.StringCriterionInput{
Value: n,
Modifier: models.CriterionModifierEquals,
},
}
}
tagFilterForAlias := func(n string) *models.TagFilterType {
return &models.TagFilterType{
Aliases: &models.StringCriterionInput{
Value: n,
Modifier: models.CriterionModifierEquals,
},
}
}
tagRW.On("Query", tagFilterForName(existingTagName), findFilter).Return([]*models.Tag{
{
ID: existingTagID,
Name: existingTagName,
},
}, 1, nil).Once()
tagRW.On("Query", tagFilterForName(errTagName), findFilter).Return(nil, 0, nil).Once()
tagRW.On("Query", tagFilterForAlias(errTagName), findFilter).Return(nil, 0, nil).Once()
expectedErr := errors.New("TagCreate error")
tagRW.On("Create", mock.AnythingOfType("models.Tag")).Return(nil, expectedErr)
@@ -55,7 +82,8 @@ func TestTagCreate(t *testing.T) {
r = newResolver()
tagRW = r.txnManager.(*mocks.TransactionManager).Tag().(*mocks.TagReaderWriter)
tagRW.On("FindByName", tagName, true).Return(nil, nil).Once()
tagRW.On("Query", tagFilterForName(tagName), findFilter).Return(nil, 0, nil).Once()
tagRW.On("Query", tagFilterForAlias(tagName), findFilter).Return(nil, 0, nil).Once()
tagRW.On("Create", mock.AnythingOfType("models.Tag")).Return(&models.Tag{
ID: newTagID,
Name: tagName,