diff options
Diffstat (limited to 'internal/processing')
-rw-r--r-- | internal/processing/filters/v2/create.go | 23 | ||||
-rw-r--r-- | internal/processing/filters/v2/update.go | 151 |
2 files changed, 164 insertions, 10 deletions
diff --git a/internal/processing/filters/v2/create.go b/internal/processing/filters/v2/create.go index d429e1139..7095a643c 100644 --- a/internal/processing/filters/v2/create.go +++ b/internal/processing/filters/v2/create.go @@ -63,6 +63,29 @@ func (p *Processor) Create(ctx context.Context, account *gtsmodel.Account, form } } + for _, formKeyword := range form.Keywords { + filterKeyword := >smodel.FilterKeyword{ + ID: id.NewULID(), + AccountID: account.ID, + FilterID: filter.ID, + Filter: filter, + Keyword: formKeyword.Keyword, + WholeWord: formKeyword.WholeWord, + } + filter.Keywords = append(filter.Keywords, filterKeyword) + } + + for _, formStatus := range form.Statuses { + filterStatus := >smodel.FilterStatus{ + ID: id.NewULID(), + AccountID: account.ID, + FilterID: filter.ID, + Filter: filter, + StatusID: formStatus.StatusID, + } + filter.Statuses = append(filter.Statuses, filterStatus) + } + if err := p.state.DB.PutFilter(ctx, filter); err != nil { if errors.Is(err, db.ErrAlreadyExists) { err = errors.New("duplicate title, keyword, or status") diff --git a/internal/processing/filters/v2/update.go b/internal/processing/filters/v2/update.go index 5322f63d9..d8297de38 100644 --- a/internal/processing/filters/v2/update.go +++ b/internal/processing/filters/v2/update.go @@ -27,6 +27,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/id" "github.com/superseriousbusiness/gotosocial/internal/typeutils" "github.com/superseriousbusiness/gotosocial/internal/util" ) @@ -39,6 +40,8 @@ func (p *Processor) Update( filterID string, form *apimodel.FilterUpdateRequestV2, ) (*apimodel.FilterV2, gtserror.WithCode) { + var errWithCode gtserror.WithCode + // Get the filter by ID, with existing keywords and statuses. filter, err := p.state.DB.GetFilterByID(ctx, filterID) if err != nil { @@ -103,13 +106,17 @@ func (p *Processor) Update( } } - // Temporarily detach keywords and statuses from filter, since we're not updating them below. - filterKeywords := filter.Keywords - filterStatuses := filter.Statuses - filter.Keywords = nil - filter.Statuses = nil + filterKeywordColumns, deleteFilterKeywordIDs, errWithCode := applyKeywordChanges(filter, form.Keywords) + if err != nil { + return nil, errWithCode + } - if err := p.state.DB.UpdateFilter(ctx, filter, filterColumns, nil, nil, nil); err != nil { + deleteFilterStatusIDs, errWithCode := applyStatusChanges(filter, form.Statuses) + if err != nil { + return nil, errWithCode + } + + if err := p.state.DB.UpdateFilter(ctx, filter, filterColumns, filterKeywordColumns, deleteFilterKeywordIDs, deleteFilterStatusIDs); err != nil { if errors.Is(err, db.ErrAlreadyExists) { err = errors.New("you already have a filter with this title") return nil, gtserror.NewErrorConflict(err, err.Error()) @@ -117,10 +124,6 @@ func (p *Processor) Update( return nil, gtserror.NewErrorInternalError(err) } - // Re-attach keywords and statuses before returning. - filter.Keywords = filterKeywords - filter.Statuses = filterStatuses - apiFilter, errWithCode := p.apiFilter(ctx, filter) if errWithCode != nil { return nil, errWithCode @@ -131,3 +134,131 @@ func (p *Processor) Update( return apiFilter, nil } + +// applyKeywordChanges applies the provided changes to the filter's keywords in place, +// and returns a list of lists of filter columns to update, and a list of filter keyword IDs to delete. +func applyKeywordChanges(filter *gtsmodel.Filter, formKeywords []apimodel.FilterKeywordCreateUpdateDeleteRequest) ([][]string, []string, gtserror.WithCode) { + if len(formKeywords) == 0 { + // Detach currently existing keywords from the filter so we don't change them. + filter.Keywords = nil + return nil, nil, nil + } + + deleteFilterKeywordIDs := []string{} + filterKeywordsByID := map[string]*gtsmodel.FilterKeyword{} + filterKeywordColumnsByID := map[string][]string{} + for _, filterKeyword := range filter.Keywords { + filterKeywordsByID[filterKeyword.ID] = filterKeyword + } + + for _, formKeyword := range formKeywords { + if formKeyword.ID != nil { + id := *formKeyword.ID + filterKeyword, ok := filterKeywordsByID[id] + if !ok { + return nil, nil, gtserror.NewErrorNotFound( + fmt.Errorf("couldn't find filter keyword '%s' to update or delete", id), + ) + } + + // Process deletes. + if *formKeyword.Destroy { + delete(filterKeywordsByID, id) + deleteFilterKeywordIDs = append(deleteFilterKeywordIDs, id) + continue + } + + // Process updates. + columns := make([]string, 0, 2) + if formKeyword.Keyword != nil { + columns = append(columns, "keyword") + filterKeyword.Keyword = *formKeyword.Keyword + } + if formKeyword.WholeWord != nil { + columns = append(columns, "whole_word") + filterKeyword.WholeWord = formKeyword.WholeWord + } + filterKeywordColumnsByID[id] = columns + continue + } + + // Process creates. + filterKeyword := >smodel.FilterKeyword{ + ID: id.NewULID(), + AccountID: filter.AccountID, + FilterID: filter.ID, + Filter: filter, + Keyword: *formKeyword.Keyword, + WholeWord: util.Ptr(util.PtrValueOr(formKeyword.WholeWord, false)), + } + filterKeywordsByID[filterKeyword.ID] = filterKeyword + // Don't need to set columns, as we're using all of them. + } + + // Replace the filter's keywords list with our updated version. + filterKeywordColumns := [][]string{} + filter.Keywords = nil + for id, filterKeyword := range filterKeywordsByID { + filter.Keywords = append(filter.Keywords, filterKeyword) + // Okay to use the nil slice zero value for entries being created instead of updated. + filterKeywordColumns = append(filterKeywordColumns, filterKeywordColumnsByID[id]) + } + + return filterKeywordColumns, deleteFilterKeywordIDs, nil +} + +// applyKeywordChanges applies the provided changes to the filter's keywords in place, +// and returns a list of filter status IDs to delete. +func applyStatusChanges(filter *gtsmodel.Filter, formStatuses []apimodel.FilterStatusCreateDeleteRequest) ([]string, gtserror.WithCode) { + if len(formStatuses) == 0 { + // Detach currently existing statuses from the filter so we don't change them. + filter.Statuses = nil + return nil, nil + } + + deleteFilterStatusIDs := []string{} + filterStatusesByID := map[string]*gtsmodel.FilterStatus{} + for _, filterStatus := range filter.Statuses { + filterStatusesByID[filterStatus.ID] = filterStatus + } + + for _, formStatus := range formStatuses { + if formStatus.ID != nil { + id := *formStatus.ID + _, ok := filterStatusesByID[id] + if !ok { + return nil, gtserror.NewErrorNotFound( + fmt.Errorf("couldn't find filter status '%s' to delete", id), + ) + } + + // Process deletes. + if *formStatus.Destroy { + delete(filterStatusesByID, id) + deleteFilterStatusIDs = append(deleteFilterStatusIDs, id) + continue + } + + // Filter statuses don't have updates. + continue + } + + // Process creates. + filterStatus := >smodel.FilterStatus{ + ID: id.NewULID(), + AccountID: filter.AccountID, + FilterID: filter.ID, + Filter: filter, + StatusID: *formStatus.StatusID, + } + filterStatusesByID[filterStatus.ID] = filterStatus + } + + // Replace the filter's keywords list with our updated version. + filter.Statuses = nil + for _, filterStatus := range filterStatusesByID { + filter.Statuses = append(filter.Statuses, filterStatus) + } + + return deleteFilterStatusIDs, nil +} |