fix(filters): store and update with no external filters (#1049)

* fix(filters): store and update

* fix(filters): bad fmt var

* fix(filters): store expect status

* fix(filters): store expect status

* fix(filters): external filter always rejected
This commit is contained in:
ze0s 2023-08-17 21:42:43 +02:00 committed by GitHub
parent 0fa53b0b2e
commit 3e244fac10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 151 additions and 125 deletions

View file

@ -186,10 +186,11 @@ func (r *ActionRepo) attachDownloadClient(ctx context.Context, tx *Tx, clientID
var settingsJsonStr string var settingsJsonStr string
if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.TLS, &client.TLSSkipVerify, &client.Username, &client.Password, &settingsJsonStr); err != nil { if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.TLS, &client.TLSSkipVerify, &client.Username, &client.Password, &settingsJsonStr); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
r.log.Warn().Msgf("no download client with id %d", clientID) r.log.Warn().Msgf("no download client with id %d", clientID)
return nil, nil return nil, domain.ErrRecordNotFound
} }
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
@ -346,8 +347,8 @@ func (r *ActionRepo) Get(ctx context.Context, req *domain.GetActionRequest) (*do
var paused, ignoreRules sql.NullBool var paused, ignoreRules sql.NullBool
if err := row.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID, &filterID); err != nil { if err := row.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &limitRatio, &limitSeedTime, &a.ReAnnounceSkip, &a.ReAnnounceDelete, &a.ReAnnounceInterval, &a.ReAnnounceMaxAttempts, &webhookHost, &webhookType, &webhookMethod, &webhookData, &clientID, &filterID); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
return nil, nil return nil, domain.ErrRecordNotFound
} }
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
@ -506,14 +507,14 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
// return values // return values
var retID int64 var retID int64
err := queryBuilder.QueryRowContext(ctx).Scan(&retID) if err := queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
if err != nil {
return nil, errors.Wrap(err, "error executing query") return nil, errors.Wrap(err, "error executing query")
} }
r.log.Debug().Msgf("action.store: added new %v", retID)
action.ID = int(retID) action.ID = int(retID)
r.log.Debug().Msgf("action.store: added new %d", retID)
return &action, nil return &action, nil
} }
@ -588,7 +589,7 @@ func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain.
return &action, nil return &action, nil
} }
func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []*domain.Action, filterID int64) ([]*domain.Action, error) { func (r *ActionRepo) StoreFilterActions(ctx context.Context, filterID int64, actions []*domain.Action) ([]*domain.Action, error) {
tx, err := r.db.handler.BeginTx(ctx, nil) tx, err := r.db.handler.BeginTx(ctx, nil)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error begin transaction") return nil, errors.Wrap(err, "error begin transaction")

View file

@ -156,7 +156,7 @@ func (r *DownloadClientRepo) FindByID(ctx context.Context, id int32) (*domain.Do
var settingsJsonStr string var settingsJsonStr string
if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.TLS, &client.TLSSkipVerify, &client.Username, &client.Password, &settingsJsonStr); err != nil { if err := row.Scan(&client.ID, &client.Name, &client.Type, &client.Enabled, &client.Host, &client.Port, &client.TLS, &client.TLSSkipVerify, &client.Username, &client.Password, &settingsJsonStr); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
return nil, errors.New("no client configured") return nil, errors.New("no client configured")
} }

View file

@ -52,7 +52,11 @@ func (r *FeedCacheRepo) Get(bucket string, key string) ([]byte, error) {
var value []byte var value []byte
var ttl time.Duration var ttl time.Duration
if err := row.Scan(&value, &ttl); err != nil && err != sql.ErrNoRows { if err := row.Scan(&value, &ttl); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
@ -143,7 +147,11 @@ func (r *FeedCacheRepo) Exists(bucket string, key string) (bool, error) {
var exists bool var exists bool
err = r.db.handler.QueryRow(query, args...).Scan(&exists) err = r.db.handler.QueryRow(query, args...).Scan(&exists)
if err != nil && err != sql.ErrNoRows { if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, domain.ErrRecordNotFound
}
return false, errors.Wrap(err, "error query") return false, errors.Wrap(err, "error query")
} }

View file

@ -769,7 +769,7 @@ func (r *FilterRepo) FindExternalFiltersByID(ctx context.Context, filterId int)
return externalFilters, nil return externalFilters, nil
} }
func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) { func (r *FilterRepo) Store(ctx context.Context, filter *domain.Filter) error {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Insert("filter"). Insert("filter").
Columns( Columns(
@ -896,15 +896,15 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
var retID int var retID int
if err := queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil { if err := queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
return nil, errors.Wrap(err, "error executing query") return errors.Wrap(err, "error executing query")
} }
filter.ID = retID filter.ID = retID
return &filter, nil return nil
} }
func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) { func (r *FilterRepo) Update(ctx context.Context, filter *domain.Filter) error {
var err error var err error
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
@ -971,15 +971,15 @@ func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.
query, args, err := queryBuilder.ToSql() query, args, err := queryBuilder.ToSql()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error building query") return errors.Wrap(err, "error building query")
} }
_, err = r.db.handler.ExecContext(ctx, query, args...) _, err = r.db.handler.ExecContext(ctx, query, args...)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error executing query") return errors.Wrap(err, "error executing query")
} }
return &filter, nil return nil
} }
func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error { func (r *FilterRepo) UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error {
@ -1245,13 +1245,23 @@ func (r *FilterRepo) StoreIndexerConnections(ctx context.Context, filterID int,
if err != nil { if err != nil {
return errors.Wrap(err, "error building query") return errors.Wrap(err, "error building query")
} }
_, err = tx.ExecContext(ctx, deleteQuery, deleteArgs...) _, err = tx.ExecContext(ctx, deleteQuery, deleteArgs...)
if err != nil { if err != nil {
return errors.Wrap(err, "error executing query") return errors.Wrap(err, "error executing query")
} }
if len(indexers) == 0 {
if err := tx.Commit(); err != nil {
return errors.Wrap(err, "error store indexers for filter: %d", filterID)
}
return nil
}
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Insert("filter_indexer").Columns("filter_id", "indexer_id") Insert("filter_indexer").
Columns("filter_id", "indexer_id")
for _, indexer := range indexers { for _, indexer := range indexers {
queryBuilder = queryBuilder.Values(filterID, indexer.ID) queryBuilder = queryBuilder.Values(filterID, indexer.ID)
@ -1311,6 +1321,24 @@ func (r *FilterRepo) DeleteIndexerConnections(ctx context.Context, filterID int)
return nil return nil
} }
func (r *FilterRepo) DeleteFilterExternal(ctx context.Context, filterID int) error {
queryBuilder := r.db.squirrel.
Delete("filter_external").
Where(sq.Eq{"filter_id": filterID})
query, args, err := queryBuilder.ToSql()
if err != nil {
return errors.Wrap(err, "error building query")
}
_, err = r.db.handler.ExecContext(ctx, query, args...)
if err != nil {
return errors.Wrap(err, "error executing query")
}
return nil
}
func (r *FilterRepo) Delete(ctx context.Context, filterID int) error { func (r *FilterRepo) Delete(ctx context.Context, filterID int) error {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Delete("filter"). Delete("filter").
@ -1411,6 +1439,14 @@ func (r *FilterRepo) StoreFilterExternal(ctx context.Context, filterID int, exte
return errors.Wrap(err, "error executing query") return errors.Wrap(err, "error executing query")
} }
if len(externalFilters) == 0 {
if err := tx.Commit(); err != nil {
return errors.Wrap(err, "error delete external filters for filter: %d", filterID)
}
return nil
}
qb := r.db.squirrel. qb := r.db.squirrel.
Insert("filter_external"). Insert("filter_external").
Columns( Columns(

View file

@ -260,12 +260,12 @@ func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcN
var tls sql.NullBool var tls sql.NullBool
if err = row.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &nick, &net.Auth.Mechanism, &account, &password, &inviteCmd, &bouncerAddr, &net.UseBouncer); err != nil { if err = row.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &nick, &net.Auth.Mechanism, &account, &password, &inviteCmd, &bouncerAddr, &net.UseBouncer); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
// no result is not an error in our case // no result is not an error in our case
return nil, nil return nil, nil
} else {
return nil, errors.Wrap(err, "error scanning row")
} }
return nil, errors.Wrap(err, "error scanning row")
} }
net.TLS = tls.Bool net.TLS = tls.Bool

View file

@ -425,7 +425,7 @@ func (repo *ReleaseRepo) Get(ctx context.Context, req *domain.GetReleaseRequest)
var filterId sql.NullInt64 var filterId sql.NullInt64
if err := row.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &indexerName, &filterName, &filterId, &rls.Protocol, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Timestamp); err != nil { if err := row.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &indexerName, &filterName, &filterId, &rls.Protocol, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Timestamp); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
return nil, nil return nil, nil
} }
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
@ -468,7 +468,7 @@ func (repo *ReleaseRepo) GetActionStatus(ctx context.Context, req *domain.GetRel
var actionId, filterId sql.NullInt64 var actionId, filterId sql.NullInt64
if err := row.Scan(&rls.ID, &rls.Status, &rls.Action, &actionId, &rls.Type, &client, &filter, &filterId, &rls.ReleaseID, pq.Array(&rls.Rejections), &rls.Timestamp); err != nil { if err := row.Scan(&rls.ID, &rls.Status, &rls.Action, &actionId, &rls.Type, &client, &filter, &filterId, &rls.ReleaseID, pq.Array(&rls.Rejections), &rls.Timestamp); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
return nil, nil return nil, nil
} }

