From e38350e8b3bcdab7016cefbb73bc410fd74037de Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 21 Jan 2024 17:19:25 +0100 Subject: [PATCH] WIP new WebAdmin: role page Signed-off-by: Nicola Murino --- internal/dataprovider/group.go | 12 ---- internal/dataprovider/role.go | 20 ++----- internal/httpd/webadmin.go | 36 ++++++------ internal/util/i18n.go | 2 + static/locales/en/translation.json | 4 +- static/locales/it/translation.json | 4 +- templates/webadmin/role.html | 94 ++++++++++++++++-------------- 7 files changed, 82 insertions(+), 90 deletions(-) diff --git a/internal/dataprovider/group.go b/internal/dataprovider/group.go index cc6c28fa..8577efda 100644 --- a/internal/dataprovider/group.go +++ b/internal/dataprovider/group.go @@ -237,15 +237,3 @@ func (g *Group) getACopy() Group { VirtualFolders: virtualFolders, } } - -// GetMembersAsString returns a string representation for the group members -func (g *Group) GetMembersAsString() string { - var sb strings.Builder - if len(g.Users) > 0 { - sb.WriteString(fmt.Sprintf("Users: %d. ", len(g.Users))) - } - if len(g.Admins) > 0 { - sb.WriteString(fmt.Sprintf("Admins: %d. ", len(g.Admins))) - } - return sb.String() -} diff --git a/internal/dataprovider/role.go b/internal/dataprovider/role.go index 2790fdc5..dffe0321 100644 --- a/internal/dataprovider/role.go +++ b/internal/dataprovider/role.go @@ -17,7 +17,6 @@ package dataprovider import ( "encoding/json" "fmt" - "strings" "github.com/drakkan/sftpgo/v2/internal/logger" "github.com/drakkan/sftpgo/v2/internal/util" @@ -56,13 +55,16 @@ func (r *Role) RenderAsJSON(reload bool) ([]byte, error) { func (r *Role) validate() error { if r.Name == "" { - return util.NewValidationError("name is mandatory") + return util.NewI18nError(util.NewValidationError("name is mandatory"), util.I18nErrorNameRequired) } if len(r.Name) > 255 { return util.NewValidationError("name is too long, 255 is the maximum length allowed") } if config.NamingRules&1 == 0 && !usernameRegex.MatchString(r.Name) { - return util.NewValidationError(fmt.Sprintf("name %q is not valid, the following characters are allowed: a-zA-Z0-9-_.~", r.Name)) + return util.NewI18nError( + util.NewValidationError(fmt.Sprintf("name %q is not valid, the following characters are allowed: a-zA-Z0-9-_.~", r.Name)), + util.I18nErrorInvalidName, + ) } return nil } @@ -83,15 +85,3 @@ func (r *Role) getACopy() Role { Admins: admins, } } - -// GetMembersAsString returns a string representation for the role members -func (r *Role) GetMembersAsString() string { - var sb strings.Builder - if len(r.Users) > 0 { - sb.WriteString(fmt.Sprintf("Users: %d. ", len(r.Users))) - } - if len(r.Admins) > 0 { - sb.WriteString(fmt.Sprintf("Admins: %d. ", len(r.Admins))) - } - return sb.String() -} diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 0a4bfb52..1f40f52e 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -307,7 +307,7 @@ type groupPage struct { type rolePage struct { basePage Role *dataprovider.Role - Error string + Error *util.I18nError Mode genericPageMode } @@ -516,7 +516,7 @@ func loadAdminTemplates(templatesPath string) { filepath.Join(templatesPath, templateAdminDir, templateRoles), } rolePaths := []string{ - filepath.Join(templatesPath, templateCommonDir, templateCommonCSS), + filepath.Join(templatesPath, templateCommonDir, templateCommonBase), filepath.Join(templatesPath, templateAdminDir, templateBase), filepath.Join(templatesPath, templateAdminDir, templateRole), } @@ -1024,20 +1024,20 @@ func (s *httpdServer) renderIPListPage(w http.ResponseWriter, r *http.Request, e } func (s *httpdServer) renderRolePage(w http.ResponseWriter, r *http.Request, role dataprovider.Role, - mode genericPageMode, error string, + mode genericPageMode, err error, ) { var title, currentURL string switch mode { case genericPageModeAdd: - title = "Add a new role" + title = util.I18nRoleAddTitle currentURL = webAdminRolePath case genericPageModeUpdate: - title = "Update role" + title = util.I18nRoleUpdateTitle currentURL = fmt.Sprintf("%s/%s", webAdminRolePath, url.PathEscape(role.Name)) } data := rolePage{ basePage: s.getBasePageData(title, currentURL, r), - Error: error, + Error: getI18nError(err), Role: &role, Mode: mode, } @@ -1751,7 +1751,7 @@ func getAdminFromPostFields(r *http.Request) (dataprovider.Admin, error) { var admin dataprovider.Admin err := r.ParseForm() if err != nil { - return admin, err + return admin, util.NewI18nError(err, util.I18nErrorInvalidForm) } status, err := strconv.Atoi(r.Form.Get("status")) if err != nil { @@ -2346,7 +2346,7 @@ func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEven func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction, error) { err := r.ParseForm() if err != nil { - return dataprovider.BaseEventAction{}, err + return dataprovider.BaseEventAction{}, util.NewI18nError(err, util.I18nErrorInvalidForm) } actionType, err := strconv.Atoi(r.Form.Get("type")) if err != nil { @@ -2500,7 +2500,7 @@ func getEventRuleActionsFromPostFields(r *http.Request) ([]dataprovider.EventAct func getEventRuleFromPostFields(r *http.Request) (dataprovider.EventRule, error) { err := r.ParseForm() if err != nil { - return dataprovider.EventRule{}, err + return dataprovider.EventRule{}, util.NewI18nError(err, util.I18nErrorInvalidForm) } status, err := strconv.Atoi(r.Form.Get("status")) if err != nil { @@ -2532,7 +2532,7 @@ func getEventRuleFromPostFields(r *http.Request) (dataprovider.EventRule, error) func getRoleFromPostFields(r *http.Request) (dataprovider.Role, error) { err := r.ParseForm() if err != nil { - return dataprovider.Role{}, err + return dataprovider.Role{}, util.NewI18nError(err, util.I18nErrorInvalidForm) } return dataprovider.Role{ @@ -2544,7 +2544,7 @@ func getRoleFromPostFields(r *http.Request) (dataprovider.Role, error) { func getIPListEntryFromPostFields(r *http.Request, listType dataprovider.IPListType) (dataprovider.IPListEntry, error) { err := r.ParseForm() if err != nil { - return dataprovider.IPListEntry{}, err + return dataprovider.IPListEntry{}, util.NewI18nError(err, util.I18nErrorInvalidForm) } var mode int if listType == dataprovider.IPListTypeDefender { @@ -3890,14 +3890,14 @@ func (s *httpdServer) handleWebGetRoles(w http.ResponseWriter, r *http.Request) func (s *httpdServer) handleWebAddRoleGet(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) - s.renderRolePage(w, r, dataprovider.Role{}, genericPageModeAdd, "") + s.renderRolePage(w, r, dataprovider.Role{}, genericPageModeAdd, nil) } func (s *httpdServer) handleWebAddRolePost(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) role, err := getRoleFromPostFields(r) if err != nil { - s.renderRolePage(w, r, role, genericPageModeAdd, err.Error()) + s.renderRolePage(w, r, role, genericPageModeAdd, err) return } claims, err := getTokenClaims(r) @@ -3912,7 +3912,7 @@ func (s *httpdServer) handleWebAddRolePost(w http.ResponseWriter, r *http.Reques } err = dataprovider.AddRole(&role, claims.Username, ipAddr, claims.Role) if err != nil { - s.renderRolePage(w, r, role, genericPageModeAdd, err.Error()) + s.renderRolePage(w, r, role, genericPageModeAdd, err) return } http.Redirect(w, r, webAdminRolesPath, http.StatusSeeOther) @@ -3922,7 +3922,7 @@ func (s *httpdServer) handleWebUpdateRoleGet(w http.ResponseWriter, r *http.Requ r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) role, err := dataprovider.RoleExists(getURLParam(r, "name")) if err == nil { - s.renderRolePage(w, r, role, genericPageModeUpdate, "") + s.renderRolePage(w, r, role, genericPageModeUpdate, nil) } else if errors.Is(err, util.ErrNotFound) { s.renderNotFoundPage(w, r, err) } else { @@ -3948,7 +3948,7 @@ func (s *httpdServer) handleWebUpdateRolePost(w http.ResponseWriter, r *http.Req updatedRole, err := getRoleFromPostFields(r) if err != nil { - s.renderRolePage(w, r, role, genericPageModeUpdate, err.Error()) + s.renderRolePage(w, r, role, genericPageModeUpdate, err) return } ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) @@ -3960,7 +3960,7 @@ func (s *httpdServer) handleWebUpdateRolePost(w http.ResponseWriter, r *http.Req updatedRole.Name = role.Name err = dataprovider.UpdateRole(&updatedRole, claims.Username, ipAddr, claims.Role) if err != nil { - s.renderRolePage(w, r, updatedRole, genericPageModeUpdate, err.Error()) + s.renderRolePage(w, r, updatedRole, genericPageModeUpdate, err) return } http.Redirect(w, r, webAdminRolesPath, http.StatusSeeOther) @@ -4113,7 +4113,7 @@ func (s *httpdServer) handleWebConfigsPost(w http.ResponseWriter, r *http.Reques } err = r.ParseForm() if err != nil { - s.renderBadRequestPage(w, r, err) + s.renderBadRequestPage(w, r, util.NewI18nError(err, util.I18nErrorInvalidForm)) return } ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) diff --git a/internal/util/i18n.go b/internal/util/i18n.go index 1e1cc9a0..bf60d076 100644 --- a/internal/util/i18n.go +++ b/internal/util/i18n.go @@ -193,6 +193,8 @@ const ( I18nErrorFsUsernameRequired = "storage.username_required" I18nAddGroupTitle = "title.add_group" I18nUpdateGroupTitle = "title.update_group" + I18nRoleAddTitle = "title.add_role" + I18nRoleUpdateTitle = "title.update_role" I18nErrorInvalidTLSCert = "user.tls_cert_invalid" I18nAddFolderTitle = "title.add_folder" I18nUpdateFolderTitle = "title.update_folder" diff --git a/static/locales/en/translation.json b/static/locales/en/translation.json index f322fbb5..7c488442 100644 --- a/static/locales/en/translation.json +++ b/static/locales/en/translation.json @@ -54,7 +54,9 @@ "update_folder": "Update virtual folder", "template_folder": "Virtual folder template", "oauth2_error": "Unable to complete OAuth2 flow", - "oauth2_success": "OAuth2 flow completed" + "oauth2_success": "OAuth2 flow completed", + "add_role": "Add role", + "update_role": "Update role" }, "setup": { "desc": "To start using SFTPGo you need to create an administrator user", diff --git a/static/locales/it/translation.json b/static/locales/it/translation.json index 23b0abbd..ab4dfe76 100644 --- a/static/locales/it/translation.json +++ b/static/locales/it/translation.json @@ -54,7 +54,9 @@ "update_folder": "Aggiorna cartella virtuale", "template_folder": "Modello cartella virtuale", "oauth2_error": "Impossibile completare il flusso OAuth2", - "oauth2_success": "OAuth2 completato" + "oauth2_success": "OAuth2 completato", + "add_role": "Aggiungi ruolo", + "update_role": "Aggiorna ruolo" }, "setup": { "desc": "Per iniziare a utilizzare SFTPGo devi creare un utente amministratore", diff --git a/templates/webadmin/role.html b/templates/webadmin/role.html index a9d1a32a..f2328a85 100644 --- a/templates/webadmin/role.html +++ b/templates/webadmin/role.html @@ -1,61 +1,69 @@ {{template "base" .}} -{{define "title"}}{{.Title}}{{end}} - -{{define "page_body"}} - -
-
-
{{.Title}}
+{{- define "page_body"}} +
+
+

- {{if .Error}} - - {{end}} + {{- template "errmsg" .Error}}
+
- -
- -
-
-
- -
- - - Optional description - + +
+
- -
- +
+ +
+ +
+
+ +
+ +
-{{end}} +{{- end}} + +{{- define "extra_js"}} + +{{- end}} \ No newline at end of file