mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Add findFolder and findFolders queries to graphql schema (#5965)
* Add findFolder and findFolders queries to graphql schema * Add zip file criterion to file and folder queries
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
const folderTable = "folders"
|
||||
const folderIDColumn = "folder_id"
|
||||
|
||||
type folderRow struct {
|
||||
ID models.FolderID `db:"id" goqu:"skipinsert"`
|
||||
@@ -83,6 +84,25 @@ func (r folderQueryRows) resolve() []*models.Folder {
|
||||
return ret
|
||||
}
|
||||
|
||||
type folderRepositoryType struct {
|
||||
repository
|
||||
|
||||
galleries repository
|
||||
}
|
||||
|
||||
var (
|
||||
folderRepository = folderRepositoryType{
|
||||
repository: repository{
|
||||
tableName: folderTable,
|
||||
idColumn: idColumn,
|
||||
},
|
||||
galleries: repository{
|
||||
tableName: galleryTable,
|
||||
idColumn: folderIDColumn,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type FolderStore struct {
|
||||
repository
|
||||
|
||||
@@ -92,7 +112,7 @@ type FolderStore struct {
|
||||
func NewFolderStore() *FolderStore {
|
||||
return &FolderStore{
|
||||
repository: repository{
|
||||
tableName: sceneTable,
|
||||
tableName: folderTable,
|
||||
idColumn: idColumn,
|
||||
},
|
||||
|
||||
@@ -360,3 +380,162 @@ func (qb *FolderStore) FindByZipFileID(ctx context.Context, zipFileID models.Fil
|
||||
|
||||
return qb.getMany(ctx, q)
|
||||
}
|
||||
|
||||
func (qb *FolderStore) validateFilter(fileFilter *models.FolderFilterType) error {
|
||||
const and = "AND"
|
||||
const or = "OR"
|
||||
const not = "NOT"
|
||||
|
||||
if fileFilter.And != nil {
|
||||
if fileFilter.Or != nil {
|
||||
return illegalFilterCombination(and, or)
|
||||
}
|
||||
if fileFilter.Not != nil {
|
||||
return illegalFilterCombination(and, not)
|
||||
}
|
||||
|
||||
return qb.validateFilter(fileFilter.And)
|
||||
}
|
||||
|
||||
if fileFilter.Or != nil {
|
||||
if fileFilter.Not != nil {
|
||||
return illegalFilterCombination(or, not)
|
||||
}
|
||||
|
||||
return qb.validateFilter(fileFilter.Or)
|
||||
}
|
||||
|
||||
if fileFilter.Not != nil {
|
||||
return qb.validateFilter(fileFilter.Not)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *FolderStore) makeFilter(ctx context.Context, folderFilter *models.FolderFilterType) *filterBuilder {
|
||||
query := &filterBuilder{}
|
||||
|
||||
if folderFilter.And != nil {
|
||||
query.and(qb.makeFilter(ctx, folderFilter.And))
|
||||
}
|
||||
if folderFilter.Or != nil {
|
||||
query.or(qb.makeFilter(ctx, folderFilter.Or))
|
||||
}
|
||||
if folderFilter.Not != nil {
|
||||
query.not(qb.makeFilter(ctx, folderFilter.Not))
|
||||
}
|
||||
|
||||
filter := filterBuilderFromHandler(ctx, &folderFilterHandler{
|
||||
folderFilter: folderFilter,
|
||||
})
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
func (qb *FolderStore) Query(ctx context.Context, options models.FolderQueryOptions) (*models.FolderQueryResult, error) {
|
||||
folderFilter := options.FolderFilter
|
||||
findFilter := options.FindFilter
|
||||
|
||||
if folderFilter == nil {
|
||||
folderFilter = &models.FolderFilterType{}
|
||||
}
|
||||
if findFilter == nil {
|
||||
findFilter = &models.FindFilterType{}
|
||||
}
|
||||
|
||||
query := qb.newQuery()
|
||||
|
||||
distinctIDs(&query, folderTable)
|
||||
|
||||
if q := findFilter.Q; q != nil && *q != "" {
|
||||
searchColumns := []string{"folders.path"}
|
||||
query.parseQueryString(searchColumns, *q)
|
||||
}
|
||||
|
||||
if err := qb.validateFilter(folderFilter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter := qb.makeFilter(ctx, folderFilter)
|
||||
|
||||
if err := query.addFilter(filter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := qb.setQuerySort(&query, findFilter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.sortAndPagination += getPagination(findFilter)
|
||||
|
||||
result, err := qb.queryGroupedFields(ctx, options, query)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error querying aggregate fields: %w", err)
|
||||
}
|
||||
|
||||
idsResult, err := query.findIDs(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error finding IDs: %w", err)
|
||||
}
|
||||
|
||||
result.IDs = make([]models.FolderID, len(idsResult))
|
||||
for i, id := range idsResult {
|
||||
result.IDs[i] = models.FolderID(id)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (qb *FolderStore) queryGroupedFields(ctx context.Context, options models.FolderQueryOptions, query queryBuilder) (*models.FolderQueryResult, error) {
|
||||
if !options.Count {
|
||||
// nothing to do - return empty result
|
||||
return models.NewFolderQueryResult(qb), nil
|
||||
}
|
||||
|
||||
aggregateQuery := qb.newQuery()
|
||||
|
||||
if options.Count {
|
||||
aggregateQuery.addColumn("COUNT(DISTINCT temp.id) as total")
|
||||
}
|
||||
|
||||
const includeSortPagination = false
|
||||
aggregateQuery.from = fmt.Sprintf("(%s) as temp", query.toSQL(includeSortPagination))
|
||||
|
||||
out := struct {
|
||||
Total int
|
||||
Duration float64
|
||||
Megapixels float64
|
||||
Size int64
|
||||
}{}
|
||||
if err := qb.repository.queryStruct(ctx, aggregateQuery.toSQL(includeSortPagination), query.args, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := models.NewFolderQueryResult(qb)
|
||||
ret.Count = out.Total
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
var folderSortOptions = sortOptions{
|
||||
"created_at",
|
||||
"id",
|
||||
"path",
|
||||
"random",
|
||||
"updated_at",
|
||||
}
|
||||
|
||||
func (qb *FolderStore) setQuerySort(query *queryBuilder, findFilter *models.FindFilterType) error {
|
||||
if findFilter == nil || findFilter.Sort == nil || *findFilter.Sort == "" {
|
||||
return nil
|
||||
}
|
||||
sort := findFilter.GetSort("path")
|
||||
|
||||
// CVE-2024-32231 - ensure sort is in the list of allowed sorts
|
||||
if err := folderSortOptions.validateSort(sort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
direction := findFilter.GetDirection()
|
||||
query.sortAndPagination += getSort(sort, direction, "folders")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user