mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
feat: add postgres support (#215)
* feat: add postgres support and refactor * feat: improve releases find * fix: autobrrctl create user
This commit is contained in:
parent
f6873e932e
commit
3185832708
30 changed files with 1708 additions and 831 deletions
|
@ -54,16 +54,19 @@ func main() {
|
||||||
// setup logger
|
// setup logger
|
||||||
logger.Setup(cfg, serverEvents)
|
logger.Setup(cfg, serverEvents)
|
||||||
|
|
||||||
log.Info().Msg("Starting autobrr")
|
|
||||||
log.Info().Msgf("Version: %v", version)
|
|
||||||
log.Info().Msgf("Log-level: %v", cfg.LogLevel)
|
|
||||||
|
|
||||||
// open database connection
|
// open database connection
|
||||||
db, _ := database.NewDB(cfg)
|
db, _ := database.NewDB(cfg)
|
||||||
if err := db.Open(); err != nil {
|
if err := db.Open(); err != nil {
|
||||||
log.Fatal().Err(err).Msg("could not open db connection")
|
log.Fatal().Err(err).Msg("could not open db connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Msgf("Starting autobrr")
|
||||||
|
log.Info().Msgf("Version: %v", version)
|
||||||
|
log.Info().Msgf("Commit: %v", commit)
|
||||||
|
log.Info().Msgf("Build date: %v", date)
|
||||||
|
log.Info().Msgf("Log-level: %v", cfg.LogLevel)
|
||||||
|
log.Info().Msgf("Using database: %v", db.Driver)
|
||||||
|
|
||||||
// setup repos
|
// setup repos
|
||||||
var (
|
var (
|
||||||
actionRepo = database.NewActionRepo(db)
|
actionRepo = database.NewActionRepo(db)
|
||||||
|
|
|
@ -39,7 +39,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// open database connection
|
// open database connection
|
||||||
db, _ := database.NewDB(domain.Config{ConfigPath: configPath})
|
db, _ := database.NewDB(domain.Config{ConfigPath: configPath, DatabaseType: "sqlite"})
|
||||||
if err := db.Open(); err != nil {
|
if err := db.Open(); err != nil {
|
||||||
log.Fatal("could not open db connection")
|
log.Fatal("could not open db connection")
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Password = hashed
|
user.Password = hashed
|
||||||
if err := userRepo.Store(context.Background(), *user); err != nil {
|
if err := userRepo.Update(context.Background(), *user); err != nil {
|
||||||
log.Fatalf("failed to create user: %v", err)
|
log.Fatalf("failed to create user: %v", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Store(ctx context.Context, action domain.Action) (*domain.Action, error)
|
Store(ctx context.Context, action domain.Action) (*domain.Action, error)
|
||||||
Fetch() ([]domain.Action, error)
|
List(ctx context.Context) ([]domain.Action, error)
|
||||||
Delete(actionID int) error
|
Delete(actionID int) error
|
||||||
DeleteByFilterID(ctx context.Context, filterID int) error
|
DeleteByFilterID(ctx context.Context, filterID int) error
|
||||||
ToggleEnabled(actionID int) error
|
ToggleEnabled(actionID int) error
|
||||||
|
@ -31,45 +31,21 @@ func NewService(repo domain.ActionRepo, clientSvc download_client.Service, bus E
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Store(ctx context.Context, action domain.Action) (*domain.Action, error) {
|
func (s *service) Store(ctx context.Context, action domain.Action) (*domain.Action, error) {
|
||||||
// validate data
|
return s.repo.Store(ctx, action)
|
||||||
|
|
||||||
a, err := s.repo.Store(ctx, action)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return a, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Delete(actionID int) error {
|
func (s *service) Delete(actionID int) error {
|
||||||
if err := s.repo.Delete(actionID); err != nil {
|
return s.repo.Delete(actionID)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) DeleteByFilterID(ctx context.Context, filterID int) error {
|
func (s *service) DeleteByFilterID(ctx context.Context, filterID int) error {
|
||||||
if err := s.repo.DeleteByFilterID(ctx, filterID); err != nil {
|
return s.repo.DeleteByFilterID(ctx, filterID)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Fetch() ([]domain.Action, error) {
|
func (s *service) List(ctx context.Context) ([]domain.Action, error) {
|
||||||
actions, err := s.repo.List()
|
return s.repo.List(ctx)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return actions, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) ToggleEnabled(actionID int) error {
|
func (s *service) ToggleEnabled(actionID int) error {
|
||||||
if err := s.repo.ToggleEnabled(actionID); err != nil {
|
return s.repo.ToggleEnabled(actionID)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,17 +19,47 @@ func NewActionRepo(db *DB) domain.ActionRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]domain.Action, error) {
|
func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]domain.Action, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select(
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"exec_cmd",
|
||||||
|
"exec_args",
|
||||||
|
"watch_folder",
|
||||||
|
"category",
|
||||||
|
"tags",
|
||||||
|
"label",
|
||||||
|
"save_path",
|
||||||
|
"paused",
|
||||||
|
"ignore_rules",
|
||||||
|
"limit_upload_speed",
|
||||||
|
"limit_download_speed",
|
||||||
|
"webhook_host",
|
||||||
|
"webhook_type",
|
||||||
|
"webhook_method",
|
||||||
|
"webhook_data",
|
||||||
|
"client_id",
|
||||||
|
).
|
||||||
|
From("action").
|
||||||
|
Where("filter_id = ?", filterID)
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, name, type, enabled, exec_cmd, exec_args, watch_folder, category, tags, label, save_path, paused, ignore_rules, limit_download_speed, limit_upload_speed, webhook_host, webhook_data, webhook_type, webhook_method, client_id FROM action WHERE action.filter_id = ?", filterID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("action.findByFilterID: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.findByFilterID: query error")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var actions []domain.Action
|
actions := make([]domain.Action, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var a domain.Action
|
var a domain.Action
|
||||||
|
|
||||||
|
@ -39,9 +70,7 @@ func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]domain
|
||||||
var paused, ignoreRules sql.NullBool
|
var paused, ignoreRules sql.NullBool
|
||||||
|
|
||||||
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &host, &data, &webhookType, &webhookMethod, &clientID); err != nil {
|
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &host, &data, &webhookType, &webhookMethod, &clientID); err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("action.findByFilterID: error scanning row")
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,24 +94,54 @@ func (r *ActionRepo) FindByFilterID(ctx context.Context, filterID int) ([]domain
|
||||||
actions = append(actions, a)
|
actions = append(actions, a)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.findByFilterID: row error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions, nil
|
return actions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) List() ([]domain.Action, error) {
|
func (r *ActionRepo) List(ctx context.Context) ([]domain.Action, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select(
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"exec_cmd",
|
||||||
|
"exec_args",
|
||||||
|
"watch_folder",
|
||||||
|
"category",
|
||||||
|
"tags",
|
||||||
|
"label",
|
||||||
|
"save_path",
|
||||||
|
"paused",
|
||||||
|
"ignore_rules",
|
||||||
|
"limit_upload_speed",
|
||||||
|
"limit_download_speed",
|
||||||
|
"webhook_host",
|
||||||
|
"webhook_type",
|
||||||
|
"webhook_method",
|
||||||
|
"webhook_data",
|
||||||
|
"client_id",
|
||||||
|
).
|
||||||
|
From("action")
|
||||||
|
|
||||||
rows, err := r.db.handler.Query("SELECT id, name, type, enabled, exec_cmd, exec_args, watch_folder, category, tags, label, save_path, paused, ignore_rules, limit_download_speed, limit_upload_speed, client_id FROM action")
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("action.list: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.list: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var actions []domain.Action
|
actions := make([]domain.Action, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var a domain.Action
|
var a domain.Action
|
||||||
|
|
||||||
|
@ -92,9 +151,7 @@ func (r *ActionRepo) List() ([]domain.Action, error) {
|
||||||
var paused, ignoreRules sql.NullBool
|
var paused, ignoreRules sql.NullBool
|
||||||
|
|
||||||
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &clientID); err != nil {
|
if err := rows.Scan(&a.ID, &a.Name, &a.Type, &a.Enabled, &execCmd, &execArgs, &watchFolder, &category, &tags, &label, &savePath, &paused, &ignoreRules, &limitDl, &limitUl, &clientID); err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("action.list: error scanning row")
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +168,7 @@ func (r *ActionRepo) List() ([]domain.Action, error) {
|
||||||
actions = append(actions, a)
|
actions = append(actions, a)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.list: row error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,40 +176,50 @@ func (r *ActionRepo) List() ([]domain.Action, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) Delete(actionID int) error {
|
func (r *ActionRepo) Delete(actionID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("action").
|
||||||
|
Where("id = ?", actionID)
|
||||||
|
|
||||||
res, err := r.db.handler.Exec(`DELETE FROM action WHERE action.id = ?`, actionID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.delete: error building query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, _ := res.RowsAffected()
|
_, err = r.db.handler.Exec(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.delete: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
log.Info().Msgf("rows affected %v", rows)
|
log.Debug().Msgf("action.delete: %v", actionID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) DeleteByFilterID(ctx context.Context, filterID int) error {
|
func (r *ActionRepo) DeleteByFilterID(ctx context.Context, filterID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("action").
|
||||||
|
Where("filter_id = ?", filterID)
|
||||||
|
|
||||||
_, err := r.db.handler.ExecContext(ctx, `DELETE FROM action WHERE filter_id = ?`, filterID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("actions: error deleting by filterid")
|
log.Error().Stack().Err(err).Msg("action.deleteByFilterID: error building query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msgf("actions: delete by filterid %v", filterID)
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.deleteByFilterID: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("action.deleteByFilterID: %v", filterID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.Action, error) {
|
func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.Action, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
execCmd := toNullString(action.ExecCmd)
|
execCmd := toNullString(action.ExecCmd)
|
||||||
execArgs := toNullString(action.ExecArgs)
|
execArgs := toNullString(action.ExecArgs)
|
||||||
watchFolder := toNullString(action.WatchFolder)
|
watchFolder := toNullString(action.WatchFolder)
|
||||||
|
@ -159,8 +227,89 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
|
||||||
tags := toNullString(action.Tags)
|
tags := toNullString(action.Tags)
|
||||||
label := toNullString(action.Label)
|
label := toNullString(action.Label)
|
||||||
savePath := toNullString(action.SavePath)
|
savePath := toNullString(action.SavePath)
|
||||||
host := toNullString(action.WebhookHost)
|
webhookHost := toNullString(action.WebhookHost)
|
||||||
data := toNullString(action.WebhookData)
|
webhookData := toNullString(action.WebhookData)
|
||||||
|
webhookType := toNullString(action.WebhookType)
|
||||||
|
webhookMethod := toNullString(action.WebhookMethod)
|
||||||
|
|
||||||
|
limitDL := toNullInt64(action.LimitDownloadSpeed)
|
||||||
|
limitUL := toNullInt64(action.LimitUploadSpeed)
|
||||||
|
clientID := toNullInt32(action.ClientID)
|
||||||
|
filterID := toNullInt32(int32(action.FilterID))
|
||||||
|
|
||||||
|
queryBuilder := r.db.squirrel.
|
||||||
|
Insert("action").
|
||||||
|
Columns(
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"exec_cmd",
|
||||||
|
"exec_args",
|
||||||
|
"watch_folder",
|
||||||
|
"category",
|
||||||
|
"tags",
|
||||||
|
"label",
|
||||||
|
"save_path",
|
||||||
|
"paused",
|
||||||
|
"ignore_rules",
|
||||||
|
"limit_upload_speed",
|
||||||
|
"limit_download_speed",
|
||||||
|
"webhook_host",
|
||||||
|
"webhook_type",
|
||||||
|
"webhook_method",
|
||||||
|
"webhook_data",
|
||||||
|
"client_id",
|
||||||
|
"filter_id",
|
||||||
|
).
|
||||||
|
Values(
|
||||||
|
action.Name,
|
||||||
|
action.Type,
|
||||||
|
action.Enabled,
|
||||||
|
execCmd,
|
||||||
|
execArgs,
|
||||||
|
watchFolder,
|
||||||
|
category,
|
||||||
|
tags,
|
||||||
|
label,
|
||||||
|
savePath,
|
||||||
|
action.Paused,
|
||||||
|
action.IgnoreRules,
|
||||||
|
limitUL,
|
||||||
|
limitDL,
|
||||||
|
webhookHost,
|
||||||
|
webhookType,
|
||||||
|
webhookMethod,
|
||||||
|
webhookData,
|
||||||
|
clientID,
|
||||||
|
filterID,
|
||||||
|
).
|
||||||
|
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||||
|
|
||||||
|
// return values
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.store: error executing query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("action.store: added new %v", retID)
|
||||||
|
action.ID = int(retID)
|
||||||
|
|
||||||
|
return &action, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ActionRepo) Update(ctx context.Context, action domain.Action) (*domain.Action, error) {
|
||||||
|
execCmd := toNullString(action.ExecCmd)
|
||||||
|
execArgs := toNullString(action.ExecArgs)
|
||||||
|
watchFolder := toNullString(action.WatchFolder)
|
||||||
|
category := toNullString(action.Category)
|
||||||
|
tags := toNullString(action.Tags)
|
||||||
|
label := toNullString(action.Label)
|
||||||
|
savePath := toNullString(action.SavePath)
|
||||||
|
webhookHost := toNullString(action.WebhookHost)
|
||||||
|
webhookData := toNullString(action.WebhookData)
|
||||||
webhookType := toNullString(action.WebhookType)
|
webhookType := toNullString(action.WebhookType)
|
||||||
webhookMethod := toNullString(action.WebhookMethod)
|
webhookMethod := toNullString(action.WebhookMethod)
|
||||||
|
|
||||||
|
@ -170,32 +319,49 @@ func (r *ActionRepo) Store(ctx context.Context, action domain.Action) (*domain.A
|
||||||
filterID := toNullInt32(int32(action.FilterID))
|
filterID := toNullInt32(int32(action.FilterID))
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if action.ID != 0 {
|
|
||||||
log.Debug().Msg("actions: update existing record")
|
|
||||||
_, err = r.db.handler.ExecContext(ctx, `UPDATE action SET name = ?, type = ?, enabled = ?, exec_cmd = ?, exec_args = ?, watch_folder = ? , category =? , tags = ?, label = ?, save_path = ?, paused = ?, ignore_rules = ?, limit_upload_speed = ?, limit_download_speed = ?, webhook_host = ?, webhook_data = ?, webhook_type = ?, webhook_method = ?, client_id = ?
|
|
||||||
WHERE id = ?`, action.Name, action.Type, action.Enabled, execCmd, execArgs, watchFolder, category, tags, label, savePath, action.Paused, action.IgnoreRules, limitUL, limitDL, host, data, webhookType, webhookMethod, clientID, action.ID)
|
|
||||||
} else {
|
|
||||||
var res sql.Result
|
|
||||||
|
|
||||||
res, err = r.db.handler.ExecContext(ctx, `INSERT INTO action(name, type, enabled, exec_cmd, exec_args, watch_folder, category, tags, label, save_path, paused, ignore_rules, limit_upload_speed, limit_download_speed, webhook_host, webhook_data, webhook_type, webhook_method, client_id, filter_id)
|
queryBuilder := r.db.squirrel.
|
||||||
VALUES (?, ?, ?, ?, ?,? ,?, ?,?,?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT DO NOTHING`, action.Name, action.Type, action.Enabled, execCmd, execArgs, watchFolder, category, tags, label, savePath, action.Paused, action.IgnoreRules, limitUL, limitDL, host, data, webhookType, webhookMethod, clientID, filterID)
|
Update("action").
|
||||||
if err != nil {
|
Set("name", action.Name).
|
||||||
log.Error().Err(err)
|
Set("type", action.Type).
|
||||||
return nil, err
|
Set("enabled", action.Enabled).
|
||||||
}
|
Set("exec_cmd", execCmd).
|
||||||
|
Set("exec_args", execArgs).
|
||||||
|
Set("watch_folder", watchFolder).
|
||||||
|
Set("category", category).
|
||||||
|
Set("tags", tags).
|
||||||
|
Set("label", label).
|
||||||
|
Set("save_path", savePath).
|
||||||
|
Set("paused", action.Paused).
|
||||||
|
Set("ignore_rules", action.IgnoreRules).
|
||||||
|
Set("limit_upload_speed", limitUL).
|
||||||
|
Set("limit_download_speed", limitDL).
|
||||||
|
Set("webhook_host", webhookHost).
|
||||||
|
Set("webhook_type", webhookType).
|
||||||
|
Set("webhook_method", webhookMethod).
|
||||||
|
Set("webhook_data", webhookData).
|
||||||
|
Set("client_id", clientID).
|
||||||
|
Set("filter_id", filterID).
|
||||||
|
Where("id = ?", action.ID)
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
query, args, err := queryBuilder.ToSql()
|
||||||
log.Debug().Msgf("actions: added new %v", resId)
|
if err != nil {
|
||||||
action.ID = int(resId)
|
log.Error().Stack().Err(err).Msg("action.update: error building query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.update: error executing query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("action.update: %v", action.ID)
|
||||||
|
|
||||||
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, actions []domain.Action, filterID int64) ([]domain.Action, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
tx, err := r.db.handler.BeginTx(ctx, nil)
|
tx, err := r.db.handler.BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -203,9 +369,18 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []domain.Ac
|
||||||
|
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
_, err = tx.ExecContext(ctx, `DELETE FROM action WHERE filter_id = ?`, filterID)
|
deleteQueryBuilder := r.db.squirrel.
|
||||||
|
Delete("action").
|
||||||
|
Where("filter_id = ?", filterID)
|
||||||
|
|
||||||
|
deleteQuery, deleteArgs, err := deleteQueryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting actions for filter: %v", filterID)
|
log.Error().Stack().Err(err).Msg("action.StoreFilterActions: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = tx.ExecContext(ctx, deleteQuery, deleteArgs...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.StoreFilterActions: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +392,8 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []domain.Ac
|
||||||
tags := toNullString(action.Tags)
|
tags := toNullString(action.Tags)
|
||||||
label := toNullString(action.Label)
|
label := toNullString(action.Label)
|
||||||
savePath := toNullString(action.SavePath)
|
savePath := toNullString(action.SavePath)
|
||||||
host := toNullString(action.WebhookHost)
|
webhookHost := toNullString(action.WebhookHost)
|
||||||
data := toNullString(action.WebhookData)
|
webhookData := toNullString(action.WebhookData)
|
||||||
webhookType := toNullString(action.WebhookType)
|
webhookType := toNullString(action.WebhookType)
|
||||||
webhookMethod := toNullString(action.WebhookMethod)
|
webhookMethod := toNullString(action.WebhookMethod)
|
||||||
|
|
||||||
|
@ -226,25 +401,71 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []domain.Ac
|
||||||
limitUL := toNullInt64(action.LimitUploadSpeed)
|
limitUL := toNullInt64(action.LimitUploadSpeed)
|
||||||
clientID := toNullInt32(action.ClientID)
|
clientID := toNullInt32(action.ClientID)
|
||||||
|
|
||||||
var err error
|
queryBuilder := r.db.squirrel.
|
||||||
var res sql.Result
|
Insert("action").
|
||||||
|
Columns(
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"exec_cmd",
|
||||||
|
"exec_args",
|
||||||
|
"watch_folder",
|
||||||
|
"category",
|
||||||
|
"tags",
|
||||||
|
"label",
|
||||||
|
"save_path",
|
||||||
|
"paused",
|
||||||
|
"ignore_rules",
|
||||||
|
"limit_upload_speed",
|
||||||
|
"limit_download_speed",
|
||||||
|
"webhook_host",
|
||||||
|
"webhook_type",
|
||||||
|
"webhook_method",
|
||||||
|
"webhook_data",
|
||||||
|
"client_id",
|
||||||
|
"filter_id",
|
||||||
|
).
|
||||||
|
Values(
|
||||||
|
action.Name,
|
||||||
|
action.Type,
|
||||||
|
action.Enabled,
|
||||||
|
execCmd,
|
||||||
|
execArgs,
|
||||||
|
watchFolder,
|
||||||
|
category,
|
||||||
|
tags,
|
||||||
|
label,
|
||||||
|
savePath,
|
||||||
|
action.Paused,
|
||||||
|
action.IgnoreRules,
|
||||||
|
limitUL,
|
||||||
|
limitDL,
|
||||||
|
webhookHost,
|
||||||
|
webhookType,
|
||||||
|
webhookMethod,
|
||||||
|
webhookData,
|
||||||
|
clientID,
|
||||||
|
filterID,
|
||||||
|
).
|
||||||
|
Suffix("RETURNING id").RunWith(tx)
|
||||||
|
|
||||||
res, err = tx.ExecContext(ctx, `INSERT INTO action(name, type, enabled, exec_cmd, exec_args, watch_folder, category, tags, label, save_path, paused, ignore_rules, limit_upload_speed, limit_download_speed, webhook_host, webhook_data, webhook_type, webhook_method, client_id, filter_id)
|
// return values
|
||||||
VALUES (?, ?, ?, ?, ?,? ,?, ?,?,?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT DO NOTHING`, action.Name, action.Type, action.Enabled, execCmd, execArgs, watchFolder, category, tags, label, savePath, action.Paused, action.IgnoreRules, limitUL, limitDL, host, data, webhookType, webhookMethod, clientID, filterID)
|
var retID int
|
||||||
|
|
||||||
|
err = queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("actions: error executing query")
|
log.Error().Stack().Err(err).Msg("action.StoreFilterActions: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
action.ID = retID
|
||||||
action.ID = int(resId)
|
|
||||||
|
|
||||||
log.Debug().Msgf("actions: store '%v' type: '%v' on filter: %v", action.Name, action.Type, filterID)
|
log.Debug().Msgf("action.StoreFilterActions: store '%v' type: '%v' on filter: %v", action.Name, action.Type, filterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error updating actions")
|
log.Error().Stack().Err(err).Msg("action.StoreFilterActions: error updating actions")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -253,20 +474,26 @@ func (r *ActionRepo) StoreFilterActions(ctx context.Context, actions []domain.Ac
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRepo) ToggleEnabled(actionID int) error {
|
func (r *ActionRepo) ToggleEnabled(actionID int) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var res sql.Result
|
|
||||||
|
|
||||||
res, err = r.db.handler.Exec(`UPDATE action SET enabled = NOT enabled WHERE id = ?`, actionID)
|
queryBuilder := r.db.squirrel.
|
||||||
|
Update("action").
|
||||||
|
Set("enabled", sq.Expr("NOT enabled")).
|
||||||
|
Where("id = ?", actionID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err)
|
log.Error().Stack().Err(err).Msg("action.toggleEnabled: error building query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
_, err = r.db.handler.Exec(query, args...)
|
||||||
log.Info().Msgf("LAST INSERT ID %v", resId)
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("action.toggleEnabled: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("action.toggleEnabled: %v", actionID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
|
@ -19,10 +20,15 @@ type DB struct {
|
||||||
|
|
||||||
Driver string
|
Driver string
|
||||||
DSN string
|
DSN string
|
||||||
|
|
||||||
|
squirrel sq.StatementBuilderType
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDB(cfg domain.Config) (*DB, error) {
|
func NewDB(cfg domain.Config) (*DB, error) {
|
||||||
db := &DB{}
|
db := &DB{
|
||||||
|
// set default placeholder for squirrel to support both sqlite and postgres
|
||||||
|
squirrel: sq.StatementBuilder.PlaceholderFormat(sq.Dollar),
|
||||||
|
}
|
||||||
db.ctx, db.cancel = context.WithCancel(context.Background())
|
db.ctx, db.cancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
switch cfg.DatabaseType {
|
switch cfg.DatabaseType {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -57,14 +56,34 @@ func NewDownloadClientRepo(db *DB) domain.DownloadClientRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) List(ctx context.Context) ([]domain.DownloadClient, error) {
|
func (r *DownloadClientRepo) List(ctx context.Context) ([]domain.DownloadClient, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
clients := make([]domain.DownloadClient, 0)
|
clients := make([]domain.DownloadClient, 0)
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, name, type, enabled, host, port, tls, tls_skip_verify, username, password, settings FROM client")
|
queryBuilder := r.db.squirrel.
|
||||||
|
Select(
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"host",
|
||||||
|
"port",
|
||||||
|
"tls",
|
||||||
|
"tls_skip_verify",
|
||||||
|
"username",
|
||||||
|
"password",
|
||||||
|
"settings",
|
||||||
|
).
|
||||||
|
From("client")
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
log.Error().Stack().Err(err).Msg("download_client.list: error building query")
|
||||||
return clients, err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.list: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -74,7 +93,7 @@ func (r *DownloadClientRepo) List(ctx context.Context) ([]domain.DownloadClient,
|
||||||
var settingsJsonStr string
|
var settingsJsonStr string
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Name, &f.Type, &f.Enabled, &f.Host, &f.Port, &f.TLS, &f.TLSSkipVerify, &f.Username, &f.Password, &settingsJsonStr); err != nil {
|
if err := rows.Scan(&f.ID, &f.Name, &f.Type, &f.Enabled, &f.Host, &f.Port, &f.TLS, &f.TLSSkipVerify, &f.Username, &f.Password, &settingsJsonStr); err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("could not scan download client to struct")
|
log.Error().Stack().Err(err).Msg("download_client.list: error scanning row")
|
||||||
return clients, err
|
return clients, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +107,7 @@ func (r *DownloadClientRepo) List(ctx context.Context) ([]domain.DownloadClient,
|
||||||
clients = append(clients, f)
|
clients = append(clients, f)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
log.Error().Stack().Err(err).Msg("download_client.list: row error")
|
||||||
return clients, err
|
return clients, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,20 +115,38 @@ func (r *DownloadClientRepo) List(ctx context.Context) ([]domain.DownloadClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error) {
|
func (r *DownloadClientRepo) FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
// get client from cache
|
// get client from cache
|
||||||
c := r.cache.Get(int(id))
|
c := r.cache.Get(int(id))
|
||||||
if c != nil {
|
if c != nil {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `SELECT id, name, type, enabled, host, port, tls, tls_skip_verify, username, password, settings FROM client WHERE id = ?`
|
queryBuilder := r.db.squirrel.
|
||||||
|
Select(
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"enabled",
|
||||||
|
"host",
|
||||||
|
"port",
|
||||||
|
"tls",
|
||||||
|
"tls_skip_verify",
|
||||||
|
"username",
|
||||||
|
"password",
|
||||||
|
"settings",
|
||||||
|
).
|
||||||
|
From("client").
|
||||||
|
Where("id = ?", id)
|
||||||
|
|
||||||
row := r.db.handler.QueryRowContext(ctx, query, id)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err := row.Err(); err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("could not query download client rows")
|
log.Error().Stack().Err(err).Msg("download_client.findByID: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.findByID: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +154,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 {
|
||||||
log.Error().Stack().Err(err).Msg("could not scan download client to struct")
|
log.Error().Stack().Err(err).Msg("download_client.findByID: error scanning row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,9 +169,6 @@ func (r *DownloadClientRepo) FindByID(ctx context.Context, id int32) (*domain.Do
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
|
func (r *DownloadClientRepo) Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
settings := domain.DownloadClientSettings{
|
settings := domain.DownloadClientSettings{
|
||||||
|
@ -149,79 +183,73 @@ func (r *DownloadClientRepo) Store(ctx context.Context, client domain.DownloadCl
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.ID != 0 {
|
queryBuilder := r.db.squirrel.
|
||||||
_, err = r.db.handler.ExecContext(ctx, `
|
Insert("client").
|
||||||
UPDATE
|
Columns("name", "type", "enabled", "host", "port", "tls", "tls_skip_verify", "username", "password", "settings").
|
||||||
client
|
Values(client.Name, client.Type, client.Enabled, client.Host, client.Port, client.TLS, client.TLSSkipVerify, client.Username, client.Password, settingsJson).
|
||||||
SET
|
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||||
name = ?,
|
|
||||||
type = ?,
|
|
||||||
enabled = ?,
|
|
||||||
host = ?,
|
|
||||||
port = ?,
|
|
||||||
tls = ?,
|
|
||||||
tls_skip_verify = ?,
|
|
||||||
username = ?,
|
|
||||||
password = ?,
|
|
||||||
settings = (?)
|
|
||||||
WHERE
|
|
||||||
id = ?`,
|
|
||||||
client.Name,
|
|
||||||
client.Type,
|
|
||||||
client.Enabled,
|
|
||||||
client.Host,
|
|
||||||
client.Port,
|
|
||||||
client.TLS,
|
|
||||||
client.TLSSkipVerify,
|
|
||||||
client.Username,
|
|
||||||
client.Password,
|
|
||||||
string(settingsJson),
|
|
||||||
client.ID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msgf("could not update download client: %v", client)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var res sql.Result
|
|
||||||
|
|
||||||
res, err = r.db.handler.ExecContext(ctx, `INSERT INTO
|
// return values
|
||||||
client(
|
var retID int
|
||||||
name,
|
|
||||||
type,
|
|
||||||
enabled,
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
tls,
|
|
||||||
tls_skip_verify,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
settings)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ? , ?, ?, ?, ?) ON CONFLICT DO NOTHING`,
|
|
||||||
client.Name,
|
|
||||||
client.Type,
|
|
||||||
client.Enabled,
|
|
||||||
client.Host,
|
|
||||||
client.Port,
|
|
||||||
client.TLS,
|
|
||||||
client.TLSSkipVerify,
|
|
||||||
client.Username,
|
|
||||||
client.Password,
|
|
||||||
string(settingsJson),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msgf("could not store new download client: %v", client)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
err = queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
client.ID = int(resId)
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.store: error executing query")
|
||||||
log.Trace().Msgf("download_client: store new record %d", client.ID)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("store download client: %v", client.Name)
|
client.ID = retID
|
||||||
log.Trace().Msgf("store download client: %+v", client)
|
|
||||||
|
log.Debug().Msgf("download_client.store: %d", client.ID)
|
||||||
|
|
||||||
|
// save to cache
|
||||||
|
r.cache.Set(client.ID, &client)
|
||||||
|
|
||||||
|
return &client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DownloadClientRepo) Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
settings := domain.DownloadClientSettings{
|
||||||
|
APIKey: client.Settings.APIKey,
|
||||||
|
Basic: client.Settings.Basic,
|
||||||
|
Rules: client.Settings.Rules,
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsJson, err := json.Marshal(&settings)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("could not marshal download client settings %v", settings)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
queryBuilder := r.db.squirrel.
|
||||||
|
Update("client").
|
||||||
|
Set("name", client.Name).
|
||||||
|
Set("type", client.Type).
|
||||||
|
Set("enabled", client.Enabled).
|
||||||
|
Set("host", client.Host).
|
||||||
|
Set("port", client.Port).
|
||||||
|
Set("tls", client.TLS).
|
||||||
|
Set("tls_skip_verify", client.TLSSkipVerify).
|
||||||
|
Set("username", client.Username).
|
||||||
|
Set("password", client.Password).
|
||||||
|
Set("settings", string(settingsJson)).
|
||||||
|
Where("id = ?", client.ID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.update: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.update: error querying data")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("download_client.update: %d", client.ID)
|
||||||
|
|
||||||
// save to cache
|
// save to cache
|
||||||
r.cache.Set(client.ID, &client)
|
r.cache.Set(client.ID, &client)
|
||||||
|
@ -230,12 +258,19 @@ func (r *DownloadClientRepo) Store(ctx context.Context, client domain.DownloadCl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DownloadClientRepo) Delete(ctx context.Context, clientID int) error {
|
func (r *DownloadClientRepo) Delete(ctx context.Context, clientID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("client").
|
||||||
|
Where("id = ?", clientID)
|
||||||
|
|
||||||
res, err := r.db.handler.ExecContext(ctx, `DELETE FROM client WHERE client.id = ?`, clientID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("could not delete download client: %d", clientID)
|
log.Error().Stack().Err(err).Msg("download_client.delete: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("download_client.delete: error query data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ package database
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
@ -20,12 +22,28 @@ func NewFilterRepo(db *DB) domain.FilterRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select(
|
||||||
|
"id",
|
||||||
|
"enabled",
|
||||||
|
"name",
|
||||||
|
"match_releases",
|
||||||
|
"except_releases",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
).
|
||||||
|
From("filter").
|
||||||
|
OrderBy("name ASC")
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, match_releases, except_releases, created_at, updated_at FROM filter ORDER BY name ASC")
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("filters_list: error query data")
|
log.Error().Stack().Err(err).Msg("filter.list: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.list: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +56,7 @@ func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
var matchReleases, exceptReleases sql.NullString
|
var matchReleases, exceptReleases sql.NullString
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &matchReleases, &exceptReleases, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &matchReleases, &exceptReleases, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("filters_list: error scanning data to struct")
|
log.Error().Stack().Err(err).Msg("filter.list: error scanning row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +66,7 @@ func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
filters = append(filters, f)
|
filters = append(filters, f)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.list: row error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,11 +74,64 @@ func (r *FilterRepo) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter, error) {
|
func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select(
|
||||||
|
"id",
|
||||||
|
"enabled",
|
||||||
|
"name",
|
||||||
|
"min_size",
|
||||||
|
"max_size",
|
||||||
|
"delay",
|
||||||
|
"priority",
|
||||||
|
"match_releases",
|
||||||
|
"except_releases",
|
||||||
|
"use_regex",
|
||||||
|
"match_release_groups",
|
||||||
|
"except_release_groups",
|
||||||
|
"scene",
|
||||||
|
"freeleech",
|
||||||
|
"freeleech_percent",
|
||||||
|
"shows",
|
||||||
|
"seasons",
|
||||||
|
"episodes",
|
||||||
|
"resolutions",
|
||||||
|
"codecs",
|
||||||
|
"sources",
|
||||||
|
"containers",
|
||||||
|
"match_hdr",
|
||||||
|
"except_hdr",
|
||||||
|
"years",
|
||||||
|
"artists",
|
||||||
|
"albums",
|
||||||
|
"release_types_match",
|
||||||
|
"formats",
|
||||||
|
"quality",
|
||||||
|
"media",
|
||||||
|
"log_score",
|
||||||
|
"has_log",
|
||||||
|
"has_cue",
|
||||||
|
"perfect_flac",
|
||||||
|
"match_categories",
|
||||||
|
"except_categories",
|
||||||
|
"match_uploaders",
|
||||||
|
"except_uploaders",
|
||||||
|
"tags",
|
||||||
|
"except_tags",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
).
|
||||||
|
From("filter").
|
||||||
|
Where("id = ?", filterID)
|
||||||
|
|
||||||
row := r.db.handler.QueryRowContext(ctx, "SELECT id, enabled, name, min_size, max_size, delay, priority, match_releases, except_releases, use_regex, match_release_groups, except_release_groups, scene, freeleech, freeleech_percent, shows, seasons, episodes, resolutions, codecs, sources, containers, match_hdr, except_hdr, years, artists, albums, release_types_match, formats, quality, media, log_score, has_log, has_cue, perfect_flac, match_categories, except_categories, match_uploaders, except_uploaders, tags, except_tags, created_at, updated_at FROM filter WHERE id = ?", filterID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.findByID: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||||
if err := row.Err(); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.findByID: error query row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +141,7 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
|
||||||
var delay, logScore sql.NullInt32
|
var delay, logScore sql.NullInt32
|
||||||
|
|
||||||
if err := row.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &scene, &freeleech, &freeleechPercent, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, &tags, &exceptTags, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := row.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &scene, &freeleech, &freeleechPercent, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, &tags, &exceptTags, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("filter: %v : error scanning data to struct", filterID)
|
log.Error().Stack().Err(err).Msgf("filter.findByID: %v : error scanning row", filterID)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,63 +178,69 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
|
||||||
|
|
||||||
// FindByIndexerIdentifier find active filters with active indexer only
|
// FindByIndexerIdentifier find active filters with active indexer only
|
||||||
func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, error) {
|
func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select(
|
||||||
|
"f.id",
|
||||||
|
"f.enabled",
|
||||||
|
"f.name",
|
||||||
|
"f.min_size",
|
||||||
|
"f.max_size",
|
||||||
|
"f.delay",
|
||||||
|
"f.priority",
|
||||||
|
"f.match_releases",
|
||||||
|
"f.except_releases",
|
||||||
|
"f.use_regex",
|
||||||
|
"f.match_release_groups",
|
||||||
|
"f.except_release_groups",
|
||||||
|
"f.scene",
|
||||||
|
"f.freeleech",
|
||||||
|
"f.freeleech_percent",
|
||||||
|
"f.shows",
|
||||||
|
"f.seasons",
|
||||||
|
"f.episodes",
|
||||||
|
"f.resolutions",
|
||||||
|
"f.codecs",
|
||||||
|
"f.sources",
|
||||||
|
"f.containers",
|
||||||
|
"f.match_hdr",
|
||||||
|
"f.except_hdr",
|
||||||
|
"f.years",
|
||||||
|
"f.artists",
|
||||||
|
"f.albums",
|
||||||
|
"f.release_types_match",
|
||||||
|
"f.formats",
|
||||||
|
"f.quality",
|
||||||
|
"f.media",
|
||||||
|
"f.log_score",
|
||||||
|
"f.has_log",
|
||||||
|
"f.has_cue",
|
||||||
|
"f.perfect_flac",
|
||||||
|
"f.match_categories",
|
||||||
|
"f.except_categories",
|
||||||
|
"f.match_uploaders",
|
||||||
|
"f.except_uploaders",
|
||||||
|
"f.tags",
|
||||||
|
"f.except_tags",
|
||||||
|
"f.created_at",
|
||||||
|
"f.updated_at",
|
||||||
|
).
|
||||||
|
From("filter f").
|
||||||
|
Join("filter_indexer fi ON f.id = fi.filter_id").
|
||||||
|
Join("indexer i ON i.id = fi.indexer_id").
|
||||||
|
Where("i.identifier = ?", indexer).
|
||||||
|
Where("i.enabled = ?", true).
|
||||||
|
Where("f.enabled = ?", true).
|
||||||
|
OrderBy("f.priority DESC")
|
||||||
|
|
||||||
rows, err := r.db.handler.Query(`
|
query, args, err := queryBuilder.ToSql()
|
||||||
SELECT
|
|
||||||
f.id,
|
|
||||||
f.enabled,
|
|
||||||
f.name,
|
|
||||||
f.min_size,
|
|
||||||
f.max_size,
|
|
||||||
f.delay,
|
|
||||||
f.priority,
|
|
||||||
f.match_releases,
|
|
||||||
f.except_releases,
|
|
||||||
f.use_regex,
|
|
||||||
f.match_release_groups,
|
|
||||||
f.except_release_groups,
|
|
||||||
f.scene,
|
|
||||||
f.freeleech,
|
|
||||||
f.freeleech_percent,
|
|
||||||
f.shows,
|
|
||||||
f.seasons,
|
|
||||||
f.episodes,
|
|
||||||
f.resolutions,
|
|
||||||
f.codecs,
|
|
||||||
f.sources,
|
|
||||||
f.containers,
|
|
||||||
f.match_hdr,
|
|
||||||
f.except_hdr,
|
|
||||||
f.years,
|
|
||||||
f.artists,
|
|
||||||
f.albums,
|
|
||||||
f.release_types_match,
|
|
||||||
f.formats,
|
|
||||||
f.quality,
|
|
||||||
f.media,
|
|
||||||
f.log_score,
|
|
||||||
f.has_log,
|
|
||||||
f.has_cue,
|
|
||||||
f.perfect_flac,
|
|
||||||
f.match_categories,
|
|
||||||
f.except_categories,
|
|
||||||
f.match_uploaders,
|
|
||||||
f.except_uploaders,
|
|
||||||
f.tags,
|
|
||||||
f.except_tags,
|
|
||||||
f.created_at,
|
|
||||||
f.updated_at
|
|
||||||
FROM filter f
|
|
||||||
JOIN filter_indexer fi on f.id = fi.filter_id
|
|
||||||
JOIN indexer i on i.id = fi.indexer_id
|
|
||||||
WHERE i.identifier = ?
|
|
||||||
AND f.enabled = true
|
|
||||||
AND i.enabled = true
|
|
||||||
ORDER BY f.priority DESC`, indexer)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error querying filter row")
|
log.Error().Stack().Err(err).Msg("filter.findByIndexerIdentifier: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.findByIndexerIdentifier: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +255,7 @@ func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, e
|
||||||
var delay, logScore sql.NullInt32
|
var delay, logScore sql.NullInt32
|
||||||
|
|
||||||
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &scene, &freeleech, &freeleechPercent, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, &tags, &exceptTags, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &minSize, &maxSize, &delay, &f.Priority, &matchReleases, &exceptReleases, &useRegex, &matchReleaseGroups, &exceptReleaseGroups, &scene, &freeleech, &freeleechPercent, &shows, &seasons, &episodes, pq.Array(&f.Resolutions), pq.Array(&f.Codecs), pq.Array(&f.Sources), pq.Array(&f.Containers), pq.Array(&f.MatchHDR), pq.Array(&f.ExceptHDR), &years, &artists, &albums, pq.Array(&f.MatchReleaseTypes), pq.Array(&f.Formats), pq.Array(&f.Quality), pq.Array(&f.Media), &logScore, &hasLog, &hasCue, &perfectFlac, &matchCategories, &exceptCategories, &matchUploaders, &exceptUploaders, &tags, &exceptTags, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error scanning data to struct")
|
log.Error().Stack().Err(err).Msg("filter.findByIndexerIdentifier: error scanning row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,66 +289,56 @@ func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, e
|
||||||
|
|
||||||
filters = append(filters, f)
|
filters = append(filters, f)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters, nil
|
return filters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) {
|
func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.Filter, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Insert("filter").
|
||||||
|
Columns(
|
||||||
var err error
|
"name",
|
||||||
if filter.ID != 0 {
|
"enabled",
|
||||||
log.Debug().Msg("update existing record")
|
"min_size",
|
||||||
} else {
|
"max_size",
|
||||||
var res sql.Result
|
"delay",
|
||||||
|
"priority",
|
||||||
res, err = r.db.handler.ExecContext(ctx, `INSERT INTO filter (
|
"match_releases",
|
||||||
name,
|
"except_releases",
|
||||||
enabled,
|
"use_regex",
|
||||||
min_size,
|
"match_release_groups",
|
||||||
max_size,
|
"except_release_groups",
|
||||||
delay,
|
"scene",
|
||||||
priority,
|
"freeleech",
|
||||||
match_releases,
|
"freeleech_percent",
|
||||||
except_releases,
|
"shows",
|
||||||
use_regex,
|
"seasons",
|
||||||
match_release_groups,
|
"episodes",
|
||||||
except_release_groups,
|
"resolutions",
|
||||||
scene,
|
"codecs",
|
||||||
freeleech,
|
"sources",
|
||||||
freeleech_percent,
|
"containers",
|
||||||
shows,
|
"match_hdr",
|
||||||
seasons,
|
"except_hdr",
|
||||||
episodes,
|
"years",
|
||||||
resolutions,
|
"match_categories",
|
||||||
codecs,
|
"except_categories",
|
||||||
sources,
|
"match_uploaders",
|
||||||
containers,
|
"except_uploaders",
|
||||||
match_hdr,
|
"tags",
|
||||||
except_hdr,
|
"except_tags",
|
||||||
years,
|
"artists",
|
||||||
match_categories,
|
"albums",
|
||||||
except_categories,
|
"release_types_match",
|
||||||
match_uploaders,
|
"formats",
|
||||||
except_uploaders,
|
"quality",
|
||||||
tags,
|
"media",
|
||||||
except_tags,
|
"log_score",
|
||||||
artists,
|
"has_log",
|
||||||
albums,
|
"has_cue",
|
||||||
release_types_match,
|
"perfect_flac",
|
||||||
formats,
|
).
|
||||||
quality,
|
Values(
|
||||||
media,
|
|
||||||
log_score,
|
|
||||||
has_log,
|
|
||||||
has_cue,
|
|
||||||
perfect_flac
|
|
||||||
)
|
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40) ON CONFLICT DO NOTHING`,
|
|
||||||
filter.Name,
|
filter.Name,
|
||||||
filter.Enabled,
|
filter.Enabled,
|
||||||
filter.MinSize,
|
filter.MinSize,
|
||||||
|
@ -311,114 +379,80 @@ func (r *FilterRepo) Store(ctx context.Context, filter domain.Filter) (*domain.F
|
||||||
filter.Log,
|
filter.Log,
|
||||||
filter.Cue,
|
filter.Cue,
|
||||||
filter.PerfectFlac,
|
filter.PerfectFlac,
|
||||||
)
|
).
|
||||||
if err != nil {
|
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
// return values
|
||||||
filter.ID = int(resId)
|
var retID int
|
||||||
|
|
||||||
|
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.store: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter.ID = retID
|
||||||
|
|
||||||
return &filter, nil
|
return &filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) {
|
func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.Filter, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
//var res sql.Result
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
_, err = r.db.handler.ExecContext(ctx, `
|
|
||||||
UPDATE filter SET
|
queryBuilder := r.db.squirrel.
|
||||||
name = ?,
|
Update("filter").
|
||||||
enabled = ?,
|
Set("name", filter.Name).
|
||||||
min_size = ?,
|
Set("enabled", filter.Enabled).
|
||||||
max_size = ?,
|
Set("min_size", filter.MinSize).
|
||||||
delay = ?,
|
Set("max_size", filter.MaxSize).
|
||||||
priority = ?,
|
Set("delay", filter.Delay).
|
||||||
match_releases = ?,
|
Set("priority", filter.Priority).
|
||||||
except_releases = ?,
|
Set("use_regex", filter.UseRegex).
|
||||||
use_regex = ?,
|
Set("match_releases", filter.MatchReleases).
|
||||||
match_release_groups = ?,
|
Set("except_releases", filter.ExceptReleases).
|
||||||
except_release_groups = ?,
|
Set("match_release_groups", filter.MatchReleaseGroups).
|
||||||
scene = ?,
|
Set("except_release_groups", filter.ExceptReleaseGroups).
|
||||||
freeleech = ?,
|
Set("scene", filter.Scene).
|
||||||
freeleech_percent = ?,
|
Set("freeleech", filter.Freeleech).
|
||||||
shows = ?,
|
Set("freeleech_percent", filter.FreeleechPercent).
|
||||||
seasons = ?,
|
Set("shows", filter.Shows).
|
||||||
episodes = ?,
|
Set("seasons", filter.Seasons).
|
||||||
resolutions = ?,
|
Set("episodes", filter.Episodes).
|
||||||
codecs = ?,
|
Set("resolutions", pq.Array(filter.Resolutions)).
|
||||||
sources = ?,
|
Set("codecs", pq.Array(filter.Codecs)).
|
||||||
containers = ?,
|
Set("sources", pq.Array(filter.Sources)).
|
||||||
match_hdr = ?,
|
Set("containers", pq.Array(filter.Containers)).
|
||||||
except_hdr = ?,
|
Set("match_hdr", pq.Array(filter.MatchHDR)).
|
||||||
years = ?,
|
Set("except_hdr", pq.Array(filter.ExceptHDR)).
|
||||||
match_categories = ?,
|
Set("years", filter.Years).
|
||||||
except_categories = ?,
|
Set("match_categories", filter.MatchCategories).
|
||||||
match_uploaders = ?,
|
Set("except_categories", filter.ExceptCategories).
|
||||||
except_uploaders = ?,
|
Set("match_uploaders", filter.MatchUploaders).
|
||||||
tags = ?,
|
Set("except_uploaders", filter.ExceptUploaders).
|
||||||
except_tags = ?,
|
Set("tags", filter.Tags).
|
||||||
artists = ?,
|
Set("except_tags", filter.ExceptTags).
|
||||||
albums = ?,
|
Set("artists", filter.Artists).
|
||||||
release_types_match = ?,
|
Set("albums", filter.Albums).
|
||||||
formats = ?,
|
Set("release_types_match", pq.Array(filter.MatchReleaseTypes)).
|
||||||
quality = ?,
|
Set("formats", pq.Array(filter.Formats)).
|
||||||
media = ?,
|
Set("quality", pq.Array(filter.Quality)).
|
||||||
log_score = ?,
|
Set("media", pq.Array(filter.Media)).
|
||||||
has_log = ?,
|
Set("log_score", filter.LogScore).
|
||||||
has_cue = ?,
|
Set("has_log", filter.Log).
|
||||||
perfect_flac = ?,
|
Set("has_cue", filter.Cue).
|
||||||
updated_at = CURRENT_TIMESTAMP
|
Set("perfect_flac", filter.PerfectFlac).
|
||||||
WHERE id = ?`,
|
Set("updated_at", time.Now().Format(time.RFC3339)).
|
||||||
filter.Name,
|
Where("id = ?", filter.ID)
|
||||||
filter.Enabled,
|
|
||||||
filter.MinSize,
|
query, args, err := queryBuilder.ToSql()
|
||||||
filter.MaxSize,
|
|
||||||
filter.Delay,
|
|
||||||
filter.Priority,
|
|
||||||
filter.MatchReleases,
|
|
||||||
filter.ExceptReleases,
|
|
||||||
filter.UseRegex,
|
|
||||||
filter.MatchReleaseGroups,
|
|
||||||
filter.ExceptReleaseGroups,
|
|
||||||
filter.Scene,
|
|
||||||
filter.Freeleech,
|
|
||||||
filter.FreeleechPercent,
|
|
||||||
filter.Shows,
|
|
||||||
filter.Seasons,
|
|
||||||
filter.Episodes,
|
|
||||||
pq.Array(filter.Resolutions),
|
|
||||||
pq.Array(filter.Codecs),
|
|
||||||
pq.Array(filter.Sources),
|
|
||||||
pq.Array(filter.Containers),
|
|
||||||
pq.Array(filter.MatchHDR),
|
|
||||||
pq.Array(filter.ExceptHDR),
|
|
||||||
filter.Years,
|
|
||||||
filter.MatchCategories,
|
|
||||||
filter.ExceptCategories,
|
|
||||||
filter.MatchUploaders,
|
|
||||||
filter.ExceptUploaders,
|
|
||||||
filter.Tags,
|
|
||||||
filter.ExceptTags,
|
|
||||||
filter.Artists,
|
|
||||||
filter.Albums,
|
|
||||||
pq.Array(filter.MatchReleaseTypes),
|
|
||||||
pq.Array(filter.Formats),
|
|
||||||
pq.Array(filter.Quality),
|
|
||||||
pq.Array(filter.Media),
|
|
||||||
filter.LogScore,
|
|
||||||
filter.Log,
|
|
||||||
filter.Cue,
|
|
||||||
filter.PerfectFlac,
|
|
||||||
filter.ID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.update: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.update: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,20 +460,22 @@ func (r *FilterRepo) Update(ctx context.Context, filter domain.Filter) (*domain.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) ToggleEnabled(ctx context.Context, filterID int, enabled bool) error {
|
func (r *FilterRepo) ToggleEnabled(ctx context.Context, filterID int, enabled bool) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
_, err = r.db.handler.ExecContext(ctx, `
|
|
||||||
UPDATE filter SET
|
queryBuilder := r.db.squirrel.
|
||||||
enabled = ?,
|
Update("filter").
|
||||||
updated_at = CURRENT_TIMESTAMP
|
Set("enabled", enabled).
|
||||||
WHERE id = ?`,
|
Set("updated_at", sq.Expr("CURRENT_TIMESTAMP")).
|
||||||
enabled,
|
Where("id = ?", filterID)
|
||||||
filterID,
|
|
||||||
)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.toggleEnabled: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.toggleEnabled: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,9 +483,6 @@ func (r *FilterRepo) ToggleEnabled(ctx context.Context, filterID int, enabled bo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) StoreIndexerConnections(ctx context.Context, filterID int, indexers []domain.Indexer) error {
|
func (r *FilterRepo) StoreIndexerConnections(ctx context.Context, filterID int, indexers []domain.Indexer) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
tx, err := r.db.handler.BeginTx(ctx, nil)
|
tx, err := r.db.handler.BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -457,27 +490,43 @@ func (r *FilterRepo) StoreIndexerConnections(ctx context.Context, filterID int,
|
||||||
|
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
deleteQuery := `DELETE FROM filter_indexer WHERE filter_id = ?`
|
deleteQueryBuilder := r.db.squirrel.
|
||||||
_, err = tx.ExecContext(ctx, deleteQuery, filterID)
|
Delete("filter_indexer").
|
||||||
|
Where("filter_id = ?", filterID)
|
||||||
|
|
||||||
|
deleteQuery, deleteArgs, err := deleteQueryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting indexers for filter: %v", filterID)
|
log.Error().Stack().Err(err).Msg("filter.StoreIndexerConnections: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.ExecContext(ctx, deleteQuery, deleteArgs...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msgf("filter.StoreIndexerConnections: error deleting indexers for filter: %v", filterID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, indexer := range indexers {
|
for _, indexer := range indexers {
|
||||||
query := `INSERT INTO filter_indexer (filter_id, indexer_id) VALUES ($1, $2)`
|
queryBuilder := r.db.squirrel.
|
||||||
_, err := tx.ExecContext(ctx, query, filterID, indexer.ID)
|
Insert("filter_indexer").Columns("filter_id", "indexer_id").
|
||||||
|
Values(filterID, indexer.ID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.StoreIndexerConnections: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.StoreIndexerConnections: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msgf("filter.indexers: store '%v' on filter: %v", indexer.Name, filterID)
|
log.Debug().Msgf("filter.StoreIndexerConnections: store '%v' on filter: %v", indexer.Name, filterID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting indexers for filter: %v", filterID)
|
log.Error().Stack().Err(err).Msgf("filter.StoreIndexerConnections: error storing indexers for filter: %v", filterID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,13 +534,19 @@ func (r *FilterRepo) StoreIndexerConnections(ctx context.Context, filterID int,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) StoreIndexerConnection(ctx context.Context, filterID int, indexerID int) error {
|
func (r *FilterRepo) StoreIndexerConnection(ctx context.Context, filterID int, indexerID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Insert("filter_indexer").Columns("filter_id", "indexer_id").
|
||||||
|
Values(filterID, indexerID)
|
||||||
|
|
||||||
query := `INSERT INTO filter_indexer (filter_id, indexer_id) VALUES ($1, $2)`
|
query, args, err := queryBuilder.ToSql()
|
||||||
_, err := r.db.handler.ExecContext(ctx, query, filterID, indexerID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.storeIndexerConnection: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.storeIndexerConnection: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,13 +554,19 @@ func (r *FilterRepo) StoreIndexerConnection(ctx context.Context, filterID int, i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) DeleteIndexerConnections(ctx context.Context, filterID int) error {
|
func (r *FilterRepo) DeleteIndexerConnections(ctx context.Context, filterID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("filter_indexer").
|
||||||
|
Where("filter_id = ?", filterID)
|
||||||
|
|
||||||
query := `DELETE FROM filter_indexer WHERE filter_id = ?`
|
query, args, err := queryBuilder.ToSql()
|
||||||
_, err := r.db.handler.ExecContext(ctx, query, filterID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.deleteIndexerConnections: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.deleteIndexerConnections: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,12 +574,19 @@ func (r *FilterRepo) DeleteIndexerConnections(ctx context.Context, filterID int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FilterRepo) Delete(ctx context.Context, filterID int) error {
|
func (r *FilterRepo) Delete(ctx context.Context, filterID int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("filter").
|
||||||
|
Where("id = ?", filterID)
|
||||||
|
|
||||||
_, err := r.db.handler.ExecContext(ctx, `DELETE FROM filter WHERE id = ?`, filterID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("filter.delete: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("filter.delete: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,11 @@ package database
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexerRepo struct {
|
type IndexerRepo struct {
|
||||||
|
@ -17,52 +20,64 @@ func NewIndexerRepo(db *DB) domain.IndexerRepo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IndexerRepo) Store(indexer domain.Indexer) (*domain.Indexer, error) {
|
func (r *IndexerRepo) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
settings, err := json.Marshal(indexer.Settings)
|
settings, err := json.Marshal(indexer.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error marshaling json data")
|
log.Error().Stack().Err(err).Msg("error marshaling json data")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := r.db.handler.Exec(`INSERT INTO indexer (enabled, name, identifier, settings) VALUES (?, ?, ?, ?)`, indexer.Enabled, indexer.Name, indexer.Identifier, settings)
|
queryBuilder := r.db.squirrel.
|
||||||
|
Insert("indexer").Columns("enabled", "name", "identifier", "settings").
|
||||||
|
Values(indexer.Enabled, indexer.Name, indexer.Identifier, settings).
|
||||||
|
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||||
|
|
||||||
|
// return values
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err = queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("indexer.store: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, _ := res.LastInsertId()
|
indexer.ID = retID
|
||||||
indexer.ID = id
|
|
||||||
|
|
||||||
return &indexer, nil
|
return &indexer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IndexerRepo) Update(indexer domain.Indexer) (*domain.Indexer, error) {
|
func (r *IndexerRepo) Update(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
//r.db.lock.RLock()
|
settings, err := json.Marshal(indexer.Settings)
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
sett, err := json.Marshal(indexer.Settings)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error marshaling json data")
|
log.Error().Stack().Err(err).Msg("error marshaling json data")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.db.handler.Exec(`UPDATE indexer SET enabled = ?, name = ?, settings = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`, indexer.Enabled, indexer.Name, sett, indexer.ID)
|
queryBuilder := r.db.squirrel.
|
||||||
|
Update("indexer").
|
||||||
|
Set("enabled", indexer.Enabled).
|
||||||
|
Set("name", indexer.Name).
|
||||||
|
Set("settings", settings).
|
||||||
|
Set("updated_at", time.Now().Format(time.RFC3339)).
|
||||||
|
Where("id = ?", indexer.ID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("indexer.update: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("indexer.update: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &indexer, nil
|
return &indexer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IndexerRepo) List() ([]domain.Indexer, error) {
|
func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) {
|
||||||
//r.db.lock.RLock()
|
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, identifier, settings FROM indexer ORDER BY name ASC")
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
rows, err := r.db.handler.Query("SELECT id, enabled, name, identifier, settings FROM indexer ORDER BY name ASC")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("indexer.list: error query indexer")
|
log.Error().Stack().Err(err).Msg("indexer.list: error query indexer")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -100,14 +115,19 @@ func (r *IndexerRepo) List() ([]domain.Indexer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) {
|
func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select("id", "enabled", "name", "identifier").
|
||||||
|
From("indexer").
|
||||||
|
Join("filter_indexer ON indexer.id = filter_indexer.indexer_id").
|
||||||
|
Where("filter_indexer.filter_id = ?", id)
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, `
|
query, args, err := queryBuilder.ToSql()
|
||||||
SELECT i.id, i.enabled, i.name, i.identifier
|
if err != nil {
|
||||||
FROM indexer i
|
log.Error().Stack().Err(err).Msg("irc.check_existing_network: error fetching data")
|
||||||
JOIN filter_indexer fi on i.id = fi.indexer_id
|
return nil, err
|
||||||
WHERE fi.filter_id = ?`, id)
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("indexer.find_by_filter_id: error query indexer")
|
log.Error().Stack().Err(err).Msg("indexer.find_by_filter_id: error query indexer")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -115,7 +135,7 @@ func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Inde
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var indexers []domain.Indexer
|
indexers := make([]domain.Indexer, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var f domain.Indexer
|
var f domain.Indexer
|
||||||
|
|
||||||
|
@ -146,12 +166,17 @@ func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Inde
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IndexerRepo) Delete(ctx context.Context, id int) error {
|
func (r *IndexerRepo) Delete(ctx context.Context, id int) error {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Delete("indexer").
|
||||||
|
Where("id = ?", id)
|
||||||
|
|
||||||
query := `DELETE FROM indexer WHERE id = ?`
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("indexer.delete: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err := r.db.handler.ExecContext(ctx, query, id)
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("indexer.delete: error executing query: '%v'", query)
|
log.Error().Stack().Err(err).Msgf("indexer.delete: error executing query: '%v'", query)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,8 +3,8 @@ package database
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"github.com/pkg/errors"
|
||||||
sq "github.com/Masterminds/squirrel"
|
"time"
|
||||||
|
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
|
|
||||||
|
@ -19,15 +19,18 @@ func NewIrcRepo(db *DB) domain.IrcRepo {
|
||||||
return &IrcRepo{db: db}
|
return &IrcRepo{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) GetNetworkByID(id int64) (*domain.IrcNetwork, error) {
|
func (r *IrcRepo) GetNetworkByID(ctx context.Context, id int64) (*domain.IrcNetwork, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
|
||||||
|
From("irc_network").
|
||||||
|
Where("id = ?", id)
|
||||||
|
|
||||||
row := r.db.handler.QueryRow("SELECT id, enabled, name, server, port, tls, pass, invite_command, nickserv_account, nickserv_password FROM irc_network WHERE id = ?", id)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err := row.Err(); err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.getNetworkByID: error building query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
log.Trace().Str("database", "irc.check_existing_network").Msgf("query: '%v', args: '%v'", query, args)
|
||||||
|
|
||||||
var n domain.IrcNetwork
|
var n domain.IrcNetwork
|
||||||
|
|
||||||
|
@ -35,8 +38,10 @@ func (r *IrcRepo) GetNetworkByID(id int64) (*domain.IrcNetwork, error) {
|
||||||
var nsAccount, nsPassword sql.NullString
|
var nsAccount, nsPassword sql.NullString
|
||||||
var tls sql.NullBool
|
var tls sql.NullBool
|
||||||
|
|
||||||
|
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||||
if err := row.Scan(&n.ID, &n.Enabled, &n.Name, &n.Server, &n.Port, &tls, &pass, &inviteCmd, &nsAccount, &nsPassword); err != nil {
|
if err := row.Scan(&n.ID, &n.Enabled, &n.Name, &n.Server, &n.Port, &tls, &pass, &inviteCmd, &nsAccount, &nsPassword); err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.getNetworkByID: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.TLS = tls.Bool
|
n.TLS = tls.Bool
|
||||||
|
@ -56,21 +61,41 @@ func (r *IrcRepo) DeleteNetwork(ctx context.Context, id int64) error {
|
||||||
|
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
_, err = tx.ExecContext(ctx, `DELETE FROM irc_channel WHERE network_id = ?`, id)
|
queryBuilder := r.db.squirrel.
|
||||||
|
Delete("irc_channel").
|
||||||
|
Where("network_id = ?", id)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting channels for network: %v", id)
|
log.Error().Stack().Err(err).Msg("irc.deleteNetwork: error building query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.ExecContext(ctx, `DELETE FROM irc_network WHERE id = ?`, id)
|
_, err = tx.ExecContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting network: %v", id)
|
log.Error().Stack().Err(err).Msg("irc.deleteNetwork: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
netQueryBuilder := r.db.squirrel.
|
||||||
|
Delete("irc_network").
|
||||||
|
Where("id = ?", id)
|
||||||
|
|
||||||
|
netQuery, netArgs, err := netQueryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.deleteNetwork: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.ExecContext(ctx, netQuery, netArgs...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.deleteNetwork: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting network: %v", id)
|
log.Error().Stack().Err(err).Msgf("irc.deleteNetwork: error deleting network %v", id)
|
||||||
return err
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,12 +104,21 @@ func (r *IrcRepo) DeleteNetwork(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) FindActiveNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
|
func (r *IrcRepo) FindActiveNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
|
||||||
|
From("irc_network").
|
||||||
|
Where("enabled = ?", true)
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, server, port, tls, pass, invite_command, nickserv_account, nickserv_password FROM irc_network WHERE enabled = true")
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.findActiveNetworks: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.findActiveNetworks: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -94,19 +128,25 @@ func (r *IrcRepo) FindActiveNetworks(ctx context.Context) ([]domain.IrcNetwork,
|
||||||
var net domain.IrcNetwork
|
var net domain.IrcNetwork
|
||||||
|
|
||||||
var pass, inviteCmd sql.NullString
|
var pass, inviteCmd sql.NullString
|
||||||
|
var nsAccount, nsPassword sql.NullString
|
||||||
var tls sql.NullBool
|
var tls sql.NullBool
|
||||||
|
|
||||||
if err := rows.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &net.NickServ.Account, &net.NickServ.Password); err != nil {
|
if err := rows.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &nsAccount, &nsPassword); err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.findActiveNetworks: error scanning row")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
net.TLS = tls.Bool
|
net.TLS = tls.Bool
|
||||||
net.Pass = pass.String
|
net.Pass = pass.String
|
||||||
net.InviteCommand = inviteCmd.String
|
net.InviteCommand = inviteCmd.String
|
||||||
|
|
||||||
|
net.NickServ.Account = nsAccount.String
|
||||||
|
net.NickServ.Password = nsPassword.String
|
||||||
|
|
||||||
networks = append(networks, net)
|
networks = append(networks, net)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.findActiveNetworks: row error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,12 +154,21 @@ func (r *IrcRepo) FindActiveNetworks(ctx context.Context) ([]domain.IrcNetwork,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
|
func (r *IrcRepo) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
|
||||||
|
From("irc_network").
|
||||||
|
OrderBy("name ASC")
|
||||||
|
|
||||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, server, port, tls, pass, invite_command, nickserv_account, nickserv_password FROM irc_network ORDER BY name ASC")
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.listNetworks: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.listNetworks: error executing query")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -129,19 +178,25 @@ func (r *IrcRepo) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
var net domain.IrcNetwork
|
var net domain.IrcNetwork
|
||||||
|
|
||||||
var pass, inviteCmd sql.NullString
|
var pass, inviteCmd sql.NullString
|
||||||
|
var nsAccount, nsPassword sql.NullString
|
||||||
var tls sql.NullBool
|
var tls sql.NullBool
|
||||||
|
|
||||||
if err := rows.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &net.NickServ.Account, &net.NickServ.Password); err != nil {
|
if err := rows.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &nsAccount, &nsPassword); err != nil {
|
||||||
log.Fatal().Err(err)
|
log.Error().Stack().Err(err).Msg("irc.listNetworks: error scanning row")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
net.TLS = tls.Bool
|
net.TLS = tls.Bool
|
||||||
net.Pass = pass.String
|
net.Pass = pass.String
|
||||||
net.InviteCommand = inviteCmd.String
|
net.InviteCommand = inviteCmd.String
|
||||||
|
|
||||||
|
net.NickServ.Account = nsAccount.String
|
||||||
|
net.NickServ.Password = nsPassword.String
|
||||||
|
|
||||||
networks = append(networks, net)
|
networks = append(networks, net)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.listNetworks: row error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,12 +204,20 @@ func (r *IrcRepo) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
|
func (r *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
Select("id", "name", "enabled", "password").
|
||||||
|
From("irc_channel").
|
||||||
|
Where("network_id = ?", networkID)
|
||||||
|
|
||||||
rows, err := r.db.handler.Query("SELECT id, name, enabled, password FROM irc_channel WHERE network_id = ?", networkID)
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error querying channels for network: %v", networkID)
|
log.Error().Stack().Err(err).Msg("irc.listChannels: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.db.handler.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.listChannels: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -165,7 +228,7 @@ func (r *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
|
||||||
var pass sql.NullString
|
var pass sql.NullString
|
||||||
|
|
||||||
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Enabled, &pass); err != nil {
|
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Enabled, &pass); err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error querying channels for network: %v", networkID)
|
log.Error().Stack().Err(err).Msg("irc.listChannels: error scanning row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +237,7 @@ func (r *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
|
||||||
channels = append(channels, ch)
|
channels = append(channels, ch)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.listChannels: error row")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,10 +245,7 @@ func (r *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcNetwork) (*domain.IrcNetwork, error) {
|
func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcNetwork) (*domain.IrcNetwork, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := r.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
queryBuilder := sq.
|
|
||||||
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
|
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
|
||||||
From("irc_network").
|
From("irc_network").
|
||||||
Where("server = ?", network.Server).
|
Where("server = ?", network.Server).
|
||||||
|
@ -192,10 +253,10 @@ func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcN
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("irc.check_existing_network: error fetching data")
|
log.Error().Stack().Err(err).Msg("irc.checkExistingNetwork: error building query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Trace().Str("database", "irc.check_existing_network").Msgf("query: '%v', args: '%v'", query, args)
|
log.Trace().Str("database", "irc.checkExistingNetwork").Msgf("query: '%v', args: '%v'", query, args)
|
||||||
|
|
||||||
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||||
|
|
||||||
|
@ -209,7 +270,7 @@ func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcN
|
||||||
// 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 if err != nil {
|
} else if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("irc.check_existing_network: error scanning data to struct")
|
log.Error().Stack().Err(err).Msg("irc.checkExistingNetwork: error scanning data to struct")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +283,6 @@ func (r *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcN
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
|
func (r *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
netName := toNullString(network.Name)
|
netName := toNullString(network.Name)
|
||||||
pass := toNullString(network.Pass)
|
pass := toNullString(network.Pass)
|
||||||
inviteCmd := toNullString(network.InviteCommand)
|
inviteCmd := toNullString(network.InviteCommand)
|
||||||
|
@ -233,20 +291,22 @@ func (r *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
|
||||||
nsPassword := toNullString(network.NickServ.Password)
|
nsPassword := toNullString(network.NickServ.Password)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if network.ID != 0 {
|
var retID int64
|
||||||
// update record
|
|
||||||
_, err = r.db.handler.Exec(`UPDATE irc_network
|
queryBuilder := r.db.squirrel.
|
||||||
SET enabled = ?,
|
Insert("irc_network").
|
||||||
name = ?,
|
Columns(
|
||||||
server = ?,
|
"enabled",
|
||||||
port = ?,
|
"name",
|
||||||
tls = ?,
|
"server",
|
||||||
pass = ?,
|
"port",
|
||||||
invite_command = ?,
|
"tls",
|
||||||
nickserv_account = ?,
|
"pass",
|
||||||
nickserv_password = ?,
|
"invite_command",
|
||||||
updated_at = CURRENT_TIMESTAMP
|
"nickserv_account",
|
||||||
WHERE id = ?`,
|
"nickserv_password",
|
||||||
|
).
|
||||||
|
Values(
|
||||||
network.Enabled,
|
network.Enabled,
|
||||||
netName,
|
netName,
|
||||||
network.Server,
|
network.Server,
|
||||||
|
@ -256,51 +316,22 @@ func (r *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
|
||||||
inviteCmd,
|
inviteCmd,
|
||||||
nsAccount,
|
nsAccount,
|
||||||
nsPassword,
|
nsPassword,
|
||||||
network.ID,
|
).
|
||||||
)
|
Suffix("RETURNING id").
|
||||||
if err != nil {
|
RunWith(r.db.handler)
|
||||||
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var res sql.Result
|
|
||||||
|
|
||||||
res, err = r.db.handler.Exec(`INSERT INTO irc_network (
|
err = queryBuilder.QueryRow().Scan(&retID)
|
||||||
enabled,
|
if err != nil {
|
||||||
name,
|
log.Error().Stack().Err(err).Msg("irc.storeNetwork: error executing query")
|
||||||
server,
|
return errors.Wrap(err, "error executing query")
|
||||||
port,
|
|
||||||
tls,
|
|
||||||
pass,
|
|
||||||
invite_command,
|
|
||||||
nickserv_account,
|
|
||||||
nickserv_password
|
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING`,
|
|
||||||
network.Enabled,
|
|
||||||
netName,
|
|
||||||
network.Server,
|
|
||||||
network.Port,
|
|
||||||
network.TLS,
|
|
||||||
pass,
|
|
||||||
inviteCmd,
|
|
||||||
nsAccount,
|
|
||||||
nsPassword,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
network.ID, err = res.LastInsertId()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
network.ID = retID
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error {
|
func (r *IrcRepo) UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
netName := toNullString(network.Name)
|
netName := toNullString(network.Name)
|
||||||
pass := toNullString(network.Pass)
|
pass := toNullString(network.Pass)
|
||||||
inviteCmd := toNullString(network.InviteCommand)
|
inviteCmd := toNullString(network.InviteCommand)
|
||||||
|
@ -309,32 +340,31 @@ func (r *IrcRepo) UpdateNetwork(ctx context.Context, network *domain.IrcNetwork)
|
||||||
nsPassword := toNullString(network.NickServ.Password)
|
nsPassword := toNullString(network.NickServ.Password)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
// update record
|
|
||||||
_, err = r.db.handler.ExecContext(ctx, `UPDATE irc_network
|
queryBuilder := r.db.squirrel.
|
||||||
SET enabled = ?,
|
Update("irc_network").
|
||||||
name = ?,
|
Set("enabled", network.Enabled).
|
||||||
server = ?,
|
Set("name", netName).
|
||||||
port = ?,
|
Set("server", network.Server).
|
||||||
tls = ?,
|
Set("port", network.Port).
|
||||||
pass = ?,
|
Set("tls", network.TLS).
|
||||||
invite_command = ?,
|
Set("pass", pass).
|
||||||
nickserv_account = ?,
|
Set("invite_command", inviteCmd).
|
||||||
nickserv_password = ?,
|
Set("nickserv_account", nsAccount).
|
||||||
updated_at = CURRENT_TIMESTAMP
|
Set("nickserv_password", nsPassword).
|
||||||
WHERE id = ?`,
|
Set("updated_at", time.Now().Format(time.RFC3339)).
|
||||||
network.Enabled,
|
Where("id = ?", network.ID)
|
||||||
netName,
|
|
||||||
network.Server,
|
query, args, err := queryBuilder.ToSql()
|
||||||
network.Port,
|
|
||||||
network.TLS,
|
|
||||||
pass,
|
|
||||||
inviteCmd,
|
|
||||||
nsAccount,
|
|
||||||
nsPassword,
|
|
||||||
network.ID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
|
log.Error().Stack().Err(err).Msg("irc.updateNetwork: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update record
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.updateNetwork: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,9 +374,6 @@ func (r *IrcRepo) UpdateNetwork(ctx context.Context, network *domain.IrcNetwork)
|
||||||
// TODO create new channel handler to only add, not delete
|
// TODO create new channel handler to only add, not delete
|
||||||
|
|
||||||
func (r *IrcRepo) StoreNetworkChannels(ctx context.Context, networkID int64, channels []domain.IrcChannel) error {
|
func (r *IrcRepo) StoreNetworkChannels(ctx context.Context, networkID int64, channels []domain.IrcChannel) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
tx, err := r.db.handler.BeginTx(ctx, nil)
|
tx, err := r.db.handler.BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -354,40 +381,74 @@ func (r *IrcRepo) StoreNetworkChannels(ctx context.Context, networkID int64, cha
|
||||||
|
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
_, err = tx.ExecContext(ctx, `DELETE FROM irc_channel WHERE network_id = ?`, networkID)
|
queryBuilder := r.db.squirrel.
|
||||||
|
Delete("irc_channel").
|
||||||
|
Where("network_id = ?", networkID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting channels for network: %v", networkID)
|
log.Error().Stack().Err(err).Msg("irc.storeNetworkChannels: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.storeNetworkChannels: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
var res sql.Result
|
// values
|
||||||
pass := toNullString(channel.Password)
|
pass := toNullString(channel.Password)
|
||||||
|
|
||||||
res, err = tx.ExecContext(ctx, `INSERT INTO irc_channel (
|
channelQueryBuilder := r.db.squirrel.
|
||||||
enabled,
|
Insert("irc_channel").
|
||||||
detached,
|
Columns(
|
||||||
name,
|
"enabled",
|
||||||
password,
|
"detached",
|
||||||
network_id
|
"name",
|
||||||
) VALUES (?, ?, ?, ?, ?)`,
|
"password",
|
||||||
channel.Enabled,
|
"network_id",
|
||||||
true,
|
).
|
||||||
channel.Name,
|
Values(
|
||||||
pass,
|
channel.Enabled,
|
||||||
networkID,
|
true,
|
||||||
)
|
channel.Name,
|
||||||
|
pass,
|
||||||
|
networkID,
|
||||||
|
).
|
||||||
|
Suffix("RETURNING id").
|
||||||
|
RunWith(tx)
|
||||||
|
|
||||||
|
// returning
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err = channelQueryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("irc.storeNetworkChannels: error executing query")
|
||||||
return err
|
return errors.Wrap(err, "error executing query")
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.ID, err = res.LastInsertId()
|
channel.ID = retID
|
||||||
|
|
||||||
|
//channelQuery, channelArgs, err := channelQueryBuilder.ToSql()
|
||||||
|
//if err != nil {
|
||||||
|
// log.Error().Stack().Err(err).Msg("irc.storeNetworkChannels: error building query")
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//res, err = r.db.handler.ExecContext(ctx, channelQuery, channelArgs...)
|
||||||
|
//if err != nil {
|
||||||
|
// log.Error().Stack().Err(err).Msg("irc.storeNetworkChannels: error executing query")
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//channel.ID, err = res.LastInsertId()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("error deleting network: %v", networkID)
|
log.Error().Stack().Err(err).Msgf("irc.storeNetworkChannels: error deleting network: %v", networkID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,50 +456,102 @@ func (r *IrcRepo) StoreNetworkChannels(ctx context.Context, networkID int64, cha
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IrcRepo) StoreChannel(networkID int64, channel *domain.IrcChannel) error {
|
func (r *IrcRepo) StoreChannel(networkID int64, channel *domain.IrcChannel) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
pass := toNullString(channel.Password)
|
pass := toNullString(channel.Password)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if channel.ID != 0 {
|
if channel.ID != 0 {
|
||||||
// update record
|
// update record
|
||||||
_, err = r.db.handler.Exec(`UPDATE irc_channel
|
channelQueryBuilder := r.db.squirrel.
|
||||||
SET
|
Update("irc_channel").
|
||||||
enabled = ?,
|
Set("enabled", channel.Enabled).
|
||||||
detached = ?,
|
Set("detached", channel.Detached).
|
||||||
name = ?,
|
Set("name", channel.Name).
|
||||||
password = ?
|
Set("pass", pass).
|
||||||
WHERE
|
Where("id = ?", channel.ID)
|
||||||
id = ?`,
|
|
||||||
channel.Enabled,
|
|
||||||
channel.Detached,
|
|
||||||
channel.Name,
|
|
||||||
pass,
|
|
||||||
channel.ID,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
var res sql.Result
|
|
||||||
|
|
||||||
res, err = r.db.handler.Exec(`INSERT INTO irc_channel (
|
query, args, err := channelQueryBuilder.ToSql()
|
||||||
enabled,
|
|
||||||
detached,
|
|
||||||
name,
|
|
||||||
password,
|
|
||||||
network_id
|
|
||||||
) VALUES (?, ?, ?, ?, ?) ON CONFLICT DO NOTHING`,
|
|
||||||
channel.Enabled,
|
|
||||||
true,
|
|
||||||
channel.Name,
|
|
||||||
pass,
|
|
||||||
networkID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
log.Error().Stack().Err(err).Msg("irc.storeChannel: error building query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.ID, err = res.LastInsertId()
|
_, err = r.db.handler.Exec(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.storeChannel: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queryBuilder := r.db.squirrel.
|
||||||
|
Insert("irc_channel").
|
||||||
|
Columns(
|
||||||
|
"enabled",
|
||||||
|
"detached",
|
||||||
|
"name",
|
||||||
|
"password",
|
||||||
|
"network_id",
|
||||||
|
).
|
||||||
|
Values(
|
||||||
|
channel.Enabled,
|
||||||
|
true,
|
||||||
|
channel.Name,
|
||||||
|
pass,
|
||||||
|
networkID,
|
||||||
|
).
|
||||||
|
Suffix("RETURNING id").
|
||||||
|
RunWith(r.db.handler)
|
||||||
|
|
||||||
|
// returning
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err = queryBuilder.QueryRow().Scan(&retID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.storeChannels: error executing query")
|
||||||
|
return errors.Wrap(err, "error executing query")
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.ID = retID
|
||||||
|
|
||||||
|
//channelQuery, channelArgs, err := channelQueryBuilder.ToSql()
|
||||||
|
//if err != nil {
|
||||||
|
// log.Error().Stack().Err(err).Msg("irc.storeChannel: error building query")
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//res, err := r.db.handler.Exec(channelQuery, channelArgs...)
|
||||||
|
//if err != nil {
|
||||||
|
// log.Error().Stack().Err(err).Msg("irc.storeChannel: error executing query")
|
||||||
|
// return errors.Wrap(err, "error executing query")
|
||||||
|
// //return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//channel.ID, err = res.LastInsertId()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IrcRepo) UpdateChannel(channel *domain.IrcChannel) error {
|
||||||
|
pass := toNullString(channel.Password)
|
||||||
|
|
||||||
|
// update record
|
||||||
|
channelQueryBuilder := r.db.squirrel.
|
||||||
|
Update("irc_channel").
|
||||||
|
Set("enabled", channel.Enabled).
|
||||||
|
Set("detached", channel.Detached).
|
||||||
|
Set("name", channel.Name).
|
||||||
|
Set("pass", pass).
|
||||||
|
Where("id = ?", channel.ID)
|
||||||
|
|
||||||
|
query, args, err := channelQueryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.updateChannel: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.Exec(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("irc.updateChannel: error executing query")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
const schema = `
|
const sqliteSchema = `
|
||||||
CREATE TABLE users
|
CREATE TABLE users
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
@ -107,7 +107,7 @@ CREATE TABLE filter_indexer
|
||||||
filter_id INTEGER,
|
filter_id INTEGER,
|
||||||
indexer_id INTEGER,
|
indexer_id INTEGER,
|
||||||
FOREIGN KEY (filter_id) REFERENCES filter(id),
|
FOREIGN KEY (filter_id) REFERENCES filter(id),
|
||||||
FOREIGN KEY (indexer_id) REFERENCES indexer(id),
|
FOREIGN KEY (indexer_id) REFERENCES indexer(id) ON DELETE CASCADE,
|
||||||
PRIMARY KEY (filter_id, indexer_id)
|
PRIMARY KEY (filter_id, indexer_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -150,8 +150,8 @@ CREATE TABLE action
|
||||||
webhook_headers TEXT [] DEFAULT '{}',
|
webhook_headers TEXT [] DEFAULT '{}',
|
||||||
client_id INTEGER,
|
client_id INTEGER,
|
||||||
filter_id INTEGER,
|
filter_id INTEGER,
|
||||||
FOREIGN KEY (client_id) REFERENCES client(id),
|
FOREIGN KEY (filter_id) REFERENCES filter(id),
|
||||||
FOREIGN KEY (filter_id) REFERENCES filter(id)
|
FOREIGN KEY (client_id) REFERENCES client(id) ON DELETE SET NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE "release"
|
CREATE TABLE "release"
|
||||||
|
@ -207,20 +207,20 @@ CREATE TABLE "release"
|
||||||
|
|
||||||
CREATE TABLE release_action_status
|
CREATE TABLE release_action_status
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
status TEXT,
|
status TEXT,
|
||||||
action TEXT NOT NULL,
|
action TEXT NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
rejections TEXT [] DEFAULT '{}' NOT NULL,
|
rejections TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
raw TEXT,
|
raw TEXT,
|
||||||
log TEXT,
|
log TEXT,
|
||||||
release_id INTEGER NOT NULL,
|
release_id INTEGER NOT NULL,
|
||||||
FOREIGN KEY (release_id) REFERENCES "release"(id)
|
FOREIGN KEY (release_id) REFERENCES "release"(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
var migrations = []string{
|
var sqliteMigrations = []string{
|
||||||
"",
|
"",
|
||||||
`
|
`
|
||||||
CREATE TABLE "release"
|
CREATE TABLE "release"
|
||||||
|
@ -368,4 +368,348 @@ var migrations = []string{
|
||||||
ALTER TABLE "action"
|
ALTER TABLE "action"
|
||||||
ADD COLUMN webhook_headers TEXT [] DEFAULT '{}';
|
ADD COLUMN webhook_headers TEXT [] DEFAULT '{}';
|
||||||
`,
|
`,
|
||||||
|
`
|
||||||
|
CREATE TABLE action_dg_tmp
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
type TEXT,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
exec_cmd TEXT,
|
||||||
|
exec_args TEXT,
|
||||||
|
watch_folder TEXT,
|
||||||
|
category TEXT,
|
||||||
|
tags TEXT,
|
||||||
|
label TEXT,
|
||||||
|
save_path TEXT,
|
||||||
|
paused BOOLEAN,
|
||||||
|
ignore_rules BOOLEAN,
|
||||||
|
limit_upload_speed INT,
|
||||||
|
limit_download_speed INT,
|
||||||
|
client_id INTEGER
|
||||||
|
CONSTRAINT action_client_id_fkey
|
||||||
|
REFERENCES client
|
||||||
|
ON DELETE SET NULL,
|
||||||
|
filter_id INTEGER
|
||||||
|
CONSTRAINT action_filter_id_fkey
|
||||||
|
REFERENCES filter,
|
||||||
|
webhook_host TEXT,
|
||||||
|
webhook_data TEXT,
|
||||||
|
webhook_method TEXT,
|
||||||
|
webhook_type TEXT,
|
||||||
|
webhook_headers TEXT [] default '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO action_dg_tmp(id, name, type, enabled, exec_cmd, exec_args, watch_folder, category, tags, label, save_path,
|
||||||
|
paused, ignore_rules, limit_upload_speed, limit_download_speed, client_id, filter_id,
|
||||||
|
webhook_host, webhook_data, webhook_method, webhook_type, webhook_headers)
|
||||||
|
SELECT id,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
enabled,
|
||||||
|
exec_cmd,
|
||||||
|
exec_args,
|
||||||
|
watch_folder,
|
||||||
|
category,
|
||||||
|
tags,
|
||||||
|
label,
|
||||||
|
save_path,
|
||||||
|
paused,
|
||||||
|
ignore_rules,
|
||||||
|
limit_upload_speed,
|
||||||
|
limit_download_speed,
|
||||||
|
client_id,
|
||||||
|
filter_id,
|
||||||
|
webhook_host,
|
||||||
|
webhook_data,
|
||||||
|
webhook_method,
|
||||||
|
webhook_type,
|
||||||
|
webhook_headers
|
||||||
|
FROM action;
|
||||||
|
|
||||||
|
DROP TABLE action;
|
||||||
|
|
||||||
|
ALTER TABLE action_dg_tmp
|
||||||
|
RENAME TO action;
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
CREATE TABLE filter_indexer_dg_tmp
|
||||||
|
(
|
||||||
|
filter_id INTEGER
|
||||||
|
CONSTRAINT filter_indexer_filter_id_fkey
|
||||||
|
REFERENCES filter,
|
||||||
|
indexer_id INTEGER
|
||||||
|
CONSTRAINT filter_indexer_indexer_id_fkey
|
||||||
|
REFERENCES indexer
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY (filter_id, indexer_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO filter_indexer_dg_tmp(filter_id, indexer_id)
|
||||||
|
SELECT filter_id, indexer_id
|
||||||
|
FROM filter_indexer;
|
||||||
|
|
||||||
|
DROP TABLE filter_indexer;
|
||||||
|
|
||||||
|
ALTER TABLE filter_indexer_dg_tmp
|
||||||
|
RENAME TO filter_indexer;
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
CREATE TABLE release_action_status_dg_tmp
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
status TEXT,
|
||||||
|
action TEXT not null,
|
||||||
|
type TEXT not null,
|
||||||
|
rejections TEXT [] default '{}' not null,
|
||||||
|
timestamp TIMESTAMP default CURRENT_TIMESTAMP,
|
||||||
|
raw TEXT,
|
||||||
|
log TEXT,
|
||||||
|
release_id INTEGER not null
|
||||||
|
CONSTRAINT release_action_status_release_id_fkey
|
||||||
|
REFERENCES "release"
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO release_action_status_dg_tmp(id, status, action, type, rejections, timestamp, raw, log, release_id)
|
||||||
|
SELECT id,
|
||||||
|
status,
|
||||||
|
action,
|
||||||
|
type,
|
||||||
|
rejections,
|
||||||
|
timestamp,
|
||||||
|
raw,
|
||||||
|
log,
|
||||||
|
release_id
|
||||||
|
FROM release_action_status;
|
||||||
|
|
||||||
|
DROP TABLE release_action_status;
|
||||||
|
|
||||||
|
ALTER TABLE release_action_status_dg_tmp
|
||||||
|
RENAME TO release_action_status;
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const postgresSchema = `
|
||||||
|
CREATE TABLE users
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username TEXT NOT NULL,
|
||||||
|
password TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (username)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE indexer
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
identifier TEXT,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
settings TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (identifier)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE irc_network
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
server TEXT NOT NULL,
|
||||||
|
port INTEGER NOT NULL,
|
||||||
|
tls BOOLEAN,
|
||||||
|
pass TEXT,
|
||||||
|
invite_command TEXT,
|
||||||
|
nickserv_account TEXT,
|
||||||
|
nickserv_password TEXT,
|
||||||
|
connected BOOLEAN,
|
||||||
|
connected_since TIMESTAMP,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (server, port, nickserv_account)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE irc_channel
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
password TEXT,
|
||||||
|
detached BOOLEAN,
|
||||||
|
network_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (network_id) REFERENCES irc_network(id),
|
||||||
|
UNIQUE (network_id, name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE filter
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
min_size TEXT,
|
||||||
|
max_size TEXT,
|
||||||
|
delay INTEGER,
|
||||||
|
priority INTEGER DEFAULT 0 NOT NULL,
|
||||||
|
match_releases TEXT,
|
||||||
|
except_releases TEXT,
|
||||||
|
use_regex BOOLEAN,
|
||||||
|
match_release_groups TEXT,
|
||||||
|
except_release_groups TEXT,
|
||||||
|
scene BOOLEAN,
|
||||||
|
freeleech BOOLEAN,
|
||||||
|
freeleech_percent TEXT,
|
||||||
|
shows TEXT,
|
||||||
|
seasons TEXT,
|
||||||
|
episodes TEXT,
|
||||||
|
resolutions TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
codecs TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
sources TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
containers TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
match_hdr TEXT [] DEFAULT '{}',
|
||||||
|
except_hdr TEXT [] DEFAULT '{}',
|
||||||
|
years TEXT,
|
||||||
|
artists TEXT,
|
||||||
|
albums TEXT,
|
||||||
|
release_types_match TEXT [] DEFAULT '{}',
|
||||||
|
release_types_ignore TEXT [] DEFAULT '{}',
|
||||||
|
formats TEXT [] DEFAULT '{}',
|
||||||
|
quality TEXT [] DEFAULT '{}',
|
||||||
|
media TEXT [] DEFAULT '{}',
|
||||||
|
log_score INTEGER,
|
||||||
|
has_log BOOLEAN,
|
||||||
|
has_cue BOOLEAN,
|
||||||
|
perfect_flac BOOLEAN,
|
||||||
|
match_categories TEXT,
|
||||||
|
except_categories TEXT,
|
||||||
|
match_uploaders TEXT,
|
||||||
|
except_uploaders TEXT,
|
||||||
|
tags TEXT,
|
||||||
|
except_tags TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE filter_indexer
|
||||||
|
(
|
||||||
|
filter_id INTEGER,
|
||||||
|
indexer_id INTEGER,
|
||||||
|
FOREIGN KEY (filter_id) REFERENCES filter(id),
|
||||||
|
FOREIGN KEY (indexer_id) REFERENCES indexer(id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY (filter_id, indexer_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE client
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
type TEXT,
|
||||||
|
host TEXT NOT NULL,
|
||||||
|
port INTEGER,
|
||||||
|
tls BOOLEAN,
|
||||||
|
tls_skip_verify BOOLEAN,
|
||||||
|
username TEXT,
|
||||||
|
password TEXT,
|
||||||
|
settings JSON
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE action
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
type TEXT,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
exec_cmd TEXT,
|
||||||
|
exec_args TEXT,
|
||||||
|
watch_folder TEXT,
|
||||||
|
category TEXT,
|
||||||
|
tags TEXT,
|
||||||
|
label TEXT,
|
||||||
|
save_path TEXT,
|
||||||
|
paused BOOLEAN,
|
||||||
|
ignore_rules BOOLEAN,
|
||||||
|
limit_upload_speed INT,
|
||||||
|
limit_download_speed INT,
|
||||||
|
webhook_host TEXT,
|
||||||
|
webhook_method TEXT,
|
||||||
|
webhook_type TEXT,
|
||||||
|
webhook_data TEXT,
|
||||||
|
webhook_headers TEXT [] DEFAULT '{}',
|
||||||
|
client_id INTEGER,
|
||||||
|
filter_id INTEGER,
|
||||||
|
FOREIGN KEY (filter_id) REFERENCES filter(id),
|
||||||
|
FOREIGN KEY (client_id) REFERENCES client(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "release"
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
filter_status TEXT,
|
||||||
|
rejections TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
indexer TEXT,
|
||||||
|
filter TEXT,
|
||||||
|
protocol TEXT,
|
||||||
|
implementation TEXT,
|
||||||
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
group_id TEXT,
|
||||||
|
torrent_id TEXT,
|
||||||
|
torrent_name TEXT,
|
||||||
|
size INTEGER,
|
||||||
|
raw TEXT,
|
||||||
|
title TEXT,
|
||||||
|
category TEXT,
|
||||||
|
season INTEGER,
|
||||||
|
episode INTEGER,
|
||||||
|
year INTEGER,
|
||||||
|
resolution TEXT,
|
||||||
|
source TEXT,
|
||||||
|
codec TEXT,
|
||||||
|
container TEXT,
|
||||||
|
hdr TEXT,
|
||||||
|
audio TEXT,
|
||||||
|
release_group TEXT,
|
||||||
|
region TEXT,
|
||||||
|
language TEXT,
|
||||||
|
edition TEXT,
|
||||||
|
unrated BOOLEAN,
|
||||||
|
hybrid BOOLEAN,
|
||||||
|
proper BOOLEAN,
|
||||||
|
repack BOOLEAN,
|
||||||
|
website TEXT,
|
||||||
|
artists TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
type TEXT,
|
||||||
|
format TEXT,
|
||||||
|
quality TEXT,
|
||||||
|
log_score INTEGER,
|
||||||
|
has_log BOOLEAN,
|
||||||
|
has_cue BOOLEAN,
|
||||||
|
is_scene BOOLEAN,
|
||||||
|
origin TEXT,
|
||||||
|
tags TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
freeleech BOOLEAN,
|
||||||
|
freeleech_percent INTEGER,
|
||||||
|
uploader TEXT,
|
||||||
|
pre_time TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE release_action_status
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
status TEXT,
|
||||||
|
action TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
rejections TEXT [] DEFAULT '{}' NOT NULL,
|
||||||
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
raw TEXT,
|
||||||
|
log TEXT,
|
||||||
|
release_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (release_id) REFERENCES "release"(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
var postgresMigrations = []string{
|
||||||
|
"",
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,26 +55,26 @@ func (db *DB) migratePostgres() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if version == len(migrations) {
|
if version == len(postgresMigrations) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if version > len(migrations) {
|
if version > len(postgresMigrations) {
|
||||||
return fmt.Errorf("old")
|
return fmt.Errorf("old")
|
||||||
}
|
}
|
||||||
|
|
||||||
if version == 0 {
|
if version == 0 {
|
||||||
if _, err := tx.Exec(schema); err != nil {
|
if _, err := tx.Exec(postgresSchema); err != nil {
|
||||||
return fmt.Errorf("failed to initialize schema: %v", err)
|
return fmt.Errorf("failed to initialize schema: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := version; i < len(migrations); i++ {
|
for i := version; i < len(postgresMigrations); i++ {
|
||||||
if _, err := tx.Exec(migrations[i]); err != nil {
|
if _, err := tx.Exec(postgresMigrations[i]); err != nil {
|
||||||
return fmt.Errorf("failed to execute migration #%v: %v", i, err)
|
return fmt.Errorf("failed to execute migration #%v: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.Exec(`INSERT INTO schema_migrations (id, version) VALUES (1, $1) ON CONFLICT (id) DO UPDATE SET version = $1`, len(migrations))
|
_, err = tx.Exec(`INSERT INTO schema_migrations (id, version) VALUES (1, $1) ON CONFLICT (id) DO UPDATE SET version = $1`, len(postgresMigrations))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to bump schema version: %v", err)
|
return fmt.Errorf("failed to bump schema version: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReleaseRepo struct {
|
type ReleaseRepo struct {
|
||||||
|
@ -19,42 +18,43 @@ func NewReleaseRepo(db *DB) domain.ReleaseRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) (*domain.Release, error) {
|
func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) (*domain.Release, error) {
|
||||||
//r.db.lock.RLock()
|
queryBuilder := repo.db.squirrel.
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
query, args, err := sq.
|
|
||||||
Insert("release").
|
Insert("release").
|
||||||
Columns("filter_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "group_id", "torrent_id", "torrent_name", "size", "raw", "title", "category", "season", "episode", "year", "resolution", "source", "codec", "container", "hdr", "audio", "release_group", "region", "language", "edition", "unrated", "hybrid", "proper", "repack", "website", "artists", "type", "format", "quality", "log_score", "has_log", "has_cue", "is_scene", "origin", "tags", "freeleech", "freeleech_percent", "uploader", "pre_time").
|
Columns("filter_status", "rejections", "indexer", "filter", "protocol", "implementation", "timestamp", "group_id", "torrent_id", "torrent_name", "size", "raw", "title", "category", "season", "episode", "year", "resolution", "source", "codec", "container", "hdr", "audio", "release_group", "region", "language", "edition", "unrated", "hybrid", "proper", "repack", "website", "artists", "type", "format", "quality", "log_score", "has_log", "has_cue", "is_scene", "origin", "tags", "freeleech", "freeleech_percent", "uploader", "pre_time").
|
||||||
Values(r.FilterStatus, pq.Array(r.Rejections), r.Indexer, r.FilterName, r.Protocol, r.Implementation, r.Timestamp, r.GroupID, r.TorrentID, r.TorrentName, r.Size, r.Raw, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Resolution, r.Source, r.Codec, r.Container, r.HDR, r.Audio, r.Group, r.Region, r.Language, r.Edition, r.Unrated, r.Hybrid, r.Proper, r.Repack, r.Website, pq.Array(r.Artists), r.Type, r.Format, r.Quality, r.LogScore, r.HasLog, r.HasCue, r.IsScene, r.Origin, pq.Array(r.Tags), r.Freeleech, r.FreeleechPercent, r.Uploader, r.PreTime).
|
Values(r.FilterStatus, pq.Array(r.Rejections), r.Indexer, r.FilterName, r.Protocol, r.Implementation, r.Timestamp, r.GroupID, r.TorrentID, r.TorrentName, r.Size, r.Raw, r.Title, r.Category, r.Season, r.Episode, r.Year, r.Resolution, r.Source, r.Codec, r.Container, r.HDR, r.Audio, r.Group, r.Region, r.Language, r.Edition, r.Unrated, r.Hybrid, r.Proper, r.Repack, r.Website, pq.Array(r.Artists), r.Type, r.Format, r.Quality, r.LogScore, r.HasLog, r.HasCue, r.IsScene, r.Origin, pq.Array(r.Tags), r.Freeleech, r.FreeleechPercent, r.Uploader, r.PreTime).
|
||||||
ToSql()
|
Suffix("RETURNING id").RunWith(repo.db.handler)
|
||||||
|
|
||||||
res, err := repo.db.handler.ExecContext(ctx, query, args...)
|
// return values
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error inserting release")
|
log.Error().Stack().Err(err).Msg("release.store: error executing query")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
r.ID = retID
|
||||||
r.ID = resId
|
|
||||||
|
|
||||||
log.Trace().Msgf("release.store: %+v", r)
|
log.Debug().Msgf("release.store: %+v", r)
|
||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain.ReleaseActionStatus) error {
|
func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain.ReleaseActionStatus) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
if a.ID != 0 {
|
if a.ID != 0 {
|
||||||
query, args, err := sq.
|
queryBuilder := repo.db.squirrel.
|
||||||
Update("release_action_status").
|
Update("release_action_status").
|
||||||
Set("status", a.Status).
|
Set("status", a.Status).
|
||||||
Set("rejections", pq.Array(a.Rejections)).
|
Set("rejections", pq.Array(a.Rejections)).
|
||||||
Set("timestamp", a.Timestamp).
|
Set("timestamp", a.Timestamp).
|
||||||
Where("id = ?", a.ID).
|
Where("id = ?", a.ID).
|
||||||
Where("release_id = ?", a.ReleaseID).
|
Where("release_id = ?", a.ReleaseID)
|
||||||
ToSql()
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("release.store: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err = repo.db.handler.ExecContext(ctx, query, args...)
|
_, err = repo.db.handler.ExecContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -63,20 +63,22 @@ func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
query, args, err := sq.
|
queryBuilder := repo.db.squirrel.
|
||||||
Insert("release_action_status").
|
Insert("release_action_status").
|
||||||
Columns("status", "action", "type", "rejections", "timestamp", "release_id").
|
Columns("status", "action", "type", "rejections", "timestamp", "release_id").
|
||||||
Values(a.Status, a.Action, a.Type, pq.Array(a.Rejections), a.Timestamp, a.ReleaseID).
|
Values(a.Status, a.Action, a.Type, pq.Array(a.Rejections), a.Timestamp, a.ReleaseID).
|
||||||
ToSql()
|
Suffix("RETURNING id").RunWith(repo.db.handler)
|
||||||
|
|
||||||
res, err := repo.db.handler.ExecContext(ctx, query, args...)
|
// return values
|
||||||
|
var retID int64
|
||||||
|
|
||||||
|
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error inserting status of release")
|
log.Error().Stack().Err(err).Msg("release.storeReleaseActionStatus: error executing query")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, _ := res.LastInsertId()
|
a.ID = retID
|
||||||
a.ID = resId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("release.store_release_action_status: %+v", a)
|
log.Trace().Msgf("release.store_release_action_status: %+v", a)
|
||||||
|
@ -84,12 +86,32 @@ func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryParams) ([]domain.Release, int64, int64, error) {
|
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryParams) ([]*domain.Release, int64, int64, error) {
|
||||||
//r.db.lock.RLock()
|
tx, err := repo.db.BeginTx(ctx, &sql.TxOptions{})
|
||||||
//defer r.db.lock.RUnlock()
|
if err != nil {
|
||||||
|
return nil, 0, 0, err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
queryBuilder := sq.
|
releases, nextCursor, total, err := repo.findReleases(ctx, tx, params)
|
||||||
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.protocol", "r.title", "r.torrent_name", "r.size", "r.timestamp", "COUNT() OVER() AS total_count").
|
if err != nil {
|
||||||
|
return nil, nextCursor, total, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, release := range releases {
|
||||||
|
statuses, err := repo.attachActionStatus(ctx, tx, release.ID)
|
||||||
|
if err != nil {
|
||||||
|
return releases, nextCursor, total, err
|
||||||
|
}
|
||||||
|
release.ActionStatus = statuses
|
||||||
|
}
|
||||||
|
|
||||||
|
return releases, nextCursor, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain.ReleaseQueryParams) ([]*domain.Release, int64, int64, error) {
|
||||||
|
queryBuilder := repo.db.squirrel.
|
||||||
|
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.protocol", "r.title", "r.torrent_name", "r.size", "r.timestamp", "COUNT(*) OVER() AS total_count").
|
||||||
From("release r").
|
From("release r").
|
||||||
OrderBy("r.timestamp DESC")
|
OrderBy("r.timestamp DESC")
|
||||||
|
|
||||||
|
@ -123,9 +145,9 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryPar
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
log.Trace().Str("database", "release.find").Msgf("query: '%v', args: '%v'", query, args)
|
log.Trace().Str("database", "release.find").Msgf("query: '%v', args: '%v'", query, args)
|
||||||
|
|
||||||
res := make([]domain.Release, 0)
|
res := make([]*domain.Release, 0)
|
||||||
|
|
||||||
rows, err := repo.db.handler.QueryContext(ctx, query, args...)
|
rows, err := tx.QueryContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("error fetching releases")
|
log.Error().Stack().Err(err).Msg("error fetching releases")
|
||||||
return res, 0, 0, nil
|
return res, 0, 0, nil
|
||||||
|
@ -153,36 +175,21 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryPar
|
||||||
rls.Indexer = indexer.String
|
rls.Indexer = indexer.String
|
||||||
rls.FilterName = filter.String
|
rls.FilterName = filter.String
|
||||||
|
|
||||||
// get action status
|
res = append(res, &rls)
|
||||||
actionStatus, err := repo.GetActionStatusByReleaseID(ctx, rls.ID)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("release.find: error getting action status")
|
|
||||||
return res, 0, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rls.ActionStatus = actionStatus
|
|
||||||
|
|
||||||
res = append(res, rls)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextCursor := int64(0)
|
nextCursor := int64(0)
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
lastID := res[len(res)-1].ID
|
lastID := res[len(res)-1].ID
|
||||||
nextCursor = lastID
|
nextCursor = lastID
|
||||||
//nextCursor, _ = strconv.ParseInt(lastID, 10, 64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nextCursor, countItems, nil
|
return res, nextCursor, countItems, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
query := `
|
query := `SELECT DISTINCT indexer FROM "release" UNION SELECT DISTINCT identifier indexer FROM indexer;`
|
||||||
SELECT DISTINCT indexer FROM "release"
|
|
||||||
UNION
|
|
||||||
SELECT DISTINCT identifier indexer FROM indexer;`
|
|
||||||
|
|
||||||
log.Trace().Str("database", "release.get_indexers").Msgf("query: '%v'", query)
|
log.Trace().Str("database", "release.get_indexers").Msgf("query: '%v'", query)
|
||||||
|
|
||||||
|
@ -216,10 +223,8 @@ func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]domain.ReleaseActionStatus, error) {
|
func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]domain.ReleaseActionStatus, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
queryBuilder := sq.
|
queryBuilder := repo.db.squirrel.
|
||||||
Select("id", "status", "action", "type", "rejections", "timestamp").
|
Select("id", "status", "action", "type", "rejections", "timestamp").
|
||||||
From("release_action_status").
|
From("release_action_status").
|
||||||
Where("release_id = ?", releaseID)
|
Where("release_id = ?", releaseID)
|
||||||
|
@ -255,16 +260,52 @@ func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, release
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *ReleaseRepo) attachActionStatus(ctx context.Context, tx *Tx, releaseID int64) ([]domain.ReleaseActionStatus, error) {
|
||||||
|
|
||||||
|
queryBuilder := repo.db.squirrel.
|
||||||
|
Select("id", "status", "action", "type", "rejections", "timestamp").
|
||||||
|
From("release_action_status").
|
||||||
|
Where("release_id = ?", releaseID)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
|
||||||
|
res := make([]domain.ReleaseActionStatus, 0)
|
||||||
|
|
||||||
|
rows, err := tx.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("error fetching releases")
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
log.Error().Stack().Err(err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var rls domain.ReleaseActionStatus
|
||||||
|
|
||||||
|
if err := rows.Scan(&rls.ID, &rls.Status, &rls.Action, &rls.Type, pq.Array(&rls.Rejections), &rls.Timestamp); err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("release.find: error scanning data to struct")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, rls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) Stats(ctx context.Context) (*domain.ReleaseStats, error) {
|
func (repo *ReleaseRepo) Stats(ctx context.Context) (*domain.ReleaseStats, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
query := `SELECT COUNT(*) total,
|
query := `SELECT COUNT(*) total,
|
||||||
IFNULL(SUM(CASE WHEN filter_status = 'FILTER_APPROVED' THEN 1 ELSE 0 END), 0) filtered_count,
|
COALESCE(SUM(CASE WHEN filter_status = 'FILTER_APPROVED' THEN 1 ELSE 0 END), 0) AS filtered_count,
|
||||||
IFNULL(SUM(CASE WHEN filter_status = 'FILTER_REJECTED' THEN 1 ELSE 0 END), 0) filter_rejected_count,
|
COALESCE(SUM(CASE WHEN filter_status = 'FILTER_REJECTED' THEN 1 ELSE 0 END), 0) AS filter_rejected_count,
|
||||||
(SELECT IFNULL(SUM(CASE WHEN status = 'PUSH_APPROVED' THEN 1 ELSE 0 END), 0)
|
(SELECT COALESCE(SUM(CASE WHEN status = 'PUSH_APPROVED' THEN 1 ELSE 0 END), 0)
|
||||||
FROM "release_action_status") AS push_approved_count,
|
FROM "release_action_status") AS push_approved_count,
|
||||||
(SELECT IFNULL(SUM(CASE WHEN status = 'PUSH_REJECTED' THEN 1 ELSE 0 END), 0)
|
(SELECT COALESCE(SUM(CASE WHEN status = 'PUSH_REJECTED' THEN 1 ELSE 0 END), 0)
|
||||||
FROM "release_action_status") AS push_rejected_count
|
FROM "release_action_status") AS push_rejected_count
|
||||||
FROM "release";`
|
FROM "release";`
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,10 @@ func (db *DB) migrateSQLite() error {
|
||||||
return fmt.Errorf("failed to query schema version: %v", err)
|
return fmt.Errorf("failed to query schema version: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if version == len(migrations) {
|
if version == len(sqliteMigrations) {
|
||||||
return nil
|
return nil
|
||||||
} else if version > len(migrations) {
|
} else if version > len(sqliteMigrations) {
|
||||||
return fmt.Errorf("autobrr (version %d) older than schema (version: %d)", len(migrations), version)
|
return fmt.Errorf("autobrr (version %d) older than schema (version: %d)", len(sqliteMigrations), version)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := db.handler.Begin()
|
tx, err := db.handler.Begin()
|
||||||
|
@ -71,12 +71,12 @@ func (db *DB) migrateSQLite() error {
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
if version == 0 {
|
if version == 0 {
|
||||||
if _, err := tx.Exec(schema); err != nil {
|
if _, err := tx.Exec(sqliteSchema); err != nil {
|
||||||
return fmt.Errorf("failed to initialize schema: %v", err)
|
return fmt.Errorf("failed to initialize schema: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := version; i < len(migrations); i++ {
|
for i := version; i < len(sqliteMigrations); i++ {
|
||||||
if _, err := tx.Exec(migrations[i]); err != nil {
|
if _, err := tx.Exec(sqliteMigrations[i]); err != nil {
|
||||||
return fmt.Errorf("failed to execute migration #%v: %v", i, err)
|
return fmt.Errorf("failed to execute migration #%v: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,13 +86,13 @@ func (db *DB) migrateSQLite() error {
|
||||||
// get data from filter.sources, check if specific types, move to new table and clear
|
// get data from filter.sources, check if specific types, move to new table and clear
|
||||||
// if migration 6
|
// if migration 6
|
||||||
// TODO 2022-01-30 remove this in future version
|
// TODO 2022-01-30 remove this in future version
|
||||||
if version == 5 && len(migrations) == 6 {
|
if version == 5 && len(sqliteMigrations) == 6 {
|
||||||
if err := customMigrateCopySourcesToMedia(tx); err != nil {
|
if err := customMigrateCopySourcesToMedia(tx); err != nil {
|
||||||
return fmt.Errorf("could not run custom data migration: %v", err)
|
return fmt.Errorf("could not run custom data migration: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.Exec(fmt.Sprintf("PRAGMA user_version = %d", len(migrations)))
|
_, err = tx.Exec(fmt.Sprintf("PRAGMA user_version = %d", len(sqliteMigrations)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to bump schema version: %v", err)
|
return fmt.Errorf("failed to bump schema version: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,19 @@ func NewUserRepo(db *DB) domain.UserRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepo) FindByUsername(ctx context.Context, username string) (*domain.User, error) {
|
func (r *UserRepo) FindByUsername(ctx context.Context, username string) (*domain.User, error) {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
query := `SELECT id, username, password FROM users WHERE username = ?`
|
queryBuilder := r.db.squirrel.
|
||||||
|
Select("id", "username", "password").
|
||||||
|
From("users").
|
||||||
|
Where("username = ?", username)
|
||||||
|
|
||||||
row := r.db.handler.QueryRowContext(ctx, query, username)
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("user.store: error building query")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||||
if err := row.Err(); err != nil {
|
if err := row.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -37,25 +44,49 @@ func (r *UserRepo) FindByUsername(ctx context.Context, username string) (*domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepo) Store(ctx context.Context, user domain.User) error {
|
func (r *UserRepo) Store(ctx context.Context, user domain.User) error {
|
||||||
//r.db.lock.RLock()
|
|
||||||
//defer r.db.lock.RUnlock()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if user.ID != 0 {
|
|
||||||
update := `UPDATE users SET password = ? WHERE username = ?`
|
|
||||||
_, err = r.db.handler.ExecContext(ctx, update, user.Password, user.Username)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
queryBuilder := r.db.squirrel.
|
||||||
query := `INSERT INTO users (username, password) VALUES (?, ?)`
|
Update("users").
|
||||||
_, err = r.db.handler.ExecContext(ctx, query, user.Username, user.Password)
|
Set("username", user.Username).
|
||||||
if err != nil {
|
Set("password", user.Password).
|
||||||
log.Error().Stack().Err(err).Msg("error executing query")
|
Where("username = ?", user.Username)
|
||||||
return err
|
|
||||||
}
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("user.store: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("user.store: error executing query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (r *UserRepo) Update(ctx context.Context, user domain.User) error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
queryBuilder := r.db.squirrel.
|
||||||
|
Update("users").
|
||||||
|
Set("username", user.Username).
|
||||||
|
Set("password", user.Password).
|
||||||
|
Where("username = ?", user.Username)
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("user.store: error building query")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Stack().Err(err).Msg("user.store: error executing query")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -7,7 +7,7 @@ type ActionRepo interface {
|
||||||
StoreFilterActions(ctx context.Context, actions []Action, filterID int64) ([]Action, error)
|
StoreFilterActions(ctx context.Context, actions []Action, filterID int64) ([]Action, error)
|
||||||
DeleteByFilterID(ctx context.Context, filterID int) error
|
DeleteByFilterID(ctx context.Context, filterID int) error
|
||||||
FindByFilterID(ctx context.Context, filterID int) ([]Action, error)
|
FindByFilterID(ctx context.Context, filterID int) ([]Action, error)
|
||||||
List() ([]Action, error)
|
List(ctx context.Context) ([]Action, error)
|
||||||
Delete(actionID int) error
|
Delete(actionID int) error
|
||||||
ToggleEnabled(actionID int) error
|
ToggleEnabled(actionID int) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ type DownloadClientRepo interface {
|
||||||
List(ctx context.Context) ([]DownloadClient, error)
|
List(ctx context.Context) ([]DownloadClient, error)
|
||||||
FindByID(ctx context.Context, id int32) (*DownloadClient, error)
|
FindByID(ctx context.Context, id int32) (*DownloadClient, error)
|
||||||
Store(ctx context.Context, client DownloadClient) (*DownloadClient, error)
|
Store(ctx context.Context, client DownloadClient) (*DownloadClient, error)
|
||||||
|
Update(ctx context.Context, client DownloadClient) (*DownloadClient, error)
|
||||||
Delete(ctx context.Context, clientID int) error
|
Delete(ctx context.Context, clientID int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexerRepo interface {
|
type IndexerRepo interface {
|
||||||
Store(indexer Indexer) (*Indexer, error)
|
Store(ctx context.Context, indexer Indexer) (*Indexer, error)
|
||||||
Update(indexer Indexer) (*Indexer, error)
|
Update(ctx context.Context, indexer Indexer) (*Indexer, error)
|
||||||
List() ([]Indexer, error)
|
List(ctx context.Context) ([]Indexer, error)
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
FindByFilterID(ctx context.Context, id int) ([]Indexer, error)
|
FindByFilterID(ctx context.Context, id int) ([]Indexer, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,11 +71,12 @@ type IrcRepo interface {
|
||||||
StoreNetwork(network *IrcNetwork) error
|
StoreNetwork(network *IrcNetwork) error
|
||||||
UpdateNetwork(ctx context.Context, network *IrcNetwork) error
|
UpdateNetwork(ctx context.Context, network *IrcNetwork) error
|
||||||
StoreChannel(networkID int64, channel *IrcChannel) error
|
StoreChannel(networkID int64, channel *IrcChannel) error
|
||||||
|
UpdateChannel(channel *IrcChannel) error
|
||||||
StoreNetworkChannels(ctx context.Context, networkID int64, channels []IrcChannel) error
|
StoreNetworkChannels(ctx context.Context, networkID int64, channels []IrcChannel) error
|
||||||
CheckExistingNetwork(ctx context.Context, network *IrcNetwork) (*IrcNetwork, error)
|
CheckExistingNetwork(ctx context.Context, network *IrcNetwork) (*IrcNetwork, error)
|
||||||
FindActiveNetworks(ctx context.Context) ([]IrcNetwork, error)
|
FindActiveNetworks(ctx context.Context) ([]IrcNetwork, error)
|
||||||
ListNetworks(ctx context.Context) ([]IrcNetwork, error)
|
ListNetworks(ctx context.Context) ([]IrcNetwork, error)
|
||||||
ListChannels(networkID int64) ([]IrcChannel, error)
|
ListChannels(networkID int64) ([]IrcChannel, error)
|
||||||
GetNetworkByID(id int64) (*IrcNetwork, error)
|
GetNetworkByID(ctx context.Context, id int64) (*IrcNetwork, error)
|
||||||
DeleteNetwork(ctx context.Context, id int64) error
|
DeleteNetwork(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
|
|
||||||
type ReleaseRepo interface {
|
type ReleaseRepo interface {
|
||||||
Store(ctx context.Context, release *Release) (*Release, error)
|
Store(ctx context.Context, release *Release) (*Release, error)
|
||||||
Find(ctx context.Context, params ReleaseQueryParams) (res []Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, params ReleaseQueryParams) (res []*Release, nextCursor int64, count int64, err error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]ReleaseActionStatus, error)
|
GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]ReleaseActionStatus, error)
|
||||||
Stats(ctx context.Context) (*ReleaseStats, error)
|
Stats(ctx context.Context) (*ReleaseStats, error)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import "context"
|
||||||
type UserRepo interface {
|
type UserRepo interface {
|
||||||
FindByUsername(ctx context.Context, username string) (*User, error)
|
FindByUsername(ctx context.Context, username string) (*User, error)
|
||||||
Store(ctx context.Context, user User) error
|
Store(ctx context.Context, user User) error
|
||||||
|
Update(ctx context.Context, user User) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|
|
@ -11,6 +11,7 @@ type Service interface {
|
||||||
List(ctx context.Context) ([]domain.DownloadClient, error)
|
List(ctx context.Context) ([]domain.DownloadClient, error)
|
||||||
FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error)
|
FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error)
|
||||||
Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
||||||
|
Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
||||||
Delete(ctx context.Context, clientID int) error
|
Delete(ctx context.Context, clientID int) error
|
||||||
Test(client domain.DownloadClient) error
|
Test(client domain.DownloadClient) error
|
||||||
}
|
}
|
||||||
|
@ -43,6 +44,18 @@ func (s *service) Store(ctx context.Context, client domain.DownloadClient) (*dom
|
||||||
return s.repo.Store(ctx, client)
|
return s.repo.Store(ctx, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
|
||||||
|
// validate data
|
||||||
|
if client.Host == "" {
|
||||||
|
return nil, errors.New("validation error: no host")
|
||||||
|
} else if client.Type == "" {
|
||||||
|
return nil, errors.New("validation error: no type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// store
|
||||||
|
return s.repo.Update(ctx, client)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) Delete(ctx context.Context, clientID int) error {
|
func (s *service) Delete(ctx context.Context, clientID int) error {
|
||||||
return s.repo.Delete(ctx, clientID)
|
return s.repo.Delete(ctx, clientID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,12 +47,12 @@ func (s *service) ListFilters(ctx context.Context) ([]domain.Filter, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret []domain.Filter
|
ret := make([]domain.Filter, 0)
|
||||||
|
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
indexers, err := s.indexerSvc.FindByFilterID(ctx, filter.ID)
|
indexers, err := s.indexerSvc.FindByFilterID(ctx, filter.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return ret, err
|
||||||
}
|
}
|
||||||
filter.Indexers = indexers
|
filter.Indexers = indexers
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type actionService interface {
|
type actionService interface {
|
||||||
Fetch() ([]domain.Action, error)
|
List(ctx context.Context) ([]domain.Action, error)
|
||||||
Store(ctx context.Context, action domain.Action) (*domain.Action, error)
|
Store(ctx context.Context, action domain.Action) (*domain.Action, error)
|
||||||
Delete(actionID int) error
|
Delete(actionID int) error
|
||||||
ToggleEnabled(actionID int) error
|
ToggleEnabled(actionID int) error
|
||||||
|
@ -39,7 +39,7 @@ func (h actionHandler) Routes(r chi.Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h actionHandler) getActions(w http.ResponseWriter, r *http.Request) {
|
func (h actionHandler) getActions(w http.ResponseWriter, r *http.Request) {
|
||||||
actions, err := h.service.Fetch()
|
actions, err := h.service.List(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// encode error
|
// encode error
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
type downloadClientService interface {
|
type downloadClientService interface {
|
||||||
List(ctx context.Context) ([]domain.DownloadClient, error)
|
List(ctx context.Context) ([]domain.DownloadClient, error)
|
||||||
Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
||||||
|
Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
|
||||||
Delete(ctx context.Context, clientID int) error
|
Delete(ctx context.Context, clientID int) error
|
||||||
Test(client domain.DownloadClient) error
|
Test(client domain.DownloadClient) error
|
||||||
}
|
}
|
||||||
|
@ -93,7 +94,7 @@ func (h downloadClientHandler) update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := h.service.Store(r.Context(), data)
|
client, err := h.service.Update(r.Context(), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.encoder.Error(w, err)
|
h.encoder.Error(w, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type indexerService interface {
|
type indexerService interface {
|
||||||
Store(indexer domain.Indexer) (*domain.Indexer, error)
|
Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error)
|
||||||
Update(indexer domain.Indexer) (*domain.Indexer, error)
|
Update(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error)
|
||||||
List() ([]domain.Indexer, error)
|
List(ctx context.Context) ([]domain.Indexer, error)
|
||||||
GetAll() ([]*domain.IndexerDefinition, error)
|
GetAll() ([]*domain.IndexerDefinition, error)
|
||||||
GetTemplates() ([]domain.IndexerDefinition, error)
|
GetTemplates() ([]domain.IndexerDefinition, error)
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
|
@ -55,20 +55,23 @@ func (h indexerHandler) getSchema(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h indexerHandler) store(w http.ResponseWriter, r *http.Request) {
|
func (h indexerHandler) store(w http.ResponseWriter, r *http.Request) {
|
||||||
var data domain.Indexer
|
var (
|
||||||
|
ctx = r.Context()
|
||||||
|
data domain.Indexer
|
||||||
|
)
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
indexer, err := h.service.Store(data)
|
indexer, err := h.service.Store(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//
|
//
|
||||||
h.encoder.StatusResponse(r.Context(), w, nil, http.StatusBadRequest)
|
h.encoder.StatusResponse(ctx, w, nil, http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.encoder.StatusResponse(r.Context(), w, indexer, http.StatusCreated)
|
h.encoder.StatusResponse(ctx, w, indexer, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h indexerHandler) update(w http.ResponseWriter, r *http.Request) {
|
func (h indexerHandler) update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -81,7 +84,7 @@ func (h indexerHandler) update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
indexer, err := h.service.Update(data)
|
indexer, err := h.service.Update(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@ -118,7 +121,7 @@ func (h indexerHandler) getAll(w http.ResponseWriter, r *http.Request) {
|
||||||
func (h indexerHandler) list(w http.ResponseWriter, r *http.Request) {
|
func (h indexerHandler) list(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
indexers, err := h.service.List()
|
indexers, err := h.service.List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ type ircService interface {
|
||||||
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
||||||
DeleteNetwork(ctx context.Context, id int64) error
|
DeleteNetwork(ctx context.Context, id int64) error
|
||||||
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
GetNetworkByID(ctx context.Context, id int64) (*domain.IrcNetwork, error)
|
||||||
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
StoreChannel(networkID int64, channel *domain.IrcChannel) error
|
StoreChannel(networkID int64, channel *domain.IrcChannel) error
|
||||||
|
@ -61,7 +61,7 @@ func (h ircHandler) getNetworkByID(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
id, _ := strconv.Atoi(networkID)
|
id, _ := strconv.Atoi(networkID)
|
||||||
|
|
||||||
network, err := h.service.GetNetworkByID(int64(id))
|
network, err := h.service.GetNetworkByID(ctx, int64(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.encoder.Error(w, err)
|
h.encoder.Error(w, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type releaseService interface {
|
type releaseService interface {
|
||||||
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []domain.Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
||||||
Delete(ctx context.Context) error
|
Delete(ctx context.Context) error
|
||||||
|
@ -105,9 +105,9 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := struct {
|
ret := struct {
|
||||||
Data []domain.Release `json:"data"`
|
Data []*domain.Release `json:"data"`
|
||||||
NextCursor int64 `json:"next_cursor"`
|
NextCursor int64 `json:"next_cursor"`
|
||||||
Count int64 `json:"count"`
|
Count int64 `json:"count"`
|
||||||
}{
|
}{
|
||||||
Data: releases,
|
Data: releases,
|
||||||
NextCursor: nextCursor,
|
NextCursor: nextCursor,
|
||||||
|
|
|
@ -15,11 +15,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Store(indexer domain.Indexer) (*domain.Indexer, error)
|
Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error)
|
||||||
Update(indexer domain.Indexer) (*domain.Indexer, error)
|
Update(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error)
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error)
|
FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error)
|
||||||
List() ([]domain.Indexer, error)
|
List(ctx context.Context) ([]domain.Indexer, error)
|
||||||
GetAll() ([]*domain.IndexerDefinition, error)
|
GetAll() ([]*domain.IndexerDefinition, error)
|
||||||
GetTemplates() ([]domain.IndexerDefinition, error)
|
GetTemplates() ([]domain.IndexerDefinition, error)
|
||||||
LoadIndexerDefinitions() error
|
LoadIndexerDefinitions() error
|
||||||
|
@ -52,8 +52,8 @@ func NewService(config domain.Config, repo domain.IndexerRepo, apiService APISer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Store(indexer domain.Indexer) (*domain.Indexer, error) {
|
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
i, err := s.repo.Store(indexer)
|
i, err := s.repo.Store(ctx, indexer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name)
|
log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -69,8 +69,8 @@ func (s *service) Store(indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Update(indexer domain.Indexer) (*domain.Indexer, error) {
|
func (s *service) Update(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
i, err := s.repo.Update(indexer)
|
i, err := s.repo.Update(ctx, indexer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -97,25 +97,15 @@ func (s *service) Delete(ctx context.Context, id int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) {
|
func (s *service) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) {
|
||||||
filters, err := s.repo.FindByFilterID(ctx, id)
|
return s.repo.FindByFilterID(ctx, id)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) List() ([]domain.Indexer, error) {
|
func (s *service) List(ctx context.Context) ([]domain.Indexer, error) {
|
||||||
i, err := s.repo.List()
|
return s.repo.List(ctx)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return i, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetAll() ([]*domain.IndexerDefinition, error) {
|
func (s *service) GetAll() ([]*domain.IndexerDefinition, error) {
|
||||||
indexers, err := s.repo.List()
|
indexers, err := s.repo.List(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package irc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ type Service interface {
|
||||||
StopNetwork(key handlerKey) error
|
StopNetwork(key handlerKey) error
|
||||||
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
||||||
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
GetNetworkByID(ctx context.Context, id int64) (*domain.IrcNetwork, error)
|
||||||
DeleteNetwork(ctx context.Context, id int64) error
|
DeleteNetwork(ctx context.Context, id int64) error
|
||||||
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
|
@ -335,8 +336,8 @@ func (s *service) StopNetworkIfRunning(key handlerKey) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetNetworkByID(id int64) (*domain.IrcNetwork, error) {
|
func (s *service) GetNetworkByID(ctx context.Context, id int64) (*domain.IrcNetwork, error) {
|
||||||
network, err := s.repo.GetNetworkByID(id)
|
network, err := s.repo.GetNetworkByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("failed to get network: %v", id)
|
log.Error().Err(err).Msgf("failed to get network: %v", id)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -454,7 +455,7 @@ func (s *service) GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetwor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) DeleteNetwork(ctx context.Context, id int64) error {
|
func (s *service) DeleteNetwork(ctx context.Context, id int64) error {
|
||||||
network, err := s.GetNetworkByID(id)
|
network, err := s.GetNetworkByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -527,7 +528,9 @@ func (s *service) StoreNetwork(ctx context.Context, network *domain.IrcNetwork)
|
||||||
if network.Channels != nil {
|
if network.Channels != nil {
|
||||||
for _, channel := range network.Channels {
|
for _, channel := range network.Channels {
|
||||||
if err := s.repo.StoreChannel(network.ID, &channel); err != nil {
|
if err := s.repo.StoreChannel(network.ID, &channel); err != nil {
|
||||||
return err
|
log.Error().Stack().Err(err).Msg("irc.storeChannel: error executing query")
|
||||||
|
return errors.Wrap(err, "error storing channel on network")
|
||||||
|
//return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []domain.Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
||||||
Store(ctx context.Context, release *domain.Release) error
|
Store(ctx context.Context, release *domain.Release) error
|
||||||
|
@ -31,13 +31,8 @@ func NewService(repo domain.ReleaseRepo, actionService action.Service) Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Find(ctx context.Context, query domain.ReleaseQueryParams) (res []domain.Release, nextCursor int64, count int64, err error) {
|
func (s *service) Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error) {
|
||||||
res, nextCursor, count, err = s.repo.Find(ctx, query)
|
return s.repo.Find(ctx, query)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
func (s *service) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue