browse: Customizable default sort options (#6468)

* fileserver: add `sort` options

* fix: test

* fileserver: check options in `Provison`

* fileserver: more obvious err alerts in sort options
This commit is contained in:
lollipopkit🏳️‍⚧️ 2024-08-05 22:27:45 +08:00 committed by GitHub
parent 840094ac65
commit b198678174
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 103 additions and 4 deletions

View File

@ -0,0 +1,36 @@
:80
file_server browse {
sort size desc
}
----------
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"browse": {},
"handler": "file_server",
"hide": [
"./Caddyfile"
],
"sort": [
"size",
"desc"
]
}
]
}
]
}
}
}
}
}

View File

@ -206,11 +206,34 @@ func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs
// browseApplyQueryParams applies query parameters to the listing.
// It mutates the listing and may set cookies.
func (fsrv *FileServer) browseApplyQueryParams(w http.ResponseWriter, r *http.Request, listing *browseTemplateContext) {
var orderParam, sortParam string
// The configs in Caddyfile have lower priority than Query params,
// so put it at first.
for idx, item := range fsrv.SortOptions {
// Only `sort` & `order`, 2 params are allowed
if idx >= 2 {
break
}
switch item {
case sortByName, sortByNameDirFirst, sortBySize, sortByTime:
sortParam = item
case sortOrderAsc, sortOrderDesc:
orderParam = item
}
}
layoutParam := r.URL.Query().Get("layout")
sortParam := r.URL.Query().Get("sort")
orderParam := r.URL.Query().Get("order")
limitParam := r.URL.Query().Get("limit")
offsetParam := r.URL.Query().Get("offset")
sortParamTmp := r.URL.Query().Get("sort")
if sortParamTmp != "" {
sortParam = sortParamTmp
}
orderParamTmp := r.URL.Query().Get("order")
if orderParamTmp != "" {
orderParam = orderParamTmp
}
switch layoutParam {
case "list", "grid", "":
@ -233,11 +256,11 @@ func (fsrv *FileServer) browseApplyQueryParams(w http.ResponseWriter, r *http.Re
// then figure out the order
switch orderParam {
case "":
orderParam = "asc"
orderParam = sortOrderAsc
if orderCookie, orderErr := r.Cookie("order"); orderErr == nil {
orderParam = orderCookie.Value
}
case "asc", "desc":
case sortOrderAsc, sortOrderDesc:
http.SetCookie(w, &http.Cookie{Name: "order", Value: orderParam, Secure: r.TLS != nil})
}

View File

@ -373,4 +373,7 @@ const (
sortByNameDirFirst = "namedirfirst"
sortBySize = "size"
sortByTime = "time"
sortOrderAsc = "asc"
sortOrderDesc = "desc"
)

View File

@ -171,6 +171,17 @@ func (fsrv *FileServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
fsrv.EtagFileExtensions = etagFileExtensions
case "sort":
for d.NextArg() {
dVal := d.Val()
switch dVal {
case sortByName, sortBySize, sortByTime, sortOrderAsc, sortOrderDesc:
fsrv.SortOptions = append(fsrv.SortOptions, dVal)
default:
return d.Errf("unknown sort option '%s'", dVal)
}
}
default:
return d.Errf("unknown subdirective '%s'", d.Val())
}

View File

@ -153,6 +153,16 @@ type FileServer struct {
// a 404 error. By default, this is false (disabled).
PassThru bool `json:"pass_thru,omitempty"`
// Override the default sort.
// It includes the following options:
// - sort_by: name(default), namedirfirst, size, time
// - order: asc(default), desc
// eg.:
// - `sort time desc` will sort by time in descending order
// - `sort size` will sort by size in ascending order
// The first option must be `sort_by` and the second option must be `order` (if exists).
SortOptions []string `json:"sort,omitempty"`
// Selection of encoders to use to check for precompressed files.
PrecompressedRaw caddy.ModuleMap `json:"precompressed,omitempty" caddy:"namespace=http.precompressed"`
@ -236,6 +246,22 @@ func (fsrv *FileServer) Provision(ctx caddy.Context) error {
fsrv.precompressors[ae] = p
}
// check sort options
for idx, sortOption := range fsrv.SortOptions {
switch idx {
case 0:
if sortOption != sortByName && sortOption != sortByNameDirFirst && sortOption != sortBySize && sortOption != sortByTime {
return fmt.Errorf("the first option must be one of the following: %s, %s, %s, %s, but got %s", sortByName, sortByNameDirFirst, sortBySize, sortByTime, sortOption)
}
case 1:
if sortOption != sortOrderAsc && sortOption != sortOrderDesc {
return fmt.Errorf("the second option must be one of the following: %s, %s, but got %s", sortOrderAsc, sortOrderDesc, sortOption)
}
default:
return fmt.Errorf("only max 2 sort options are allowed, but got %d", idx+1)
}
}
return nil
}