View file

@ -68,8 +68,8 @@ func (r *UserRepo) FindByUsername(ctx context.Context, username string) (*domain
var user domain.User var user domain.User
if err := row.Scan(&user.ID, &user.Username, &user.Password); err != nil { if err := row.Scan(&user.ID, &user.Username, &user.Password); err != nil {
if err == sql.ErrNoRows { if errors.Is(err, sql.ErrNoRows) {
return nil, nil return nil, domain.ErrRecordNotFound
} }
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")

View file

@ -13,7 +13,7 @@ import (
type ActionRepo interface { type ActionRepo interface {
Store(ctx context.Context, action Action) (*Action, error) Store(ctx context.Context, action Action) (*Action, error)
StoreFilterActions(ctx context.Context, actions []*Action, filterID int64) ([]*Action, error) StoreFilterActions(ctx context.Context, filterID int64, actions []*Action) ([]*Action, error)
FindByFilterID(ctx context.Context, filterID int) ([]*Action, error) FindByFilterID(ctx context.Context, filterID int) ([]*Action, error)
List(ctx context.Context) ([]Action, error) List(ctx context.Context) ([]Action, error)
Get(ctx context.Context, req *GetActionRequest) (*Action, error) Get(ctx context.Context, req *GetActionRequest) (*Action, error)

View file

@ -26,8 +26,8 @@ type FilterRepo interface {
FindByID(ctx context.Context, filterID int) (*Filter, error) FindByID(ctx context.Context, filterID int) (*Filter, error)
FindByIndexerIdentifier(ctx context.Context, indexer string) ([]Filter, error) FindByIndexerIdentifier(ctx context.Context, indexer string) ([]Filter, error)
FindExternalFiltersByID(ctx context.Context, filterId int) ([]FilterExternal, error) FindExternalFiltersByID(ctx context.Context, filterId int) ([]FilterExternal, error)
Store(ctx context.Context, filter Filter) (*Filter, error) Store(ctx context.Context, filter *Filter) error
Update(ctx context.Context, filter Filter) (*Filter, error) Update(ctx context.Context, filter *Filter) error
UpdatePartial(ctx context.Context, filter FilterUpdate) error UpdatePartial(ctx context.Context, filter FilterUpdate) error
ToggleEnabled(ctx context.Context, filterID int, enabled bool) error ToggleEnabled(ctx context.Context, filterID int, enabled bool) error
Delete(ctx context.Context, filterID int) error Delete(ctx context.Context, filterID int) error
@ -35,6 +35,7 @@ type FilterRepo interface {
StoreIndexerConnections(ctx context.Context, filterID int, indexers []Indexer) error StoreIndexerConnections(ctx context.Context, filterID int, indexers []Indexer) error
StoreFilterExternal(ctx context.Context, filterID int, externalFilters []FilterExternal) error StoreFilterExternal(ctx context.Context, filterID int, externalFilters []FilterExternal) error
DeleteIndexerConnections(ctx context.Context, filterID int) error DeleteIndexerConnections(ctx context.Context, filterID int) error
DeleteFilterExternal(ctx context.Context, filterID int) error
GetDownloadsByFilterId(ctx context.Context, filterID int) (*FilterDownloads, error) GetDownloadsByFilterId(ctx context.Context, filterID int) (*FilterDownloads, error)
} }
@ -129,14 +130,6 @@ type Filter struct {
MatchDescription string `json:"match_description,omitempty"` MatchDescription string `json:"match_description,omitempty"`
ExceptDescription string `json:"except_description,omitempty"` ExceptDescription string `json:"except_description,omitempty"`
UseRegexDescription bool `json:"use_regex_description,omitempty"` UseRegexDescription bool `json:"use_regex_description,omitempty"`
//ExternalScriptEnabled bool `json:"external_script_enabled,omitempty"`
//ExternalScriptCmd string `json:"external_script_cmd,omitempty"`
//ExternalScriptArgs string `json:"external_script_args,omitempty"`
//ExternalScriptExpectStatus int `json:"external_script_expect_status,omitempty"`
//ExternalWebhookEnabled bool `json:"external_webhook_enabled,omitempty"`
//ExternalWebhookHost string `json:"external_webhook_host,omitempty"`
//ExternalWebhookData string `json:"external_webhook_data,omitempty"`
//ExternalWebhookExpectStatus int `json:"external_webhook_expect_status,omitempty"`
ActionsCount int `json:"actions_count"` ActionsCount int `json:"actions_count"`
Actions []*Action `json:"actions,omitempty"` Actions []*Action `json:"actions,omitempty"`
External []FilterExternal `json:"external,omitempty"` External []FilterExternal `json:"external,omitempty"`
@ -240,6 +233,7 @@ type FilterUpdate struct {
ExternalWebhookData *string `json:"external_webhook_data,omitempty"` ExternalWebhookData *string `json:"external_webhook_data,omitempty"`
ExternalWebhookExpectStatus *int `json:"external_webhook_expect_status,omitempty"` ExternalWebhookExpectStatus *int `json:"external_webhook_expect_status,omitempty"`
Actions []*Action `json:"actions,omitempty"` Actions []*Action `json:"actions,omitempty"`
External []FilterExternal `json:"external,omitempty"`
Indexers []Indexer `json:"indexers,omitempty"` Indexers []Indexer `json:"indexers,omitempty"`
} }

View file

@ -32,8 +32,8 @@ type Service interface {
Find(ctx context.Context, params domain.FilterQueryParams) ([]domain.Filter, error) Find(ctx context.Context, params domain.FilterQueryParams) ([]domain.Filter, error)
CheckFilter(ctx context.Context, f domain.Filter, release *domain.Release) (bool, error) CheckFilter(ctx context.Context, f domain.Filter, release *domain.Release) (bool, error)
ListFilters(ctx context.Context) ([]domain.Filter, error) ListFilters(ctx context.Context) ([]domain.Filter, error)
Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) Store(ctx context.Context, filter *domain.Filter) error
Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) Update(ctx context.Context, filter *domain.Filter) error
UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error
Duplicate(ctx context.Context, filterID int) (*domain.Filter, error) Duplicate(ctx context.Context, filterID int) (*domain.Filter, error)
ToggleEnabled(ctx context.Context, filterID int, enabled bool) error ToggleEnabled(ctx context.Context, filterID int, enabled bool) error
@ -145,54 +145,53 @@ func (s *service) GetDownloadsByFilterId(ctx context.Context, filterID int) (*do
return s.GetDownloadsByFilterId(ctx, filterID) return s.GetDownloadsByFilterId(ctx, filterID)
} }
func (s *service) Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) { func (s *service) Store(ctx context.Context, filter *domain.Filter) error {
// validate data // validate data
// store // store
f, err := s.repo.Store(ctx, filter) err := s.repo.Store(ctx, filter)
if err != nil { if err != nil {
s.log.Error().Err(err).Msgf("could not store filter: %v", filter) s.log.Error().Err(err).Msgf("could not store filter: %v", filter)
return nil, err return err
} }
return f, nil return nil
} }
func (s *service) Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) { func (s *service) Update(ctx context.Context, filter *domain.Filter) error {
// validate data // validate data
if filter.Name == "" { if filter.Name == "" {
return nil, errors.New("validation: name can't be empty") return errors.New("validation: name can't be empty")
} }
// update // update
f, err := s.repo.Update(ctx, filter) if err := s.repo.Update(ctx, filter); err != nil {
if err != nil {
s.log.Error().Err(err).Msgf("could not update filter: %s", filter.Name) s.log.Error().Err(err).Msgf("could not update filter: %s", filter.Name)
return nil, err return err
} }
// take care of connected indexers // take care of connected indexers
if err = s.repo.StoreIndexerConnections(ctx, f.ID, filter.Indexers); err != nil { if err := s.repo.StoreIndexerConnections(ctx, filter.ID, filter.Indexers); err != nil {
s.log.Error().Err(err).Msgf("could not store filter indexer connections: %s", filter.Name) s.log.Error().Err(err).Msgf("could not store filter indexer connections: %s", filter.Name)
return nil, err return err
} }
// take care of connected external filters // take care of connected external filters
if err = s.repo.StoreFilterExternal(ctx, f.ID, filter.External); err != nil { if err := s.repo.StoreFilterExternal(ctx, filter.ID, filter.External); err != nil {
s.log.Error().Err(err).Msgf("could not store external filters: %s", filter.Name) s.log.Error().Err(err).Msgf("could not store external filters: %s", filter.Name)
return nil, err return err
} }
// take care of filter actions // take care of filter actions
actions, err := s.actionRepo.StoreFilterActions(ctx, filter.Actions, int64(filter.ID)) actions, err := s.actionRepo.StoreFilterActions(ctx, int64(filter.ID), filter.Actions)
if err != nil { if err != nil {
s.log.Error().Err(err).Msgf("could not store filter actions: %s", filter.Name) s.log.Error().Err(err).Msgf("could not store filter actions: %s", filter.Name)
return nil, err return err
} }
f.Actions = actions filter.Actions = actions
return f, nil return nil
} }
func (s *service) UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error { func (s *service) UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error {
@ -211,9 +210,17 @@ func (s *service) UpdatePartial(ctx context.Context, filter domain.FilterUpdate)
} }
} }
if filter.External != nil {
// take care of connected external filters
if err := s.repo.StoreFilterExternal(ctx, filter.ID, filter.External); err != nil {
s.log.Error().Err(err).Msgf("could not store external filters: %v", filter.Name)
return err
}
}
if filter.Actions != nil { if filter.Actions != nil {
// take care of filter actions // take care of filter actions
if _, err := s.actionRepo.StoreFilterActions(ctx, filter.Actions, int64(filter.ID)); err != nil { if _, err := s.actionRepo.StoreFilterActions(ctx, int64(filter.ID), filter.Actions); err != nil {
s.log.Error().Err(err).Msgf("could not store filter actions: %v", filter.ID) s.log.Error().Err(err).Msgf("could not store filter actions: %v", filter.ID)
return err return err
} }
@ -223,57 +230,48 @@ func (s *service) UpdatePartial(ctx context.Context, filter domain.FilterUpdate)
} }
func (s *service) Duplicate(ctx context.Context, filterID int) (*domain.Filter, error) { func (s *service) Duplicate(ctx context.Context, filterID int) (*domain.Filter, error) {
// find filter // find filter with actions, indexers and external filters
baseFilter, err := s.repo.FindByID(ctx, filterID) filter, err := s.FindByID(ctx, filterID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
baseFilter.ID = 0
baseFilter.Name = fmt.Sprintf("%v Copy", baseFilter.Name)
baseFilter.Enabled = false
// find actions and attach // reset id and name
filterActions, err := s.actionRepo.FindByFilterID(ctx, filterID) filter.ID = 0
if err != nil { filter.Name = fmt.Sprintf("%s Copy", filter.Name)
s.log.Error().Msgf("could not find filter actions: %+v", &filterID) filter.Enabled = false
return nil, err
}
// find indexers and attach // store new filter
filterIndexers, err := s.indexerSvc.FindByFilterID(ctx, filterID) if err := s.repo.Store(ctx, filter); err != nil {
if err != nil { s.log.Error().Err(err).Msgf("could not update filter: %s", filter.Name)
s.log.Error().Err(err).Msgf("could not find indexers for filter: %+v", &baseFilter.Name)
return nil, err
}
// update
filter, err := s.repo.Store(ctx, *baseFilter)
if err != nil {
s.log.Error().Err(err).Msgf("could not update filter: %v", baseFilter.Name)
return nil, err return nil, err
} }
// take care of connected indexers // take care of connected indexers
if err = s.repo.StoreIndexerConnections(ctx, filter.ID, filterIndexers); err != nil { if err := s.repo.StoreIndexerConnections(ctx, filter.ID, filter.Indexers); err != nil {
s.log.Error().Err(err).Msgf("could not store filter indexer connections: %v", filter.Name) s.log.Error().Err(err).Msgf("could not store filter indexer connections: %s", filter.Name)
return nil, err return nil, err
} }
filter.Indexers = filterIndexers
// reset action id to 0 // reset action id to 0
for i, a := range filterActions { for i, a := range filter.Actions {
a := a
a.ID = 0 a.ID = 0
filterActions[i] = a filter.Actions[i] = a
} }
// take care of filter actions // take care of filter actions
actions, err := s.actionRepo.StoreFilterActions(ctx, filterActions, int64(filter.ID)) if _, err := s.actionRepo.StoreFilterActions(ctx, int64(filter.ID), filter.Actions); err != nil {
if err != nil { s.log.Error().Err(err).Msgf("could not store filter actions: %s", filter.Name)
s.log.Error().Err(err).Msgf("could not store filter actions: %v", filter.Name)
return nil, err return nil, err
} }
filter.Actions = actions // take care of connected external filters
// the external filters are fetched with FindByID
if err := s.repo.StoreFilterExternal(ctx, filter.ID, filter.External); err != nil {
s.log.Error().Err(err).Msgf("could not store external filters: %s", filter.Name)
return nil, err
}
return filter, nil return filter, nil
} }
@ -306,6 +304,12 @@ func (s *service) Delete(ctx context.Context, filterID int) error {
return err return err
} }
// delete filter external
if err := s.repo.DeleteFilterExternal(ctx, filterID); err != nil {
s.log.Error().Err(err).Msgf("could not delete filter external: %v", filterID)
return err
}
// delete filter // delete filter
if err := s.repo.Delete(ctx, filterID); err != nil { if err := s.repo.Delete(ctx, filterID); err != nil {
s.log.Error().Err(err).Msgf("could not delete filter: %v", filterID) s.log.Error().Err(err).Msgf("could not delete filter: %v", filterID)
@ -537,7 +541,7 @@ func (s *service) RunExternalFilters(ctx context.Context, externalFilters []doma
} }
} }
return false, nil return true, nil
} }
func (s *service) execCmd(ctx context.Context, external domain.FilterExternal, release *domain.Release) (int, error) { func (s *service) execCmd(ctx context.Context, external domain.FilterExternal, release *domain.Release) (int, error) {

View file

@ -21,9 +21,9 @@ type filterService interface {
ListFilters(ctx context.Context) ([]domain.Filter, error) ListFilters(ctx context.Context) ([]domain.Filter, error)
FindByID(ctx context.Context, filterID int) (*domain.Filter, error) FindByID(ctx context.Context, filterID int) (*domain.Filter, error)
Find(ctx context.Context, params domain.FilterQueryParams) ([]domain.Filter, error) Find(ctx context.Context, params domain.FilterQueryParams) ([]domain.Filter, error)
Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) Store(ctx context.Context, filter *domain.Filter) error
Delete(ctx context.Context, filterID int) error Delete(ctx context.Context, filterID int) error
Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) Update(ctx context.Context, filter *domain.Filter) error
UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error UpdatePartial(ctx context.Context, filter domain.FilterUpdate) error
Duplicate(ctx context.Context, filterID int) (*domain.Filter, error) Duplicate(ctx context.Context, filterID int) (*domain.Filter, error)
ToggleEnabled(ctx context.Context, filterID int, enabled bool) error ToggleEnabled(ctx context.Context, filterID int, enabled bool) error
@ -144,7 +144,7 @@ func (h filterHandler) duplicate(w http.ResponseWriter, r *http.Request) {
filter, err := h.service.Duplicate(ctx, id) filter, err := h.service.Duplicate(ctx, id)
if err != nil { if err != nil {
h.encoder.StatusNotFound(w) h.encoder.StatusInternalError(w)
return return
} }
@ -154,7 +154,7 @@ func (h filterHandler) duplicate(w http.ResponseWriter, r *http.Request) {
func (h filterHandler) store(w http.ResponseWriter, r *http.Request) { func (h filterHandler) store(w http.ResponseWriter, r *http.Request) {
var ( var (
ctx = r.Context() ctx = r.Context()
data domain.Filter data *domain.Filter
) )
if err := json.NewDecoder(r.Body).Decode(&data); err != nil { if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
@ -162,19 +162,18 @@ func (h filterHandler) store(w http.ResponseWriter, r *http.Request) {
return return
} }
filter, err := h.service.Store(ctx, data) if err := h.service.Store(ctx, data); err != nil {
if err != nil {
h.encoder.Error(w, err) h.encoder.Error(w, err)
return return
} }
h.encoder.StatusCreatedData(w, filter) h.encoder.StatusCreatedData(w, data)
} }
func (h filterHandler) update(w http.ResponseWriter, r *http.Request) { func (h filterHandler) update(w http.ResponseWriter, r *http.Request) {
var ( var (
ctx = r.Context() ctx = r.Context()
data domain.Filter data *domain.Filter
) )
if err := json.NewDecoder(r.Body).Decode(&data); err != nil { if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
@ -182,13 +181,12 @@ func (h filterHandler) update(w http.ResponseWriter, r *http.Request) {
return return
} }
filter, err := h.service.Update(ctx, data) if err := h.service.Update(ctx, data); err != nil {
if err != nil {
h.encoder.Error(w, err) h.encoder.Error(w, err)
return return
} }
h.encoder.StatusResponse(w, http.StatusOK, filter) h.encoder.StatusResponse(w, http.StatusOK, data)
} }
func (h filterHandler) updatePartial(w http.ResponseWriter, r *http.Request) { func (h filterHandler) updatePartial(w http.ResponseWriter, r *http.Request) {

View file

@ -226,7 +226,7 @@ const schema = z.object({
name: z.string(), name: z.string(),
indexers: z.array(indexerSchema).min(1, { message: "Must select at least one indexer" }), indexers: z.array(indexerSchema).min(1, { message: "Must select at least one indexer" }),
actions: z.array(actionSchema), actions: z.array(actionSchema),
external: z.array(externalFilterSchema) external: z.array(externalFilterSchema),
}); });
export function FilterDetails() { export function FilterDetails() {
@ -398,14 +398,6 @@ export function FilterDetails() {
indexers: filter.indexers || [], indexers: filter.indexers || [],
actions: filter.actions || [], actions: filter.actions || [],
external: filter.external || [], external: filter.external || [],
external_script_enabled: filter.external_script_enabled || false,
external_script_cmd: filter.external_script_cmd || "",
external_script_args: filter.external_script_args || "",
external_script_expect_status: filter.external_script_expect_status || 0,
external_webhook_enabled: filter.external_webhook_enabled || false,
external_webhook_host: filter.external_webhook_host || "",
external_webhook_data: filter.external_webhook_data ||"",
external_webhook_expect_status: filter.external_webhook_expect_status || 0
} as Filter} } as Filter}
onSubmit={handleSubmit} onSubmit={handleSubmit}
enableReinitialize={true} enableReinitialize={true}

View file

@ -280,10 +280,9 @@ const TypeForm = ({external, idx}: TypeFormProps) => {
</div> </div>
<div className="mt-6 grid grid-cols-12 gap-6"> <div className="mt-6 grid grid-cols-12 gap-6">
<NumberField <NumberField
name={`external.${idx}.script_expected_status`} name={`external.${idx}.exec_expect_status`}
label="Expected exit status" label="Expected exit status"
placeholder="0" placeholder="0"
/> />
</div> </div>
</div> </div>
@ -320,7 +319,7 @@ const TypeForm = ({external, idx}: TypeFormProps) => {
/> />
<NumberField <NumberField
name={`external.${idx}.webhook_expected_status`} name={`external.${idx}.webhook_expect_status`}
label="Expected http status" label="Expected http status"
placeholder="200" placeholder="200"
/> />

View file

@ -71,14 +71,6 @@ interface Filter {
actions: Action[]; actions: Action[];
indexers: Indexer[]; indexers: Indexer[];
external: ExternalFilter[]; external: ExternalFilter[];
external_script_enabled: boolean;
external_script_cmd: string;
external_script_args: string;
external_script_expect_status: number;
external_webhook_enabled: boolean;
external_webhook_host: string;
external_webhook_data: string;
external_webhook_expect_status: number;
} }
interface Action { interface Action {
@ -130,10 +122,12 @@ interface ExternalFilter {
enabled: boolean; enabled: boolean;
exec_cmd?: string; exec_cmd?: string;
exec_args?: string; exec_args?: string;
exec_expect_status?: number;
webhook_host?: string, webhook_host?: string,
webhook_type?: string; webhook_type?: string;
webhook_method?: WebhookMethod; webhook_method?: WebhookMethod;
webhook_data?: string, webhook_data?: string,
webhook_headers?: string; webhook_headers?: string;
webhook_expect_status?: number;
filter_id?: number; filter_id?: number;
} }