feat(filters): show enabled and disabled actions in list view (#1304)

* feat(filters): reflect enabled actions

* dont store release unless enabled action found

* store the release after the delay

* add new parameter to FindByFilterID method
This commit is contained in:
soup 2023-12-17 21:18:26 +01:00 committed by GitHub
parent 95cd053db5
commit 6e12654f6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 59 additions and 45 deletions

View file

@ -20,7 +20,7 @@ type Service interface {
Store(ctx context.Context, action domain.Action) (*domain.Action, error)
List(ctx context.Context) ([]domain.Action, error)
Get(ctx context.Context, req *domain.GetActionRequest) (*domain.Action, error)
FindByFilterID(ctx context.Context, filterID int) ([]*domain.Action, error)
FindByFilterID(ctx context.Context, filterID int, active *bool) ([]*domain.Action, error)
Delete(ctx context.Context, req *domain.DeleteActionRequest) error
DeleteByFilterID(ctx context.Context, filterID int) error
ToggleEnabled(actionID int) error
@ -76,8 +76,8 @@ func (s *service) Get(ctx context.Context, req *domain.GetActionRequest) (*domai
return a, nil
}
func (s *service) FindByFilterID(ctx context.Context, filterID int) ([]*domain.Action, error) {
return s.repo.FindByFilterID(ctx, filterID)
func (s *service) FindByFilterID(ctx context.Context, filterID int, active *bool) ([]*domain.Action, error) {
return s.repo.FindByFilterID(ctx, filterID, active)
}
func (s *service) Delete(ctx context.Context, req *domain.DeleteActionRequest) error {

View file

@ -30,7 +30,7 @@ func NewActionRepo(log logger.Logger, db *DB, clientRepo domain.DownloadClientRe
}
}
func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]*domain.Action, error) {
func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int, active *bool) ([]*domain.Action, error) {
tx, err := r.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
if err != nil {
return nil, err
@ -38,7 +38,7 @@ func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]*domai
defer tx.Rollback()
actions, err := r.findByFilterID(ctx, tx, filterID)
actions, err := r.findByFilterID(ctx, tx, filterID, active)
if err != nil {
return nil, err
}
@ -59,7 +59,7 @@ func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]*domai
return actions, nil
}
func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) ([]*domain.Action, error) {
func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int, active *bool) ([]*domain.Action, error) {
queryBuilder := r.db.squirrel.
Select(
"id",
@ -95,6 +95,10 @@ func (r *ActionRepo) findByFilterID(ctx context.Context, tx *Tx, filterID int) (
From("action").
Where(sq.Eq{"filter_id": filterID})
if active != nil {
queryBuilder = queryBuilder.Where(sq.Eq{"enabled": *active})
}
query, args, err := queryBuilder.ToSql()
if err != nil {
return nil, errors.Wrap(err, "error building query")

View file

@ -214,7 +214,7 @@ func TestActionRepo_FindByFilterID(t *testing.T) {
assert.NoError(t, err)
// Actual test for FindByFilterID
actions, err := repo.FindByFilterID(context.Background(), createdFilters[0].ID)
actions, err := repo.FindByFilterID(context.Background(), createdFilters[0].ID, nil)
assert.NoError(t, err)
assert.NotNil(t, actions)
assert.Equal(t, 1, len(actions))
@ -235,7 +235,7 @@ func TestActionRepo_FindByFilterID(t *testing.T) {
assert.NotNil(t, createdFilters)
// Actual test for FindByFilterID
actions, err := repo.FindByFilterID(context.Background(), createdFilters[0].ID)
actions, err := repo.FindByFilterID(context.Background(), createdFilters[0].ID, nil)
assert.NoError(t, err)
assert.Equal(t, 0, len(actions))
@ -244,7 +244,7 @@ func TestActionRepo_FindByFilterID(t *testing.T) {
})
t.Run(fmt.Sprintf("FindByFilterID_Succeeds_With_Invalid_FilterID [%s]", dbType), func(t *testing.T) {
actions, err := repo.FindByFilterID(context.Background(), 9999) // 9999 is an invalid filter ID
actions, err := repo.FindByFilterID(context.Background(), 9999, nil) // 9999 is an invalid filter ID
assert.NoError(t, err)
assert.NotNil(t, actions)
assert.Equal(t, 0, len(actions))
@ -254,7 +254,7 @@ func TestActionRepo_FindByFilterID(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
defer cancel()
actions, err := repo.FindByFilterID(ctx, 1)
actions, err := repo.FindByFilterID(ctx, 1, nil)
assert.Error(t, err)
assert.Nil(t, actions)
})

View file

@ -57,6 +57,12 @@ func (r *FilterRepo) find(ctx context.Context, tx *Tx, params domain.FilterQuery
From("action a").
Where("a.filter_id = f.id")
actionEnabledCountQuery := r.db.squirrel.
Select("COUNT(*)").
From("action a").
Where("a.filter_id = f.id").
Where("a.enabled = '1'")
queryBuilder := r.db.squirrel.
Select(
"f.id",
@ -68,6 +74,7 @@ func (r *FilterRepo) find(ctx context.Context, tx *Tx, params domain.FilterQuery
).
Distinct().
Column(sq.Alias(actionCountQuery, "action_count")).
Column(sq.Alias(actionEnabledCountQuery, "actions_enabled_count")).
LeftJoin("filter_indexer fi ON f.id = fi.filter_id").
LeftJoin("indexer i ON i.id = fi.indexer_id").
From("filter f")
@ -89,7 +96,6 @@ func (r *FilterRepo) find(ctx context.Context, tx *Tx, params domain.FilterQuery
for _, v := range params.Filters.Indexers {
filter = append(filter, sq.Eq{"i.identifier": v})
}
queryBuilder = queryBuilder.Where(filter)
}
@ -102,14 +108,13 @@ func (r *FilterRepo) find(ctx context.Context, tx *Tx, params domain.FilterQuery
if err != nil {
return nil, errors.Wrap(err, "error executing query")
}
defer rows.Close()
var filters []domain.Filter
for rows.Next() {
var f domain.Filter
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Priority, &f.CreatedAt, &f.UpdatedAt, &f.ActionsCount); err != nil {
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Priority, &f.CreatedAt, &f.UpdatedAt, &f.ActionsCount, &f.ActionsEnabledCount); err != nil {
return nil, errors.Wrap(err, "error scanning row")
}

View file

@ -14,7 +14,7 @@ import (
type ActionRepo interface {
Store(ctx context.Context, action Action) (*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, active *bool) ([]*Action, error)
List(ctx context.Context) ([]Action, error)
Get(ctx context.Context, req *GetActionRequest) (*Action, error)
Delete(ctx context.Context, req *DeleteActionRequest) error

View file

@ -133,6 +133,7 @@ type Filter struct {
ExceptDescription string `json:"except_description,omitempty"`
UseRegexDescription bool `json:"use_regex_description,omitempty"`
ActionsCount int `json:"actions_count"`
ActionsEnabledCount int `json:"actions_enabled_count"`
Actions []*Action `json:"actions,omitempty"`
External []FilterExternal `json:"external,omitempty"`
Indexers []Indexer `json:"indexers"`

View file

@ -118,7 +118,7 @@ func (s *service) FindByID(ctx context.Context, filterID int) (*domain.Filter, e
return nil, err
}
actions, err := s.actionRepo.FindByFilterID(ctx, filter.ID)
actions, err := s.actionRepo.FindByFilterID(ctx, filter.ID, nil)
if err != nil {
s.log.Error().Err(err).Msgf("could not find filter actions for filter id: %v", filter.ID)
}
@ -691,7 +691,7 @@ func (s *service) webhook(ctx context.Context, external domain.FilterExternal, r
}
// add header to req
req.Header.Add(http.CanonicalHeaderKey(h[0]), h[1])
req.Header.Add(h[0], h[1]) // go already canonicalizes the provided header key.
}
}

View file

@ -162,6 +162,27 @@ func (s *service) processFilters(ctx context.Context, filters []*domain.Filter,
l.Info().Msgf("Matched '%s' (%s) for %s", release.TorrentName, release.FilterName, release.Indexer)
// found matching filter, lets find the filter actions and attach
active := true
actions, err := s.actionSvc.FindByFilterID(ctx, f.ID, &active)
if err != nil {
s.log.Error().Err(err).Msgf("release.Process: error finding actions for filter: %s", f.Name)
return err
}
// if no actions, continue to next filter
if len(actions) == 0 {
s.log.Warn().Msgf("release.Process: no active actions found for filter '%s', trying next one..", f.Name)
continue
}
// sleep for the delay period specified in the filter before running actions
delay := release.Filter.Delay
if delay > 0 {
l.Debug().Msgf("release.Process: delaying processing of '%s' (%s) for %s by %d seconds as specified in the filter", release.TorrentName, release.FilterName, release.Indexer, delay)
time.Sleep(time.Duration(delay) * time.Second)
}
// save release here to only save those with rejections from actions instead of all releases
if release.ID == 0 {
release.FilterStatus = domain.ReleaseStatusFilterApproved
@ -172,26 +193,6 @@ func (s *service) processFilters(ctx context.Context, filters []*domain.Filter,
}
}
// found matching filter, lets find the filter actions and attach
actions, err := s.actionSvc.FindByFilterID(ctx, f.ID)
if err != nil {
s.log.Error().Err(err).Msgf("release.Process: error finding actions for filter: %s", f.Name)
return err
}
// if no actions, continue to next filter
if len(actions) == 0 {
s.log.Warn().Msgf("release.Process: no actions found for filter '%s', trying next one..", f.Name)
return nil
}
// sleep for the delay period specified in the filter before running actions
delay := release.Filter.Delay
if delay > 0 {
l.Debug().Msgf("release.Process: delaying processing of '%s' (%s) for %s by %d seconds as specified in the filter", release.TorrentName, release.FilterName, release.Indexer, delay)
time.Sleep(time.Duration(delay) * time.Second)
}
var rejections []string
// run actions (watchFolder, test, exec, qBittorrent, Deluge, arr etc.)