From 12e3cb71c1057f526ef9a0b9cc8204ad61ddd4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Thu, 14 Aug 2025 12:54:56 +0200 Subject: [PATCH] [bugfix] insert filter keywords/statuses into DB when creating new filters (#4376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't see an issue for this, but the endpoint used for creating filters simply didn't store the filter keywords/statuses in the DB. Signed-off-by: nicole mikołajczyk Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4376 Co-authored-by: nicole mikołajczyk Co-committed-by: nicole mikołajczyk --- internal/processing/filters/v2/create.go | 140 +++++++++++++++++++---- 1 file changed, 120 insertions(+), 20 deletions(-) diff --git a/internal/processing/filters/v2/create.go b/internal/processing/filters/v2/create.go index 154d80ee1..93f93d493 100644 --- a/internal/processing/filters/v2/create.go +++ b/internal/processing/filters/v2/create.go @@ -64,30 +64,29 @@ func (p *Processor) Create(ctx context.Context, requester *gtsmodel.Account, for } // Create new attached filter keywords. - for _, keyword := range form.Keywords { - filterKeyword := >smodel.FilterKeyword{ - ID: id.NewULID(), - FilterID: filter.ID, - Keyword: keyword.Keyword, - WholeWord: keyword.WholeWord, - } - - // Append the new filter key word to filter itself. - filter.Keywords = append(filter.Keywords, filterKeyword) - filter.KeywordIDs = append(filter.KeywordIDs, filterKeyword.ID) + keywordQueries, errWithCode := p.createFilterKeywords(ctx, + filter, form.Keywords) + if errWithCode != nil { + return nil, errWithCode } // Create new attached filter statuses. - for _, status := range form.Statuses { - filterStatus := >smodel.FilterStatus{ - ID: id.NewULID(), - FilterID: filter.ID, - StatusID: status.StatusID, - } + statusQueries, errWithCode := p.createFilterStatuses(ctx, + filter, form.Statuses) + if errWithCode != nil { + return nil, errWithCode + } - // Append the new filter status to filter itself. - filter.Statuses = append(filter.Statuses, filterStatus) - filter.StatusIDs = append(filter.StatusIDs, filterStatus.ID) + for _, keywordCreate := range keywordQueries { + if errWithCode := keywordCreate(); errWithCode != nil { + return nil, errWithCode + } + } + + for _, statusCreate := range statusQueries { + if errWithCode := statusCreate(); errWithCode != nil { + return nil, errWithCode + } } // Insert the new filter model into the database. @@ -110,3 +109,104 @@ func (p *Processor) Create(ctx context.Context, requester *gtsmodel.Account, for // Return as converted frontend filter model. return typeutils.FilterToAPIFilterV2(filter), nil } + +func (p *Processor) createFilterKeywords(ctx context.Context, filter *gtsmodel.Filter, form []apimodel.FilterKeywordCreateUpdateRequest) ([]func() gtserror.WithCode, gtserror.WithCode) { + if len(form) == 0 { + // No keywords created. + return nil, nil + } + + var deferred []func() gtserror.WithCode + + // Create filter keywords in the database. + for _, request := range form { + // Check for valid request. + if request.Keyword == "" { + const text = "missing keyword" + return deferred, gtserror.NewWithCode(http.StatusBadRequest, text) + } + + // Create new filter keyword for insert. + filterKeyword := >smodel.FilterKeyword{ + ID: id.NewULID(), + FilterID: filter.ID, + Keyword: request.Keyword, + WholeWord: request.WholeWord, + } + + // Verify that this is valid regular expression. + if err := filterKeyword.Compile(); err != nil { + const text = "invalid regular expression" + err := gtserror.Newf("invalid regular expression: %w", err) + return deferred, gtserror.NewWithCodeSafe( + http.StatusBadRequest, + err, text, + ) + } + + // Append new filter keyword to filter and list of IDs. + filter.Keywords = append(filter.Keywords, filterKeyword) + filter.KeywordIDs = append(filter.KeywordIDs, filterKeyword.ID) + + // Append database insert to funcs for later processing by caller. + deferred = append(deferred, func() gtserror.WithCode { + if err := p.state.DB.PutFilterKeyword(ctx, filterKeyword); // + err != nil { + if errors.Is(err, db.ErrAlreadyExists) { + const text = "duplicate keyword" + return gtserror.NewWithCode(http.StatusConflict, text) + } + err := gtserror.Newf("error inserting filter keyword: %w", err) + return gtserror.NewErrorInternalError(err) + } + return nil + }) + } + + return deferred, nil +} + +func (p *Processor) createFilterStatuses(ctx context.Context, filter *gtsmodel.Filter, form []apimodel.FilterStatusCreateRequest) ([]func() gtserror.WithCode, gtserror.WithCode) { + if len(form) == 0 { + // No statuses added. + return nil, nil + } + + var deferred []func() gtserror.WithCode + + // Create filter statuses in the database. + for _, request := range form { + // Check for valid request. + if request.StatusID == "" { + const text = "missing status" + return deferred, gtserror.NewWithCode(http.StatusBadRequest, text) + } + + // Create new filter status for insert. + filterStatus := >smodel.FilterStatus{ + ID: id.NewULID(), + FilterID: filter.ID, + StatusID: request.StatusID, + } + + // Append new filter status to filter and list of IDs. + filter.Statuses = append(filter.Statuses, filterStatus) + filter.StatusIDs = append(filter.StatusIDs, filterStatus.ID) + + // Append database insert to funcs for later processing by caller. + deferred = append(deferred, func() gtserror.WithCode { + if err := p.state.DB.PutFilterStatus(ctx, filterStatus); // + err != nil { + if errors.Is(err, db.ErrAlreadyExists) { + const text = "duplicate status" + return gtserror.NewWithCode(http.StatusConflict, text) + } + err := gtserror.Newf("error inserting filter status: %w", err) + return gtserror.NewErrorInternalError(err) + } + return nil + }) + } + + return deferred, nil +}