feat: add sorting to user itself
License: MIT Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
parent
1e163bce84
commit
9adb60206c
2
frontend
2
frontend
@ -1 +1 @@
|
||||
Subproject commit 82abdaf3900aae349f172cc1f5494fa5b6e72a02
|
||||
Subproject commit 9977299d4e3dd201cd3bf648fb70b03e09d6e4e3
|
||||
@ -83,6 +83,7 @@ type userInfo struct {
|
||||
Locale string `json:"locale"`
|
||||
ViewMode types.ViewMode `json:"viewMode"`
|
||||
Perm types.Permissions `json:"perm"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
}
|
||||
|
||||
type authToken struct {
|
||||
@ -140,6 +141,7 @@ func (e *Env) printToken(w http.ResponseWriter, r *http.Request, user *types.Use
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
},
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(),
|
||||
|
||||
@ -16,6 +16,11 @@ const (
|
||||
keyUserID key = iota
|
||||
)
|
||||
|
||||
type modifyRequest struct {
|
||||
What string `json:"what"` // Answer to: what data type?
|
||||
Which []string `json:"which"` // Answer to: which fields?
|
||||
}
|
||||
|
||||
// Env ...
|
||||
type Env struct {
|
||||
Auther types.Auther
|
||||
|
||||
@ -62,15 +62,7 @@ func (e *Env) resourceGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if file.IsDir {
|
||||
scope := "/"
|
||||
|
||||
if sort, order, err := handleSortOrder(w, r, scope); err == nil {
|
||||
file.Listing.Sort = sort
|
||||
file.Listing.Order = order
|
||||
} else {
|
||||
httpErr(w, r, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
file.Listing.Sorting = user.Sorting
|
||||
file.Listing.ApplySort()
|
||||
renderJSON(w, r, file)
|
||||
return
|
||||
@ -240,42 +232,3 @@ func (e *Env) resourcePatchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
httpErr(w, r, httpFsErr(err), err)
|
||||
}
|
||||
|
||||
func handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort string, order string, err error) {
|
||||
sort = r.URL.Query().Get("sort")
|
||||
order = r.URL.Query().Get("order")
|
||||
|
||||
switch sort {
|
||||
case "":
|
||||
sort = "name"
|
||||
if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil {
|
||||
sort = sortCookie.Value
|
||||
}
|
||||
case "name", "size":
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "sort",
|
||||
Value: sort,
|
||||
MaxAge: 31536000,
|
||||
Path: scope,
|
||||
Secure: r.TLS != nil,
|
||||
})
|
||||
}
|
||||
|
||||
switch order {
|
||||
case "":
|
||||
order = "asc"
|
||||
if orderCookie, orderErr := r.Cookie("order"); orderErr == nil {
|
||||
order = orderCookie.Value
|
||||
}
|
||||
case "asc", "desc":
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "order",
|
||||
Value: order,
|
||||
MaxAge: 31536000,
|
||||
Path: scope,
|
||||
Secure: r.TLS != nil,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/filebrowser/filebrowser/types"
|
||||
"github.com/gorilla/mux"
|
||||
@ -18,6 +20,32 @@ func getUserID(r *http.Request) (uint, error) {
|
||||
return uint(i), err
|
||||
}
|
||||
|
||||
type modifyUserRequest struct {
|
||||
modifyRequest
|
||||
Data *types.User `json:"data"`
|
||||
}
|
||||
|
||||
func getUser(w http.ResponseWriter, r *http.Request) (*modifyUserRequest, bool) {
|
||||
if r.Body == nil {
|
||||
httpErr(w, r, http.StatusBadRequest, nil)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
req := &modifyUserRequest{}
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
if err != nil {
|
||||
httpErr(w, r, http.StatusBadRequest, err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if req.What != "user" {
|
||||
httpErr(w, r, http.StatusBadRequest, nil)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return req, true
|
||||
}
|
||||
|
||||
func (e *Env) usersGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := e.getUser(w, r)
|
||||
if !ok {
|
||||
@ -109,5 +137,69 @@ func (e *Env) userPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (e *Env) userPutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: fill me
|
||||
sessionUser, modifiedID, ok := e.userSelfOrAdmin(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
req, ok := getUser(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if req.Data.ID != modifiedID {
|
||||
httpErr(w, r, http.StatusBadRequest, nil)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if len(req.Which) == 1 && req.Which[0] == "all" {
|
||||
if !sessionUser.Perm.Admin {
|
||||
httpErr(w, r, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Data.Password != "" {
|
||||
req.Data.Password, err = types.HashPwd(req.Data.Password)
|
||||
} else {
|
||||
var suser *types.User
|
||||
suser, err = e.Store.Users.Get(modifiedID)
|
||||
req.Data.Password = suser.Password
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
httpErr(w, r, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
req.Which = []string{}
|
||||
}
|
||||
|
||||
for k, v := range req.Which {
|
||||
if v == "password" {
|
||||
if !sessionUser.Perm.Admin && sessionUser.LockPassword {
|
||||
httpErr(w, r, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Password, err = types.HashPwd(req.Data.Password)
|
||||
if err != nil {
|
||||
httpErr(w, r, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !sessionUser.Perm.Admin && (v == "scope" || v == "perm" || v == "username") {
|
||||
httpErr(w, r, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
|
||||
req.Which[k] = strings.Title(v)
|
||||
}
|
||||
|
||||
err = e.Store.Users.Update(req.Data, req.Which...)
|
||||
if err != nil {
|
||||
httpErr(w, r, http.StatusInternalServerError, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,15 +11,14 @@ type Listing struct {
|
||||
Items []*File `json:"items"`
|
||||
NumDirs int `json:"numDirs"`
|
||||
NumFiles int `json:"numFiles"`
|
||||
Sort string `json:"sort"`
|
||||
Order string `json:"order"`
|
||||
Sorting Sorting `json:"sorting"`
|
||||
}
|
||||
|
||||
// ApplySort applies the sort order using .Order and .Sort
|
||||
func (l Listing) ApplySort() {
|
||||
// Check '.Order' to know how to sort
|
||||
if l.Order == "desc" {
|
||||
switch l.Sort {
|
||||
if !l.Sorting.Asc {
|
||||
switch l.Sorting.By {
|
||||
case "name":
|
||||
sort.Sort(sort.Reverse(byName(l)))
|
||||
case "size":
|
||||
@ -31,7 +30,7 @@ func (l Listing) ApplySort() {
|
||||
return
|
||||
}
|
||||
} else { // If we had more Orderings we could add them here
|
||||
switch l.Sort {
|
||||
switch l.Sorting.By {
|
||||
case "name":
|
||||
sort.Sort(byName(l))
|
||||
case "size":
|
||||
|
||||
@ -2,14 +2,15 @@ package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Rule is a allow/disallow rule.
|
||||
type Rule struct {
|
||||
Regex bool
|
||||
Allow bool
|
||||
Path string
|
||||
Regexp *Regexp
|
||||
Regex bool `json:"regex"`
|
||||
Allow bool `json:"allow"`
|
||||
Path string `json:"path"`
|
||||
Regexp *Regexp `json:"regexp"`
|
||||
}
|
||||
|
||||
// Regexp is a wrapper to the native regexp type where we
|
||||
@ -27,3 +28,17 @@ func (r *Regexp) MatchString(s string) bool {
|
||||
|
||||
return r.regexp.MatchString(s)
|
||||
}
|
||||
|
||||
func isAllowed(path string, rules []Rule) bool {
|
||||
for _, rule := range rules {
|
||||
if rule.Regex {
|
||||
if rule.Regexp.MatchString(path) {
|
||||
return rule.Allow
|
||||
}
|
||||
} else if strings.HasPrefix(path, rule.Path) {
|
||||
return rule.Allow
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -10,7 +10,19 @@ type Settings struct {
|
||||
Signup bool `json:"signup"`
|
||||
Defaults UserDefaults `json:"defaults"`
|
||||
AuthMethod AuthMethod `json:"authMethod"`
|
||||
Branding Branding `json:"Branding"`
|
||||
Branding Branding `json:"branding"`
|
||||
Rules []Rule `json:"rules"` // TODO: use this add to cli
|
||||
}
|
||||
|
||||
// IsAllowed matches the rules against the url.
|
||||
func (e Settings) IsAllowed(url string) bool {
|
||||
return isAllowed(url, e.Rules)
|
||||
}
|
||||
|
||||
// Sorting contains a sorting order.
|
||||
type Sorting struct {
|
||||
By string `json:"by"`
|
||||
Asc bool `json:"asc"`
|
||||
}
|
||||
|
||||
// Branding contains the branding settings of the app.
|
||||
@ -26,5 +38,6 @@ type UserDefaults struct {
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
Sorting Sorting `json:"sorting"` // TODO: add to cli
|
||||
Perm Permissions `json:"perm"`
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
@ -35,8 +33,10 @@ type User struct {
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"` // TODO: add to cli
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Sorting Sorting `json:"sorting"` // TODO: add to cli
|
||||
Fs afero.Fs `json:"-"`
|
||||
Rules []Rule `json:"rules"`
|
||||
}
|
||||
@ -51,24 +51,7 @@ func (u *User) BuildFs() {
|
||||
|
||||
// IsAllowed checks if an user is allowed to go to a certain path.
|
||||
func (u User) IsAllowed(url string) bool {
|
||||
var rule *Rule
|
||||
i := len(u.Rules) - 1
|
||||
|
||||
for i >= 0 {
|
||||
rule = &u.Rules[i]
|
||||
|
||||
if rule.Regex {
|
||||
if rule.Regexp.MatchString(url) {
|
||||
return rule.Allow
|
||||
}
|
||||
} else if strings.HasPrefix(url, rule.Path) {
|
||||
return rule.Allow
|
||||
}
|
||||
|
||||
i--
|
||||
}
|
||||
|
||||
return true
|
||||
return isAllowed(url, u.Rules)
|
||||
}
|
||||
|
||||
// HashPwd hashes a password.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user