fix(feeds): indexer identifier issues (#538)

* fix(torznab/rss): keep original name

* fix(feeds): get identifier via indexer join

* fix(feeds/web): remove identifier slugify
This commit is contained in:
Kyle Sanderson 2022-11-17 09:50:40 -08:00 committed by GitHub
parent dc42ca0042
commit a93b54bbbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 90 deletions

View file

@ -27,22 +27,23 @@ type FeedRepo struct {
func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) { func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select( Select(
"id", "f.id",
"indexer", "i.identifier",
"name", "f.name",
"type", "f.type",
"enabled", "f.enabled",
"url", "f.url",
"interval", "f.interval",
"timeout", "f.timeout",
"max_age", "f.max_age",
"api_key", "f.api_key",
"cookie", "f.cookie",
"created_at", "f.created_at",
"updated_at", "f.updated_at",
). ).
From("feed"). From("feed f").
Where("id = ?", id) Join("indexer i ON f.indexer_id = i.id").
Where("f.id = ?", id)
query, args, err := queryBuilder.ToSql() query, args, err := queryBuilder.ToSql()
if err != nil { if err != nil {
@ -72,22 +73,23 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) (*domain.Feed, error) { func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) (*domain.Feed, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select( Select(
"id", "f.id",
"indexer", "i.identifier",
"name", "f.name",
"type", "f.type",
"enabled", "f.enabled",
"url", "f.url",
"interval", "f.interval",
"timeout", "f.timeout",
"max_age", "f.max_age",
"api_key", "f.api_key",
"cookie", "f.cookie",
"created_at", "f.created_at",
"updated_at", "f.updated_at",
). ).
From("feed"). From("feed f").
Where("indexer = ?", indexer) Join("indexer i ON f.indexer_id = i.id").
Where("i.name = ?", indexer)
query, args, err := queryBuilder.ToSql() query, args, err := queryBuilder.ToSql()
if err != nil { if err != nil {
@ -105,7 +107,6 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &f.CreatedAt, &f.UpdatedAt); err != nil { if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &f.CreatedAt, &f.UpdatedAt); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
f.ApiKey = apiKey.String f.ApiKey = apiKey.String
@ -117,24 +118,25 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) { func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select( Select(
"id", "f.id",
"indexer", "i.identifier",
"name", "f.name",
"type", "f.type",
"enabled", "f.enabled",
"url", "f.url",
"interval", "f.interval",
"timeout", "f.timeout",
"max_age", "f.max_age",
"api_key", "f.api_key",
"cookie", "f.cookie",
"last_run", "f.last_run",
"last_run_data", "f.last_run_data",
"created_at", "f.created_at",
"updated_at", "f.updated_at",
). ).
From("feed"). From("feed f").
OrderBy("name ASC") Join("indexer i ON f.indexer_id = i.id").
OrderBy("f.name ASC")
query, args, err := queryBuilder.ToSql() query, args, err := queryBuilder.ToSql()
if err != nil { if err != nil {
@ -175,7 +177,6 @@ func (r *FeedRepo) Store(ctx context.Context, feed *domain.Feed) error {
Insert("feed"). Insert("feed").
Columns( Columns(
"name", "name",
"indexer",
"type", "type",
"enabled", "enabled",
"url", "url",
@ -186,7 +187,6 @@ func (r *FeedRepo) Store(ctx context.Context, feed *domain.Feed) error {
). ).
Values( Values(
feed.Name, feed.Name,
feed.Indexer,
feed.Type, feed.Type,
feed.Enabled, feed.Enabled,
feed.URL, feed.URL,
@ -212,7 +212,6 @@ func (r *FeedRepo) Update(ctx context.Context, feed *domain.Feed) error {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Update("feed"). Update("feed").
Set("name", feed.Name). Set("name", feed.Name).
Set("indexer", feed.Indexer).
Set("type", feed.Type). Set("type", feed.Type).
Set("enabled", feed.Enabled). Set("enabled", feed.Enabled).
Set("url", feed.URL). Set("url", feed.URL).

View file

@ -69,22 +69,17 @@ func NewService(log logger.Logger, config *domain.Config, repo domain.IndexerRep
} }
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) { func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
identifier := indexer.Identifier
// if indexer is rss or torznab do additional cleanup for identifier
switch indexer.Implementation { switch indexer.Implementation {
case "torznab": case "torznab", "rss":
// if the name already contains torznab remove it // make lowercase
cleanName := strings.ReplaceAll(strings.ToLower(indexer.Name), "torznab", "") cleanName := strings.ToLower(indexer.Name)
identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName)) // torznab-name
case "rss": // torznab-name OR rss-name
// if the name already contains rss remove it indexer.Identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName))
cleanName := strings.ReplaceAll(strings.ToLower(indexer.Name), "rss", "")
identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName)) // rss-name
} }
indexer.Identifier = identifier
i, err := s.repo.Store(ctx, indexer) i, err := s.repo.Store(ctx, indexer)
if err != nil { if err != nil {
s.log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name) s.log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name)
@ -92,8 +87,7 @@ func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.In
} }
// add to indexerInstances // add to indexerInstances
err = s.addIndexer(*i) if err = s.addIndexer(*i); err != nil {
if err != nil {
s.log.Error().Stack().Err(err).Msgf("failed to add indexer: %v", indexer.Name) s.log.Error().Stack().Err(err).Msgf("failed to add indexer: %v", indexer.Name)
return nil, err return nil, err
} }

View file

@ -2,13 +2,13 @@ import { Fragment, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useMutation, useQuery } from "react-query"; import { useMutation, useQuery } from "react-query";
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select"; import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
import type { FieldProps, FormikErrors } from "formik"; import type { FieldProps } from "formik";
import { Field, Form, Formik, FormikValues } from "formik"; import { Field, Form, Formik, FormikValues } from "formik";
import { XMarkIcon } from "@heroicons/react/24/solid"; import { XMarkIcon } from "@heroicons/react/24/solid";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { sleep, slugify } from "../../utils"; import { sleep } from "../../utils";
import { queryClient } from "../../App"; import { queryClient } from "../../App";
import DEBUG from "../../components/debug"; import DEBUG from "../../components/debug";
import { APIClient } from "../../api/APIClient"; import { APIClient } from "../../api/APIClient";
@ -183,15 +183,6 @@ const SettingFields = (ind: IndexerDefinition, indexer: string) => {
} }
}; };
function slugIdentifier(name: string, prefix?: string) {
const l = name.toLowerCase();
if (prefix && prefix !== "") {
const r = l.replaceAll(prefix, "");
return slugify(`${prefix}-${r}`);
}
return slugify(l);
}
type SelectValue = { type SelectValue = {
label: string; label: string;
value: string; value: string;
@ -236,15 +227,11 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
); );
const onSubmit = (formData: FormikValues) => { const onSubmit = (formData: FormikValues) => {
console.log("form: ", formData);
const ind = data && data.find(i => i.identifier === formData.identifier); const ind = data && data.find(i => i.identifier === formData.identifier);
if (!ind) if (!ind)
return; return;
if (formData.implementation === "torznab") { if (formData.implementation === "torznab") {
// create slug for indexer identifier as "torznab-indexer_name"
const name = slugIdentifier(formData.name, "torznab");
const createFeed: FeedCreate = { const createFeed: FeedCreate = {
name: formData.name, name: formData.name,
enabled: false, enabled: false,
@ -253,7 +240,6 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
api_key: formData.feed.api_key, api_key: formData.feed.api_key,
interval: 30, interval: 30,
timeout: 60, timeout: 60,
indexer: name,
indexer_id: 0 indexer_id: 0
}; };
@ -266,12 +252,8 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
} }
}); });
return; return;
}
if (formData.implementation === "rss") {
// create slug for indexer identifier as "torznab-indexer_name"
const name = slugIdentifier(formData.name, "rss");
} else if (formData.implementation === "rss") {
const createFeed: FeedCreate = { const createFeed: FeedCreate = {
name: formData.name, name: formData.name,
enabled: false, enabled: false,
@ -279,7 +261,6 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
url: formData.feed.url, url: formData.feed.url,
interval: 30, interval: 30,
timeout: 60, timeout: 60,
indexer: name,
indexer_id: 0 indexer_id: 0
}; };
@ -292,10 +273,8 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
} }
}); });
return; return;
}
if (formData.implementation === "irc") {
} else if (formData.implementation === "irc") {
const channels: IrcChannel[] = []; const channels: IrcChannel[] = [];
if (ind.irc?.channels.length) { if (ind.irc?.channels.length) {
ind.irc.channels.forEach(element => { ind.irc.channels.forEach(element => {

View file

@ -19,7 +19,6 @@ interface Feed {
type FeedType = "TORZNAB" | "RSS"; type FeedType = "TORZNAB" | "RSS";
interface FeedCreate { interface FeedCreate {
indexer: string;
name: string; name: string;
type: FeedType; type: FeedType;
enabled: boolean; enabled: boolean;