add a query arg to the List endpoint used to determine what page a child item is on

This commit is contained in:
Cyberes 2024-03-23 17:38:28 -06:00
parent 933670c63a
commit 6a5526ba3e
1 changed files with 84 additions and 44 deletions

View File

@ -2,6 +2,7 @@ package file
import (
"crazyfs/api/helpers"
"crazyfs/cacheitem"
"crazyfs/config"
"crazyfs/file"
"crazyfs/responseitem"
@ -10,6 +11,11 @@ import (
"strconv"
)
const (
sortFolders = "folders"
sortDefault = sortFolders
)
func APIList(w http.ResponseWriter, r *http.Request) {
if helpers.CheckInitialCrawl() {
helpers.HandleRejectDuringInitialCrawl(w)
@ -25,11 +31,11 @@ func APIList(w http.ResponseWriter, r *http.Request) {
var err error
sortArg := r.URL.Query().Get("sort")
var folderSorting string
if sortArg == "default" || sortArg == "" {
folderSorting = "default"
} else if sortArg == "folders" {
folderSorting = "folders"
var sortType string
if sortArg == sortDefault || sortArg == "" {
sortType = sortDefault
} else if sortArg == sortFolders {
sortType = sortFolders
} else {
helpers.Return400Msg("folders arg must be 'default' (to not do any sorting) or 'first' (to sort the folders to the front of the list)", w)
return
@ -80,11 +86,6 @@ func APIList(w http.ResponseWriter, r *http.Request) {
}
}
// Create a copy of the cached Item, so we don't modify the Item in the cache
item := responseitem.NewResponseItem(cacheItem)
response := map[string]interface{}{}
// Pagination
var paginationLimit int
if r.URL.Query().Get("limit") != "" {
@ -102,17 +103,58 @@ func APIList(w http.ResponseWriter, r *http.Request) {
paginationLimit = 100
}
// Generate the listing.
pageParam := r.URL.Query().Get("page")
response := map[string]interface{}{}
item, pages, responseError := generateListing(cacheItem, paginationLimit, sortType, pageParam)
if responseError != "" {
helpers.Return400Msg(responseError, w)
return
}
resolveItemName := r.URL.Query().Get("resolve")
if resolveItemName != "" {
var resolvedChild *responseitem.ResponseItem
var resolvedChildPage int
for i := range pages {
for _, child := range pages[i] {
if child.Name == resolveItemName {
resolvedChild = child
resolvedChildPage = i
break
}
}
if resolvedChild != nil {
break
}
}
if resolvedChild == nil {
helpers.Return400Msg("failed to find item", w)
return
}
item.Children = make([]*responseitem.ResponseItem, 1)
item.Children[0] = resolvedChild
response["resolved_page"] = resolvedChildPage
}
if r.URL.Query().Get("page") != "" || resolveItemName != "" {
response["total_pages"] = len(pages) + 1 // We add 1 to the count because arrays are zero-indexed.
}
response["item"] = item
helpers.WriteJsonResponse(response, true, w, r)
}
func generateListing(cacheItem *cacheitem.Item, paginationLimit int, sortType string, pageParam string) (*responseitem.ResponseItem, [][]*responseitem.ResponseItem, string) {
if sortType == "" {
panic("sortType was an empty string")
}
item := responseitem.NewResponseItem(cacheItem)
totalItems := len(item.Children)
totalPages := totalItems / paginationLimit
if totalItems%paginationLimit != 0 {
totalPages++
}
if r.URL.Query().Get("page") != "" {
response["total_pages"] = totalPages
}
if folderSorting == "folders" {
if sortType == sortFolders {
var dirs, files []*responseitem.ResponseItem
for _, child := range item.Children {
if child.IsDir {
@ -121,45 +163,43 @@ func APIList(w http.ResponseWriter, r *http.Request) {
files = append(files, child)
}
}
item.Children = make([]*responseitem.ResponseItem, len(item.Children))
item.Children = append(dirs, files...)
}
// Set the children to an empty array so that the JSON encoder doesn't return it as nil.
var paginatedChildren []*responseitem.ResponseItem // this var will be either the full cacheitem list or a paginated list depending on the query args
if item.Children != nil {
paginatedChildren = item.Children
} else {
paginatedChildren = make([]*responseitem.ResponseItem, 0)
}
var pages [][]*responseitem.ResponseItem
pageParam := r.URL.Query().Get("page")
var page int
if pageParam != "" {
page, err := strconv.Atoi(pageParam)
if err != nil || page < 1 || page > totalPages {
// Don't return an error, just truncate things
page = totalPages
pageInt, err := strconv.Atoi(pageParam)
if err != nil || pageInt < 1 {
return nil, nil, "invalid page number"
}
start := (page - 1) * paginationLimit
end := start + paginationLimit
if start >= 0 { // avoid segfaults
if start > len(item.Children) {
start = len(item.Children)
}
if end > len(item.Children) {
end = len(item.Children)
}
paginatedChildren = paginatedChildren[start:end]
if pageInt > totalPages {
// Don't return an error, just set it to the max page number.
pageInt = totalPages
}
pageInt--
page = pageInt
} else {
page = 0
}
for i := 0; i < len(item.Children); i += paginationLimit {
end := i + paginationLimit
if end > len(item.Children) {
end = len(item.Children)
}
pages = append(pages, item.Children[i:end])
}
paginatedChildren := pages[page]
// Erase the children of the children so we aren't displaying things recursively.
for i := range paginatedChildren {
paginatedChildren[i].Children = nil
}
item.Children = paginatedChildren
response["item"] = item
helpers.WriteJsonResponse(response, true, w, r)
return item, pages, ""
}