feat(web): releases list filtering (#136)

This commit is contained in:
Ludvig Lundgren 2022-02-19 20:00:48 +01:00 committed by GitHub
parent 279d4ff7a3
commit 246e3ddc26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 459 additions and 48 deletions

View file

@ -84,14 +84,14 @@ func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain
return nil
}
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([]domain.Release, int64, int64, error) {
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryParams) ([]domain.Release, int64, int64, error) {
//r.db.lock.RLock()
//defer r.db.lock.RUnlock()
queryBuilder := sq.
Select("id", "filter_status", "rejections", "indexer", "filter", "protocol", "title", "torrent_name", "size", "timestamp", "COUNT() OVER() AS total_count").
From("release").
OrderBy("timestamp DESC")
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").
OrderBy("r.timestamp DESC")
if params.Limit > 0 {
queryBuilder = queryBuilder.Limit(params.Limit)
@ -104,18 +104,22 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([
}
if params.Cursor > 0 {
queryBuilder = queryBuilder.Where(sq.Lt{"id": params.Cursor})
queryBuilder = queryBuilder.Where(sq.Lt{"r.id": params.Cursor})
}
if params.Filter != nil {
if params.Filters.Indexers != nil {
filter := sq.And{}
for k, v := range params.Filter {
filter = append(filter, sq.Eq{k: v})
for _, v := range params.Filters.Indexers {
filter = append(filter, sq.Eq{"r.indexer": v})
}
queryBuilder = queryBuilder.Where(filter)
}
if params.Filters.PushStatus != "" {
queryBuilder = queryBuilder.InnerJoin("release_action_status ras ON r.id = ras.release_id").Where(sq.Eq{"ras.status": params.Filters.PushStatus})
}
query, args, err := queryBuilder.ToSql()
log.Trace().Str("database", "release.find").Msgf("query: '%v', args: '%v'", query, args)
@ -171,6 +175,46 @@ func (repo *ReleaseRepo) Find(ctx context.Context, params domain.QueryParams) ([
return res, nextCursor, countItems, nil
}
func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error) {
//r.db.lock.RLock()
//defer r.db.lock.RUnlock()
query := `
SELECT DISTINCT indexer FROM "release"
UNION
SELECT DISTINCT identifier indexer FROM indexer;`
log.Trace().Str("database", "release.get_indexers").Msgf("query: '%v'", query)
res := make([]string, 0)
rows, err := repo.db.handler.QueryContext(ctx, query)
if err != nil {
log.Error().Stack().Err(err).Msg("error fetching indexer list")
return res, err
}
defer rows.Close()
if err := rows.Err(); err != nil {
log.Error().Stack().Err(err)
return res, err
}
for rows.Next() {
var indexer string
if err := rows.Scan(&indexer); err != nil {
log.Error().Stack().Err(err).Msg("release.find: error scanning data to struct")
return res, err
}
res = append(res, indexer)
}
return res, nil
}
func (repo *ReleaseRepo) GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]domain.ReleaseActionStatus, error) {
//r.db.lock.RLock()
//defer r.db.lock.RUnlock()

View file

@ -26,7 +26,8 @@ import (
type ReleaseRepo interface {
Store(ctx context.Context, release *Release) (*Release, error)
Find(ctx context.Context, params QueryParams) (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)
GetActionStatusByReleaseID(ctx context.Context, releaseID int64) ([]ReleaseActionStatus, error)
Stats(ctx context.Context) (*ReleaseStats, error)
StoreReleaseActionStatus(ctx context.Context, actionStatus *ReleaseActionStatus) error
@ -1485,11 +1486,14 @@ const (
ReleaseImplementationIRC ReleaseImplementation = "IRC"
)
type QueryParams struct {
Limit uint64
Offset uint64
Cursor uint64
Sort map[string]string
Filter map[string]string
type ReleaseQueryParams struct {
Limit uint64
Offset uint64
Cursor uint64
Sort map[string]string
Filters struct {
Indexers []string
PushStatus string
}
Search string
}

View file

@ -3,6 +3,7 @@ package http
import (
"context"
"net/http"
"net/url"
"strconv"
"github.com/autobrr/autobrr/internal/domain"
@ -10,7 +11,8 @@ import (
)
type releaseService interface {
Find(ctx context.Context, query domain.QueryParams) (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)
Stats(ctx context.Context) (*domain.ReleaseStats, error)
}
@ -29,6 +31,7 @@ func newReleaseHandler(encoder encoder, service releaseService) *releaseHandler
func (h releaseHandler) Routes(r chi.Router) {
r.Get("/", h.findReleases)
r.Get("/stats", h.getStats)
r.Get("/indexers", h.getIndexerOptions)
}
func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
@ -40,6 +43,7 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
"code": "BAD_REQUEST_PARAMS",
"message": "limit parameter is invalid",
}, http.StatusBadRequest)
return
}
if limit == 0 {
limit = 20
@ -52,23 +56,44 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
"code": "BAD_REQUEST_PARAMS",
"message": "offset parameter is invalid",
}, http.StatusBadRequest)
return
}
cursorP := r.URL.Query().Get("cursor")
cursor, err := strconv.Atoi(cursorP)
if err != nil && cursorP != "" {
h.encoder.StatusResponse(r.Context(), w, map[string]interface{}{
"code": "BAD_REQUEST_PARAMS",
"message": "cursor parameter is invalid",
}, http.StatusBadRequest)
cursor := 0
if cursorP != "" {
cursor, err = strconv.Atoi(cursorP)
if err != nil && cursorP != "" {
h.encoder.StatusResponse(r.Context(), w, map[string]interface{}{
"code": "BAD_REQUEST_PARAMS",
"message": "cursor parameter is invalid",
}, http.StatusBadRequest)
}
return
}
query := domain.QueryParams{
u, err := url.Parse(r.URL.String())
if err != nil {
h.encoder.StatusResponse(r.Context(), w, map[string]interface{}{
"code": "BAD_REQUEST_PARAMS",
"message": "indexer parameter is invalid",
}, http.StatusBadRequest)
return
}
vals := u.Query()
indexer := vals["indexer"]
pushStatus := r.URL.Query().Get("push_status")
query := domain.ReleaseQueryParams{
Limit: uint64(limit),
Offset: uint64(offset),
Cursor: uint64(cursor),
Sort: nil,
//Filter: "",
Filters: struct {
Indexers []string
PushStatus string
}{Indexers: indexer, PushStatus: pushStatus},
}
releases, nextCursor, count, err := h.service.Find(r.Context(), query)
@ -90,6 +115,16 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
h.encoder.StatusResponse(r.Context(), w, ret, http.StatusOK)
}
func (h releaseHandler) getIndexerOptions(w http.ResponseWriter, r *http.Request) {
stats, err := h.service.GetIndexerOptions(r.Context())
if err != nil {
h.encoder.StatusNotFound(r.Context(), w)
return
}
h.encoder.StatusResponse(r.Context(), w, stats, http.StatusOK)
}
func (h releaseHandler) getStats(w http.ResponseWriter, r *http.Request) {
stats, err := h.service.Stats(r.Context())

View file

@ -10,7 +10,8 @@ import (
)
type Service interface {
Find(ctx context.Context, query domain.QueryParams) (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)
Stats(ctx context.Context) (*domain.ReleaseStats, error)
Store(ctx context.Context, release *domain.Release) error
StoreReleaseActionStatus(ctx context.Context, actionStatus *domain.ReleaseActionStatus) error
@ -29,7 +30,7 @@ func NewService(repo domain.ReleaseRepo, actionService action.Service) Service {
}
}
func (s *service) Find(ctx context.Context, query domain.QueryParams) (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)
if err != nil {
return
@ -38,6 +39,10 @@ func (s *service) Find(ctx context.Context, query domain.QueryParams) (res []dom
return
}
func (s *service) GetIndexerOptions(ctx context.Context) ([]string, error) {
return s.repo.GetIndexerOptions(ctx)
}
func (s *service) Stats(ctx context.Context) (*domain.ReleaseStats, error) {
stats, err := s.repo.Stats(ctx)
if err != nil {