fix(indexes): toggle on and off with switch (#1164)

* chore(indexers): replace array position with id

* fix(indexers): enable and disable without editing

* feat(indexer): add toggle endpoint and refactoring

---------

Co-authored-by: ze0s <ze0s@riseup.net>
This commit is contained in:
Fabricio Silva 2023-10-03 20:57:11 +01:00 committed by GitHub
parent 603191b47d
commit 8600d3a2ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 167 additions and 50 deletions

View file

@ -232,3 +232,25 @@ func (r *IndexerRepo) Delete(ctx context.Context, id int) error {
return nil
}
func (r *IndexerRepo) ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error {
var err error
queryBuilder := r.db.squirrel.
Update("indexer").
Set("enabled", enabled).
Set("updated_at", sq.Expr("CURRENT_TIMESTAMP")).
Where(sq.Eq{"id": indexerID})
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
}

View file

@ -22,6 +22,7 @@ type IndexerRepo interface {
Delete(ctx context.Context, id int) error
FindByFilterID(ctx context.Context, id int) ([]Indexer, error)
FindByID(ctx context.Context, id int) (*Indexer, error)
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
}
type Indexer struct {

View file

@ -22,6 +22,7 @@ type indexerService interface {
GetTemplates() ([]domain.IndexerDefinition, error)
Delete(ctx context.Context, id int) error
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
}
type indexerHandler struct {
@ -41,13 +42,15 @@ func newIndexerHandler(encoder encoder, service indexerService, ircSvc ircServic
func (h indexerHandler) Routes(r chi.Router) {
r.Get("/schema", h.getSchema)
r.Post("/", h.store)
r.Put("/", h.update)
r.Get("/", h.getAll)
r.Get("/options", h.list)
r.Route("/{indexerID}", func(r chi.Router) {
r.Put("/", h.update)
r.Delete("/", h.delete)
r.Post("/api/test", h.testApi)
r.Patch("/enabled", h.toggleEnabled)
})
}
@ -178,3 +181,31 @@ func (h indexerHandler) testApi(w http.ResponseWriter, r *http.Request) {
h.encoder.StatusResponse(w, http.StatusOK, res)
}
func (h indexerHandler) toggleEnabled(w http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
indexerID = chi.URLParam(r, "indexerID")
data struct {
Enabled bool `json:"enabled"`
}
)
id, err := strconv.Atoi(indexerID)
if err != nil {
h.encoder.Error(w, err)
return
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
h.encoder.Error(w, err)
return
}
if err := h.service.ToggleEnabled(ctx, id, data.Enabled); err != nil {
h.encoder.Error(w, err)
return
}
h.encoder.NoContent(w)
}

View file

@ -36,6 +36,7 @@ type Service interface {
GetTorznabIndexers() []domain.IndexerDefinition
Start() error
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
}
type service struct {
@ -77,8 +78,7 @@ func NewService(log logger.Logger, config *domain.Config, repo domain.IndexerRep
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
// if indexer is rss or torznab do additional cleanup for identifier
switch indexer.Implementation {
case "torznab", "newznab", "rss":
if isImplFeed(indexer.Implementation) {
// make lowercase
cleanName := strings.ToLower(indexer.Name)
@ -114,7 +114,7 @@ func (s *service) Update(ctx context.Context, indexer domain.Indexer) (*domain.I
return nil, err
}
if indexer.Implementation == "torznab" || indexer.Implementation == "rss" {
if isImplFeed(indexer.Implementation) {
if !indexer.Enabled {
s.stopFeed(indexer.Identifier)
}
@ -220,12 +220,9 @@ func (s *service) mapIndexers() (map[string]*domain.IndexerDefinition, error) {
func (s *service) mapIndexer(indexer domain.Indexer) (*domain.IndexerDefinition, error) {
definitionName := indexer.Identifier
if indexer.Implementation == "torznab" {
definitionName = "torznab"
} else if indexer.Implementation == "newznab" {
definitionName = "newznab"
} else if indexer.Implementation == "rss" {
definitionName = "rss"
if isImplFeed(indexer.Implementation) {
definitionName = indexer.Implementation
}
d := s.getDefinitionByName(definitionName)
@ -332,7 +329,8 @@ func (s *service) Start() error {
}
for _, indexer := range indexerDefinitions {
if indexer.IRC != nil {
switch indexer.Implementation {
case string(domain.IndexerImplementationIRC):
// add to irc server lookup table
s.mapIRCServerDefinitionLookup(indexer.IRC.Server, indexer)
@ -342,15 +340,16 @@ func (s *service) Start() error {
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
}
}
}
// handle Torznab
if indexer.Implementation == "torznab" {
s.torznabIndexers[indexer.Identifier] = indexer
} else if indexer.Implementation == "newznab" {
s.newznabIndexers[indexer.Identifier] = indexer
} else if indexer.Implementation == "rss" {
// handle feeds
case string(domain.IndexerImplementationRSS):
s.rssIndexers[indexer.Identifier] = indexer
case string(domain.IndexerImplementationTorznab):
s.torznabIndexers[indexer.Identifier] = indexer
case string(domain.IndexerImplementationNewznab):
s.newznabIndexers[indexer.Identifier] = indexer
}
}
@ -360,13 +359,16 @@ func (s *service) Start() error {
}
func (s *service) removeIndexer(indexer domain.Indexer) {
// remove Torznab
if indexer.Implementation == "torznab" {
delete(s.torznabIndexers, indexer.Identifier)
} else if indexer.Implementation == "newznab" {
delete(s.newznabIndexers, indexer.Identifier)
} else if indexer.Implementation == "rss" {
// handle feeds
switch indexer.Implementation {
case string(domain.IndexerImplementationRSS):
delete(s.rssIndexers, indexer.Identifier)
case string(domain.IndexerImplementationTorznab):
delete(s.torznabIndexers, indexer.Identifier)
case string(domain.IndexerImplementationNewznab):
delete(s.newznabIndexers, indexer.Identifier)
}
// remove mapped definition
@ -383,7 +385,8 @@ func (s *service) addIndexer(indexer domain.Indexer) error {
return errors.New("addindexer: could not find definition")
}
if indexerDefinition.IRC != nil {
switch indexer.Implementation {
case string(domain.IndexerImplementationIRC):
// add to irc server lookup table
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
@ -393,15 +396,16 @@ func (s *service) addIndexer(indexer domain.Indexer) error {
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
}
}
}
// handle Torznab and RSS
if indexerDefinition.Implementation == "torznab" {
s.torznabIndexers[indexer.Identifier] = indexerDefinition
} else if indexer.Implementation == "newznab" {
s.newznabIndexers[indexer.Identifier] = indexerDefinition
} else if indexerDefinition.Implementation == "rss" {
// handle feeds
case string(domain.IndexerImplementationRSS):
s.rssIndexers[indexer.Identifier] = indexerDefinition
case string(domain.IndexerImplementationTorznab):
s.torznabIndexers[indexer.Identifier] = indexerDefinition
case string(domain.IndexerImplementationNewznab):
s.newznabIndexers[indexer.Identifier] = indexerDefinition
}
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
@ -419,7 +423,8 @@ func (s *service) updateIndexer(indexer domain.Indexer) error {
return errors.New("update indexer: could not find definition")
}
if indexerDefinition.IRC != nil {
switch indexer.Implementation {
case string(domain.IndexerImplementationIRC):
// add to irc server lookup table
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
@ -429,15 +434,16 @@ func (s *service) updateIndexer(indexer domain.Indexer) error {
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
}
}
}
// handle Torznab
if indexerDefinition.Implementation == "torznab" {
s.torznabIndexers[indexer.Identifier] = indexerDefinition
} else if indexer.Implementation == "newznab" {
s.newznabIndexers[indexer.Identifier] = indexerDefinition
} else if indexerDefinition.Implementation == "rss" {
// handle feeds
case string(domain.IndexerImplementationRSS):
s.rssIndexers[indexer.Identifier] = indexerDefinition
case string(domain.IndexerImplementationTorznab):
s.torznabIndexers[indexer.Identifier] = indexerDefinition
case string(domain.IndexerImplementationNewznab):
s.newznabIndexers[indexer.Identifier] = indexerDefinition
}
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
@ -672,3 +678,40 @@ func (s *service) TestApi(ctx context.Context, req domain.IndexerTestApiRequest)
return nil
}
func (s *service) ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error {
indexer, err := s.FindByID(ctx, indexerID)
if err != nil {
return err
}
if err := s.repo.ToggleEnabled(ctx, int(indexer.ID), enabled); err != nil {
s.log.Error().Err(err).Msg("could not update indexer enabled")
return err
}
// update indexerInstances
if err := s.updateIndexer(*indexer); err != nil {
s.log.Error().Err(err).Msgf("failed to add indexer: %s", indexer.Name)
return err
}
if isImplFeed(indexer.Implementation) {
if !indexer.Enabled {
s.stopFeed(indexer.Identifier)
}
}
s.log.Debug().Msgf("indexer.toggle_enabled: update indexer '%d' to '%v'", indexerID, enabled)
return nil
}
func isImplFeed(implementation string) bool {
switch implementation {
case "torznab", "newznab", "rss":
return true
default:
return false
}
}