mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-21 09:55:45 +03:00
browse: Move predicate 'limit' to ServeListing
This keeps the interface of all available formatters honest, and allows for truncated listings all formats.
This commit is contained in:
parent
6908136092
commit
1d38d113f8
2 changed files with 49 additions and 50 deletions
|
@ -309,6 +309,9 @@ footer {
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<span class="meta-item"><b>{{.NumDirs}}</b> director{{if eq 1 .NumDirs}}y{{else}}ies{{end}}</span>
|
<span class="meta-item"><b>{{.NumDirs}}</b> director{{if eq 1 .NumDirs}}y{{else}}ies{{end}}</span>
|
||||||
<span class="meta-item"><b>{{.NumFiles}}</b> file{{if ne 1 .NumFiles}}s{{end}}</span>
|
<span class="meta-item"><b>{{.NumFiles}}</b> file{{if ne 1 .NumFiles}}s{{end}}</span>
|
||||||
|
{{- if ne 0 .ItemsLimitedTo}}
|
||||||
|
<span class="meta-item">(of which only <b>{{.ItemsLimitedTo}}</b> are displayed)</span>
|
||||||
|
{{- end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="listing">
|
<div class="listing">
|
||||||
|
@ -316,29 +319,29 @@ footer {
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
{{if and (eq .Sort "name") (ne .Order "desc")}}
|
{{if and (eq .Sort "name") (ne .Order "desc")}}
|
||||||
<a href="?sort=name&order=desc">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a>
|
<a href="?sort=name&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a>
|
||||||
{{else if and (eq .Sort "name") (ne .Order "asc")}}
|
{{else if and (eq .Sort "name") (ne .Order "asc")}}
|
||||||
<a href="?sort=name&order=asc">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a>
|
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="?sort=name&order=asc">Name</a>
|
<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
{{if and (eq .Sort "size") (ne .Order "desc")}}
|
{{if and (eq .Sort "size") (ne .Order "desc")}}
|
||||||
<a href="?sort=size&order=desc">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a>
|
<a href="?sort=size&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a>
|
||||||
{{else if and (eq .Sort "size") (ne .Order "asc")}}
|
{{else if and (eq .Sort "size") (ne .Order "asc")}}
|
||||||
<a href="?sort=size&order=asc">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a>
|
<a href="?sort=size&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="?sort=size&order=asc">Size</a>
|
<a href="?sort=size&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</th>
|
</th>
|
||||||
<th class="hideable">
|
<th class="hideable">
|
||||||
{{if and (eq .Sort "time") (ne .Order "desc")}}
|
{{if and (eq .Sort "time") (ne .Order "desc")}}
|
||||||
<a href="?sort=time&order=desc">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a>
|
<a href="?sort=time&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a>
|
||||||
{{else if and (eq .Sort "time") (ne .Order "asc")}}
|
{{else if and (eq .Sort "time") (ne .Order "asc")}}
|
||||||
<a href="?sort=time&order=asc">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a>
|
<a href="?sort=time&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="?sort=time&order=asc">Modified</a>
|
<a href="?sort=time&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -62,6 +62,9 @@ type Listing struct {
|
||||||
// And which order
|
// And which order
|
||||||
Order string
|
Order string
|
||||||
|
|
||||||
|
// If ≠0 then Items have been limited to that many elements
|
||||||
|
ItemsLimitedTo int
|
||||||
|
|
||||||
// Optional custom variables for use in browse templates
|
// Optional custom variables for use in browse templates
|
||||||
User interface{}
|
User interface{}
|
||||||
|
|
||||||
|
@ -298,32 +301,42 @@ func (b Browse) loadDirectoryContents(requestedFilepath, urlPath string) (*Listi
|
||||||
return &listing, hasIndex, nil
|
return &listing, hasIndex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleSortOrder gets and stores for a Listing the 'sort' and 'order'.
|
// handleSortOrder gets and stores for a Listing the 'sort' and 'order',
|
||||||
|
// and reads 'limit' if given. The latter is 0 if not given.
|
||||||
//
|
//
|
||||||
// This sets Cookies.
|
// This sets Cookies.
|
||||||
func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (string, string) {
|
func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort string, order string, limit int, err error) {
|
||||||
sort, order := r.URL.Query().Get("sort"), r.URL.Query().Get("order")
|
sort, order, limitQuery := r.URL.Query().Get("sort"), r.URL.Query().Get("order"), r.URL.Query().Get("limit")
|
||||||
|
|
||||||
// If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies
|
// If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies
|
||||||
if sort == "" {
|
switch sort {
|
||||||
|
case "":
|
||||||
sort = "name"
|
sort = "name"
|
||||||
if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil {
|
if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil {
|
||||||
sort = sortCookie.Value
|
sort = sortCookie.Value
|
||||||
}
|
}
|
||||||
} else {
|
case "name", "size", "type":
|
||||||
http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil})
|
http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
if order == "" {
|
switch order {
|
||||||
|
case "":
|
||||||
order = "asc"
|
order = "asc"
|
||||||
if orderCookie, orderErr := r.Cookie("order"); orderErr == nil {
|
if orderCookie, orderErr := r.Cookie("order"); orderErr == nil {
|
||||||
order = orderCookie.Value
|
order = orderCookie.Value
|
||||||
}
|
}
|
||||||
} else {
|
case "asc", "desc":
|
||||||
http.SetCookie(w, &http.Cookie{Name: "order", Value: order, Path: scope, Secure: r.TLS != nil})
|
http.SetCookie(w, &http.Cookie{Name: "order", Value: order, Path: scope, Secure: r.TLS != nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
return sort, order
|
if limitQuery != "" {
|
||||||
|
limit, err = strconv.Atoi(limitQuery)
|
||||||
|
if err != nil { // if the 'limit' query can't be interpreted as a number, return err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeListing returns a formatted view of 'requestedFilepath' contents'.
|
// ServeListing returns a formatted view of 'requestedFilepath' contents'.
|
||||||
|
@ -350,23 +363,24 @@ func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFi
|
||||||
listing.User = bc.Variables
|
listing.User = bc.Variables
|
||||||
|
|
||||||
// Copy the query values into the Listing struct
|
// Copy the query values into the Listing struct
|
||||||
listing.Sort, listing.Order = b.handleSortOrder(w, r, bc.PathScope)
|
var limit int
|
||||||
|
listing.Sort, listing.Order, limit, err = b.handleSortOrder(w, r, bc.PathScope)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusBadRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
listing.applySort()
|
listing.applySort()
|
||||||
|
|
||||||
|
if limit > 0 && limit <= len(listing.Items) {
|
||||||
|
listing.Items = listing.Items[:limit]
|
||||||
|
listing.ItemsLimitedTo = limit
|
||||||
|
}
|
||||||
|
|
||||||
var buf *bytes.Buffer
|
var buf *bytes.Buffer
|
||||||
acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ","))
|
acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ","))
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(acceptHeader, "application/json"):
|
case strings.Contains(acceptHeader, "application/json"):
|
||||||
var limit int
|
if buf, err = b.formatAsJSON(listing, bc); err != nil {
|
||||||
if limitQuery := r.URL.Query().Get("limit"); limitQuery != "" {
|
|
||||||
limit, err = strconv.Atoi(limitQuery)
|
|
||||||
if err != nil { // if the 'limit' query can't be interpreted as a number, return err
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf, err = b.formatAsJSON(listing, bc, limit); err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
@ -384,32 +398,14 @@ func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFi
|
||||||
return http.StatusOK, nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Browse) formatAsJSON(listing *Listing, bc *Config, limit int) (*bytes.Buffer, error) {
|
func (b Browse) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, error) {
|
||||||
|
marsh, err := json.Marshal(listing.Items)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
var marsh []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Check if we are limited
|
|
||||||
if limit > 0 {
|
|
||||||
// if `limit` is equal or less than len(listing.Items) and bigger than 0, list them
|
|
||||||
if limit <= len(listing.Items) {
|
|
||||||
marsh, err = json.Marshal(listing.Items[:limit])
|
|
||||||
} else { // if the 'limit' query is empty, or has the wrong value, list everything
|
|
||||||
marsh, err = json.Marshal(listing.Items)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else { // There's no 'limit' query; list them all
|
|
||||||
marsh, err = json.Marshal(listing.Items)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the marshaled json to buf
|
|
||||||
_, err = buf.Write(marsh)
|
_, err = buf.Write(marsh)
|
||||||
|
|
||||||
return buf, err
|
return buf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue