feat: settings working once more
License: MIT Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
parent
d3454d9641
commit
bf054c6379
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/auth"
|
"github.com/filebrowser/filebrowser/auth"
|
||||||
@ -99,6 +100,7 @@ func printSettings(s *types.Settings, auther types.Auther) {
|
|||||||
fmt.Fprintf(w, "\tScope:\t%s\n", s.Defaults.Scope)
|
fmt.Fprintf(w, "\tScope:\t%s\n", s.Defaults.Scope)
|
||||||
fmt.Fprintf(w, "\tLocale:\t%s\n", s.Defaults.Locale)
|
fmt.Fprintf(w, "\tLocale:\t%s\n", s.Defaults.Locale)
|
||||||
fmt.Fprintf(w, "\tView mode:\t%s\n", s.Defaults.ViewMode)
|
fmt.Fprintf(w, "\tView mode:\t%s\n", s.Defaults.ViewMode)
|
||||||
|
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(s.Defaults.Commands, " "))
|
||||||
fmt.Fprintf(w, "\tSorting:\n")
|
fmt.Fprintf(w, "\tSorting:\n")
|
||||||
fmt.Fprintf(w, "\t\tBy:\t%s\n", s.Defaults.Sorting.By)
|
fmt.Fprintf(w, "\t\tBy:\t%s\n", s.Defaults.Sorting.By)
|
||||||
fmt.Fprintf(w, "\t\tAsc:\t%t\n", s.Defaults.Sorting.Asc)
|
fmt.Fprintf(w, "\t\tAsc:\t%t\n", s.Defaults.Sorting.Asc)
|
||||||
|
|||||||
@ -66,7 +66,6 @@ func usernameOrIDRequired(cmd *cobra.Command, args []string) error {
|
|||||||
func addUserFlags(cmd *cobra.Command) {
|
func addUserFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().Bool("perm.admin", false, "admin perm for users")
|
cmd.Flags().Bool("perm.admin", false, "admin perm for users")
|
||||||
cmd.Flags().Bool("perm.execute", true, "execute perm for users")
|
cmd.Flags().Bool("perm.execute", true, "execute perm for users")
|
||||||
cmd.Flags().StringSlice("perm.commands", nil, "a list of the commands a user can execute")
|
|
||||||
cmd.Flags().Bool("perm.create", true, "create perm for users")
|
cmd.Flags().Bool("perm.create", true, "create perm for users")
|
||||||
cmd.Flags().Bool("perm.rename", true, "rename perm for users")
|
cmd.Flags().Bool("perm.rename", true, "rename perm for users")
|
||||||
cmd.Flags().Bool("perm.modify", true, "modify perm for users")
|
cmd.Flags().Bool("perm.modify", true, "modify perm for users")
|
||||||
@ -76,6 +75,7 @@ func addUserFlags(cmd *cobra.Command) {
|
|||||||
cmd.Flags().String("sorting.by", "name", "sorting mode (name, size or modified)")
|
cmd.Flags().String("sorting.by", "name", "sorting mode (name, size or modified)")
|
||||||
cmd.Flags().Bool("sorting.asc", false, "sorting by ascending order")
|
cmd.Flags().Bool("sorting.asc", false, "sorting by ascending order")
|
||||||
cmd.Flags().Bool("lockPassword", false, "lock password")
|
cmd.Flags().Bool("lockPassword", false, "lock password")
|
||||||
|
cmd.Flags().StringSlice("commands", nil, "a list of the commands a user can execute")
|
||||||
cmd.Flags().String("scope", "", "scope for users")
|
cmd.Flags().String("scope", "", "scope for users")
|
||||||
cmd.Flags().String("locale", "en", "locale for users")
|
cmd.Flags().String("locale", "en", "locale for users")
|
||||||
cmd.Flags().String("viewMode", string(types.ListViewMode), "view mode for users")
|
cmd.Flags().String("viewMode", string(types.ListViewMode), "view mode for users")
|
||||||
@ -114,10 +114,10 @@ func getUserDefaults(cmd *cobra.Command, defaults *types.UserDefaults, all bool)
|
|||||||
defaults.Perm.Share = mustGetBool(cmd, "perm.share")
|
defaults.Perm.Share = mustGetBool(cmd, "perm.share")
|
||||||
case "perm.download":
|
case "perm.download":
|
||||||
defaults.Perm.Download = mustGetBool(cmd, "perm.download")
|
defaults.Perm.Download = mustGetBool(cmd, "perm.download")
|
||||||
case "perm.commands":
|
case "commands":
|
||||||
commands, err := cmd.Flags().GetStringSlice("perm.commands")
|
commands, err := cmd.Flags().GetStringSlice("commands")
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
defaults.Perm.Commands = commands
|
defaults.Commands = commands
|
||||||
case "sorting.by":
|
case "sorting.by":
|
||||||
defaults.Sorting.By = mustGetString(cmd, "sorting.by")
|
defaults.Sorting.By = mustGetString(cmd, "sorting.by")
|
||||||
case "sorting.asc":
|
case "sorting.asc":
|
||||||
|
|||||||
@ -47,12 +47,14 @@ options you want to change.`,
|
|||||||
ViewMode: user.ViewMode,
|
ViewMode: user.ViewMode,
|
||||||
Perm: user.Perm,
|
Perm: user.Perm,
|
||||||
Sorting: user.Sorting,
|
Sorting: user.Sorting,
|
||||||
|
Commands: user.Commands,
|
||||||
}
|
}
|
||||||
getUserDefaults(cmd, &defaults, false)
|
getUserDefaults(cmd, &defaults, false)
|
||||||
user.Scope = defaults.Scope
|
user.Scope = defaults.Scope
|
||||||
user.Locale = defaults.Locale
|
user.Locale = defaults.Locale
|
||||||
user.ViewMode = defaults.ViewMode
|
user.ViewMode = defaults.ViewMode
|
||||||
user.Perm = defaults.Perm
|
user.Perm = defaults.Perm
|
||||||
|
user.Commands = defaults.Commands
|
||||||
user.Sorting = defaults.Sorting
|
user.Sorting = defaults.Sorting
|
||||||
user.LockPassword = mustGetBool(cmd, "lockPassword")
|
user.LockPassword = mustGetBool(cmd, "lockPassword")
|
||||||
|
|
||||||
|
|||||||
2
frontend
2
frontend
@ -1 +1 @@
|
|||||||
Subproject commit 9977299d4e3dd201cd3bf648fb70b03e09d6e4e3
|
Subproject commit daaf341bc3b6a973a9b32dbeb6b02331cedb6b05
|
||||||
1
go.mod
1
go.mod
@ -22,6 +22,7 @@ require (
|
|||||||
github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067
|
github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/jessevdk/go-flags v1.4.0 // indirect
|
github.com/jessevdk/go-flags v1.4.0 // indirect
|
||||||
|
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1
|
github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -42,6 +42,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
|
|||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs=
|
||||||
|
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
||||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
|||||||
@ -56,6 +56,7 @@ func (e *Env) signupHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
Locale: e.Settings.Defaults.Locale,
|
Locale: e.Settings.Defaults.Locale,
|
||||||
Perm: e.Settings.Defaults.Perm,
|
Perm: e.Settings.Defaults.Perm,
|
||||||
ViewMode: e.Settings.Defaults.ViewMode,
|
ViewMode: e.Settings.Defaults.ViewMode,
|
||||||
|
Commands: e.Settings.Defaults.Commands,
|
||||||
Scope: e.Settings.Defaults.Scope,
|
Scope: e.Settings.Defaults.Scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
http/http.go
17
http/http.go
@ -59,6 +59,9 @@ func Handler(e *Env) http.Handler {
|
|||||||
api.PathPrefix("/share").HandlerFunc(e.auth(e.sharePostHandler)).Methods("POST")
|
api.PathPrefix("/share").HandlerFunc(e.auth(e.sharePostHandler)).Methods("POST")
|
||||||
api.PathPrefix("/share").HandlerFunc(e.auth(e.shareDeleteHandler)).Methods("DELETE")
|
api.PathPrefix("/share").HandlerFunc(e.auth(e.shareDeleteHandler)).Methods("DELETE")
|
||||||
|
|
||||||
|
api.HandleFunc("/settings", e.auth(e.settingsGetHandler)).Methods("GET")
|
||||||
|
api.HandleFunc("/settings", e.auth(e.settingsPutHandler)).Methods("PUT")
|
||||||
|
|
||||||
api.PathPrefix("/raw").HandlerFunc(e.auth(e.rawHandler)).Methods("GET")
|
api.PathPrefix("/raw").HandlerFunc(e.auth(e.rawHandler)).Methods("GET")
|
||||||
|
|
||||||
return r
|
return r
|
||||||
@ -100,3 +103,17 @@ func (e *Env) getUser(w http.ResponseWriter, r *http.Request) (*types.User, bool
|
|||||||
|
|
||||||
return user, true
|
return user, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Env) getAdminUser(w http.ResponseWriter, r *http.Request) (*types.User, bool) {
|
||||||
|
user, ok := e.getUser(w, r)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.Perm.Admin {
|
||||||
|
httpErr(w, r, http.StatusForbidden, nil)
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, true
|
||||||
|
}
|
||||||
|
|||||||
@ -228,7 +228,7 @@ func (e *Env) resourcePatchHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return user.Fs.Rename(src, dst)
|
return user.Fs.Rename(src, dst)
|
||||||
}, "action", src, dst, user)
|
}, action, src, dst, user)
|
||||||
|
|
||||||
httpErr(w, r, httpFsErr(err), err)
|
httpErr(w, r, httpFsErr(err), err)
|
||||||
}
|
}
|
||||||
|
|||||||
74
http/settings.go
Normal file
74
http/settings.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/filebrowser/filebrowser/types"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
)
|
||||||
|
|
||||||
|
type settingsData struct {
|
||||||
|
Signup bool `json:"signup"`
|
||||||
|
Defaults types.UserDefaults `json:"defaults"`
|
||||||
|
Rules []types.Rule `json:"rules"`
|
||||||
|
Commands map[string][]string `json:"commands"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Env) settingsGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := e.getAdminUser(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &settingsData{
|
||||||
|
Signup: e.Settings.Signup,
|
||||||
|
Defaults: e.Settings.Defaults,
|
||||||
|
Rules: e.Settings.Rules,
|
||||||
|
Commands: e.Runner.Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
renderJSON(w, r, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Env) settingsPutHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := e.getAdminUser(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &settingsData{}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(req)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, r, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := &types.Runner{Commands: req.Commands}
|
||||||
|
err = e.Store.Config.SaveRunner(runner)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, r, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := &types.Settings{}
|
||||||
|
err = copier.Copy(settings, e.Settings)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, r, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Signup = req.Signup
|
||||||
|
settings.Defaults = req.Defaults
|
||||||
|
settings.Rules = req.Rules
|
||||||
|
|
||||||
|
err = e.Store.Config.SaveSettings(settings)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, r, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: env locks
|
||||||
|
e.Runner = runner
|
||||||
|
e.Settings = settings
|
||||||
|
}
|
||||||
@ -14,13 +14,9 @@ import (
|
|||||||
"github.com/filebrowser/filebrowser/types"
|
"github.com/filebrowser/filebrowser/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Env) getStaticHandlers() (http.Handler, http.Handler) {
|
func (e *Env) getStaticData () map[string]interface{} {
|
||||||
box := rice.MustFindBox("../frontend/dist")
|
|
||||||
handler := http.FileServer(box.HTTPBox())
|
|
||||||
|
|
||||||
baseURL := strings.TrimSuffix(e.Settings.BaseURL, "/")
|
baseURL := strings.TrimSuffix(e.Settings.BaseURL, "/")
|
||||||
staticURL := strings.TrimPrefix(baseURL+"/static", "/")
|
staticURL := strings.TrimPrefix(baseURL+"/static", "/")
|
||||||
cssFile := ""
|
|
||||||
|
|
||||||
// TODO: baseurl must always not have the trailing slash
|
// TODO: baseurl must always not have the trailing slash
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
@ -43,7 +39,6 @@ func (e *Env) getStaticHandlers() (http.Handler, http.Handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cssFile = path
|
|
||||||
data["CSS"] = true
|
data["CSS"] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,10 +56,18 @@ func (e *Env) getStaticHandlers() (http.Handler, http.Handler) {
|
|||||||
b, _ := json.MarshalIndent(data, "", " ")
|
b, _ := json.MarshalIndent(data, "", " ")
|
||||||
data["Json"] = string(b)
|
data["Json"] = string(b)
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Env) getStaticHandlers() (http.Handler, http.Handler) {
|
||||||
|
box := rice.MustFindBox("../frontend/dist")
|
||||||
|
handler := http.FileServer(box.HTTPBox())
|
||||||
|
|
||||||
|
|
||||||
handleWithData := func(w http.ResponseWriter, r *http.Request, file string, contentType string) {
|
handleWithData := func(w http.ResponseWriter, r *http.Request, file string, contentType string) {
|
||||||
w.Header().Set("Content-Type", contentType)
|
w.Header().Set("Content-Type", contentType)
|
||||||
index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
|
index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
|
||||||
err := index.Execute(w, data)
|
err := index.Execute(w, e.getStaticData())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpErr(w, r, http.StatusInternalServerError, err)
|
httpErr(w, r, http.StatusInternalServerError, err)
|
||||||
@ -91,8 +94,8 @@ func (e *Env) getStaticHandlers() (http.Handler, http.Handler) {
|
|||||||
http.ServeFile(w, r, path)
|
http.ServeFile(w, r, path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if r.URL.Path == "custom.css" && cssFile != "" {
|
} else if r.URL.Path == "custom.css" && e.Settings.Branding.Files != "" {
|
||||||
http.ServeFile(w, r, cssFile)
|
http.ServeFile(w, r, filepath.Join(e.Settings.Branding.Files, "custom.css"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ type Rule struct {
|
|||||||
// Regexp is a wrapper to the native regexp type where we
|
// Regexp is a wrapper to the native regexp type where we
|
||||||
// save the raw expression.
|
// save the raw expression.
|
||||||
type Regexp struct {
|
type Regexp struct {
|
||||||
Raw string
|
Raw string `json:"raw"`
|
||||||
regexp *regexp.Regexp
|
regexp *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,6 @@ import (
|
|||||||
var DefaultEvents = []string{
|
var DefaultEvents = []string{
|
||||||
"before_save",
|
"before_save",
|
||||||
"after_save",
|
"after_save",
|
||||||
"before_publish",
|
|
||||||
"after_publish",
|
|
||||||
"before_copy",
|
"before_copy",
|
||||||
"after_copy",
|
"after_copy",
|
||||||
"before_rename",
|
"before_rename",
|
||||||
@ -55,6 +53,10 @@ func (r Runner) do(event string, path string, destination string, user *User) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, command := range commands {
|
for _, command := range commands {
|
||||||
|
if command == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
args := strings.Split(command, " ")
|
args := strings.Split(command, " ")
|
||||||
nonblock := false
|
nonblock := false
|
||||||
|
|
||||||
|
|||||||
@ -40,4 +40,5 @@ type UserDefaults struct {
|
|||||||
ViewMode ViewMode `json:"viewMode"`
|
ViewMode ViewMode `json:"viewMode"`
|
||||||
Sorting Sorting `json:"sorting"`
|
Sorting Sorting `json:"sorting"`
|
||||||
Perm Permissions `json:"perm"`
|
Perm Permissions `json:"perm"`
|
||||||
|
Commands []string `json:"commands"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,15 +15,14 @@ const (
|
|||||||
|
|
||||||
// Permissions describe a user's permissions.
|
// Permissions describe a user's permissions.
|
||||||
type Permissions struct {
|
type Permissions struct {
|
||||||
Admin bool `json:"admin"`
|
Admin bool `json:"admin"`
|
||||||
Execute bool `json:"execute"`
|
Execute bool `json:"execute"`
|
||||||
Create bool `json:"create"`
|
Create bool `json:"create"`
|
||||||
Rename bool `json:"rename"`
|
Rename bool `json:"rename"`
|
||||||
Modify bool `json:"edit"`
|
Modify bool `json:"edit"`
|
||||||
Delete bool `json:"delete"`
|
Delete bool `json:"delete"`
|
||||||
Share bool `json:"share"`
|
Share bool `json:"share"`
|
||||||
Download bool `json:"download"`
|
Download bool `json:"download"`
|
||||||
Commands []string `json:"commands"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User describes a user.
|
// User describes a user.
|
||||||
@ -36,6 +35,7 @@ type User struct {
|
|||||||
LockPassword bool `json:"lockPassword"`
|
LockPassword bool `json:"lockPassword"`
|
||||||
ViewMode ViewMode `json:"viewMode"`
|
ViewMode ViewMode `json:"viewMode"`
|
||||||
Perm Permissions `json:"perm"`
|
Perm Permissions `json:"perm"`
|
||||||
|
Commands []string `json:"commands"`
|
||||||
Sorting Sorting `json:"sorting"`
|
Sorting Sorting `json:"sorting"`
|
||||||
Fs afero.Fs `json:"-"`
|
Fs afero.Fs `json:"-"`
|
||||||
Rules []Rule `json:"rules"`
|
Rules []Rule `json:"rules"`
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user