Commit 1d38d113 authored by W-Mark Kubacki's avatar W-Mark Kubacki

browse: Move predicate 'limit' to ServeListing

This keeps the interface of all available formatters honest,
and allows for truncated listings all formats.
parent 69081360
...@@ -309,6 +309,9 @@ footer { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) {
buf := new(bytes.Buffer) marsh, err := json.Marshal(listing.Items)
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 { if err != nil {
return nil, err return nil, err
} }
}
// Write the marshaled json to buf buf := new(bytes.Buffer)
_, err = buf.Write(marsh) _, err = buf.Write(marsh)
return buf, err return buf, err
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment