increase the number of agents on the ua chart

optimise mfaVerifySession
reduce boilerplate for populating the menu items
shorten ua phrases for semrush and aspiegel
rename account_username_updated phrase to account_name_updated
This commit is contained in:
Azareal 2020-03-24 12:07:30 +10:00
parent 42f965d147
commit a47a0318a7
10 changed files with 95 additions and 76 deletions

View File

@ -223,28 +223,43 @@ func seedTables(a qgen.Adapter) error {
order := 0 order := 0
mOrder := "mid, name, htmlID, cssClass, position, path, aria, tooltip, guestOnly, memberOnly, staffOnly, adminOnly" mOrder := "mid, name, htmlID, cssClass, position, path, aria, tooltip, guestOnly, memberOnly, staffOnly, adminOnly"
addMenuItem := func(data map[string]interface{}) { addMenuItem := func(data map[string]interface{}) {
if data["mid"] == nil {
data["mid"] = 1
}
if data["position"] == nil {
data["position"] = "left"
}
cols, values := qgen.InterfaceMapToInsertStrings(data, mOrder) cols, values := qgen.InterfaceMapToInsertStrings(data, mOrder)
qgen.Install.SimpleInsert("menu_items", cols+", order", values+","+strconv.Itoa(order)) qgen.Install.SimpleInsert("menu_items", cols+", order", values+","+strconv.Itoa(order))
order++ order++
} }
addMenuItem(si{"mid": 1, "name": "{lang.menu_forums}", "htmlID": "menu_forums", "position": "left", "path": "/forums/", "aria": "{lang.menu_forums_aria}", "tooltip": "{lang.menu_forums_tooltip}"}) addMenuItem(si{"name": "{lang.menu_forums}", "htmlID": "menu_forums", "path": "/forums/", "aria": "{lang.menu_forums_aria}", "tooltip": "{lang.menu_forums_tooltip}"})
addMenuItem(si{"mid": 1, "name": "{lang.menu_topics}", "htmlID": "menu_topics", "cssClass": "menu_topics", "position": "left", "path": "/topics/", "aria": "{lang.menu_topics_aria}", "tooltip": "{lang.menu_topics_tooltip}"}) addMenuItem(si{"name": "{lang.menu_topics}", "htmlID": "menu_topics", "cssClass": "menu_topics", "path": "/topics/", "aria": "{lang.menu_topics_aria}", "tooltip": "{lang.menu_topics_tooltip}"})
addMenuItem(si{"mid": 1, "htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"}) addMenuItem(si{"htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"})
addMenuItem(si{"mid": 1, "name": "{lang.menu_account}", "cssClass": "menu_account", "position": "left", "path": "/user/edit/", "aria": "{lang.menu_account_aria}", "tooltip": "{lang.menu_account_tooltip}", "memberOnly": true}) addMenuItem(si{"name": "{lang.menu_account}", "cssClass": "menu_account", "path": "/user/edit/", "aria": "{lang.menu_account_aria}", "tooltip": "{lang.menu_account_tooltip}", "memberOnly": true})
addMenuItem(si{"mid": 1, "name": "{lang.menu_profile}", "cssClass": "menu_profile", "position": "left", "path": "{me.Link}", "aria": "{lang.menu_profile_aria}", "tooltip": "{lang.menu_profile_tooltip}", "memberOnly": true}) addMenuItem(si{"name": "{lang.menu_profile}", "cssClass": "menu_profile", "path": "{me.Link}", "aria": "{lang.menu_profile_aria}", "tooltip": "{lang.menu_profile_tooltip}", "memberOnly": true})
addMenuItem(si{"mid": 1, "name": "{lang.menu_panel}", "cssClass": "menu_panel menu_account", "position": "left", "path": "/panel/", "aria": "{lang.menu_panel_aria}", "tooltip": "{lang.menu_panel_tooltip}", "memberOnly": true, "staffOnly": true}) addMenuItem(si{"name": "{lang.menu_panel}", "cssClass": "menu_panel menu_account", "path": "/panel/", "aria": "{lang.menu_panel_aria}", "tooltip": "{lang.menu_panel_tooltip}", "memberOnly": true, "staffOnly": true})
addMenuItem(si{"mid": 1, "name": "{lang.menu_logout}", "cssClass": "menu_logout", "position": "left", "path": "/accounts/logout/?s={me.Session}", "aria": "{lang.menu_logout_aria}", "tooltip": "{lang.menu_logout_tooltip}", "memberOnly": true}) addMenuItem(si{"name": "{lang.menu_logout}", "cssClass": "menu_logout", "path": "/accounts/logout/?s={me.Session}", "aria": "{lang.menu_logout_aria}", "tooltip": "{lang.menu_logout_tooltip}", "memberOnly": true})
addMenuItem(si{"mid": 1, "name": "{lang.menu_register}", "cssClass": "menu_register", "position": "left", "path": "/accounts/create/", "aria": "{lang.menu_register_aria}", "tooltip": "{lang.menu_register_tooltip}", "guestOnly": true}) addMenuItem(si{"name": "{lang.menu_register}", "cssClass": "menu_register", "path": "/accounts/create/", "aria": "{lang.menu_register_aria}", "tooltip": "{lang.menu_register_tooltip}", "guestOnly": true})
addMenuItem(si{"mid": 1, "name": "{lang.menu_login}", "cssClass": "menu_login", "position": "left", "path": "/accounts/login/", "aria": "{lang.menu_login_aria}", "tooltip": "{lang.menu_login_tooltip}", "guestOnly": true}) addMenuItem(si{"name": "{lang.menu_login}", "cssClass": "menu_login", "path": "/accounts/login/", "aria": "{lang.menu_login_aria}", "tooltip": "{lang.menu_login_tooltip}", "guestOnly": true})
var fSet []string
for _, table := range tables {
fSet = append(fSet, "'"+table+"'")
}
qgen.Install.SimpleBulkInsert("tables", "name", fSet)
/*for _, table := range tables {
qgen.Install.SimpleInsert("tables", "name", "'"+table+"'")
}*/
return nil return nil
} }
@ -347,7 +362,7 @@ func writeInsertInnerJoins(a qgen.Adapter) error {
return nil return nil
} }
func writeFile(name string, content string) (err error) { func writeFile(name, content string) (err error) {
f, err := os.Create(name) f, err := os.Create(name)
if err != nil { if err != nil {
return err return err

View File

@ -3,7 +3,7 @@ package install
import ( import (
"fmt" "fmt"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
var adapters = make(map[string]InstallAdapter) var adapters = make(map[string]InstallAdapter)
@ -11,7 +11,7 @@ var adapters = make(map[string]InstallAdapter)
type InstallAdapter interface { type InstallAdapter interface {
Name() string Name() string
DefaultPort() string DefaultPort() string
SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string) SetConfig(dbHost, dbUsername, dbPassword, dbName, dbPort string)
InitDatabase() error InitDatabase() error
TableDefs() error TableDefs() error
InitialData() error InitialData() error

View File

@ -223,13 +223,13 @@
"alexa":"Alexa", "alexa":"Alexa",
"lynx":"Lynx", "lynx":"Lynx",
"semrush":"SemrushBot", "semrush":"Semrush",
"dotbot":"DotBot", "dotbot":"DotBot",
"ahrefs":"Ahrefs", "ahrefs":"Ahrefs",
"proximic":"Comscore", "proximic":"Comscore",
"majestic":"MJ12bot", "majestic":"MJ12bot",
"blexbot":"BLEXBot", "blexbot":"BLEXBot",
"aspiegel":"AspiegelBot", "aspiegel":"Aspiegel",
"mail_ru":"Mail.ru bot", "mail_ru":"Mail.ru bot",
"zgrab":"Zgrab App Scanner", "zgrab":"Zgrab App Scanner",
"curl":"curl", "curl":"curl",
@ -341,7 +341,7 @@
"account_banned":"Your account has been suspended. Some of your permissions may have been revoked.", "account_banned":"Your account has been suspended. Some of your permissions may have been revoked.",
"account_inactive":"Your account hasn't been activated yet. Some features may remain unavailable until it is.", "account_inactive":"Your account hasn't been activated yet. Some features may remain unavailable until it is.",
"account_avatar_updated":"Your avatar was successfully updated.", "account_avatar_updated":"Your avatar was successfully updated.",
"account_username_updated":"Your username was successfully updated.", "account_name_updated":"Your name was successfully updated.",
"account_mail_disabled":"The mail system is currently disabled.", "account_mail_disabled":"The mail system is currently disabled.",
"account_mail_verify_success":"Your email was successfully verified.", "account_mail_verify_success":"Your email was successfully verified.",
"account_mfa_setup_success":"Two-factor authentication was successfully setup for your account.", "account_mfa_setup_success":"Two-factor authentication was successfully setup for your account.",

View File

@ -135,14 +135,14 @@ type Adapter interface {
// TODO: Some way to add indices and keys // TODO: Some way to add indices and keys
// TODO: Test this // TODO: Test this
AddColumn(name, table string, col DBTableColumn, key *DBTableKey) (string, error) AddColumn(name, table string, col DBTableColumn, key *DBTableKey) (string, error)
DropColumn(name, table, colname string) (string, error) DropColumn(name, table, colName string) (string, error)
RenameColumn(name, table, oldName, newName string) (string, error) RenameColumn(name, table, oldName, newName string) (string, error)
ChangeColumn(name, table, colName string, col DBTableColumn) (string, error) ChangeColumn(name, table, colName string, col DBTableColumn) (string, error)
SetDefaultColumn(name, table, colName, colType, defaultStr string) (string, error) SetDefaultColumn(name, table, colName, colType, defaultStr string) (string, error)
AddIndex(name, table, iname, colname string) (string, error) AddIndex(name, table, iname, colname string) (string, error)
AddKey(name, table, col string, key DBTableKey) (string, error) AddKey(name, table, col string, key DBTableKey) (string, error)
RemoveIndex(name, table, col string) (string, error) RemoveIndex(name, table, col string) (string, error)
AddForeignKey(name, table, col, ftable, fcolumn string, cascade bool) (out string, e error) AddForeignKey(name, table, col, ftable, fcol string, cascade bool) (out string, e error)
SimpleInsert(name, table, cols, fields string) (string, error) SimpleInsert(name, table, cols, fields string) (string, error)
SimpleBulkInsert(name, table, cols string, fieldSet []string) (string, error) SimpleBulkInsert(name, table, cols string, fieldSet []string) (string, error)
SimpleUpdate(b *updatePrebuilder) (string, error) SimpleUpdate(b *updatePrebuilder) (string, error)

View File

@ -20,9 +20,9 @@ import (
// A blank list to fill out that parameter in Page for routes which don't use it // A blank list to fill out that parameter in Page for routes which don't use it
var tList []interface{} var tList []interface{}
func AccountLogin(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError { func AccountLogin(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
if user.Loggedin { if u.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, u)
} }
h.Title = p.GetTitlePhrase("login") h.Title = p.GetTitlePhrase("login")
return renderTemplate("login", w, r, h, c.Page{h, tList, nil}) return renderTemplate("login", w, r, h, c.Page{h, tList, nil})
@ -123,21 +123,25 @@ func mfaGetCookies(r *http.Request) (uid int, provSession, signedSession string,
} }
func mfaVerifySession(provSession, signedSession string, uid int) bool { func mfaVerifySession(provSession, signedSession string, uid int) bool {
bProvSession := []byte(provSession)
bSignedSession := []byte(signedSession)
bUid := []byte(strconv.Itoa(uid))
h := sha256.New() h := sha256.New()
h.Write([]byte(c.SessionSigningKeyBox.Load().(string))) h.Write([]byte(c.SessionSigningKeyBox.Load().(string)))
h.Write([]byte(provSession)) h.Write(bProvSession)
h.Write([]byte(strconv.Itoa(uid))) h.Write(bUid)
expected := hex.EncodeToString(h.Sum(nil)) expected := hex.EncodeToString(h.Sum(nil))
if subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1 { if subtle.ConstantTimeCompare(bSignedSession, []byte(expected)) == 1 {
return true return true
} }
h = sha256.New() h = sha256.New()
h.Write([]byte(c.OldSessionSigningKeyBox.Load().(string))) h.Write([]byte(c.OldSessionSigningKeyBox.Load().(string)))
h.Write([]byte(provSession)) h.Write(bProvSession)
h.Write([]byte(strconv.Itoa(uid))) h.Write(bUid)
expected = hex.EncodeToString(h.Sum(nil)) expected = hex.EncodeToString(h.Sum(nil))
return subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1 return subtle.ConstantTimeCompare(bSignedSession, []byte(expected)) == 1
} }
func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError { func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
@ -354,26 +358,26 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user *c.User)
} }
// TODO: Figure a way of making this into middleware? // TODO: Figure a way of making this into middleware?
func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) { func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) {
h.Title = p.GetTitlePhrase(titlePhrase) h.Title = p.GetTitlePhrase(titlePhrase)
h.Path = "/user/edit/" h.Path = "/user/edit/"
h.AddSheet(h.Theme.Name + "/account.css") h.AddSheet(h.Theme.Name + "/account.css")
h.AddScriptAsync("account.js") h.AddScriptAsync("account.js")
} }
func AccountEdit(w http.ResponseWriter, r *http.Request, user *c.User, header *c.Header) c.RouteError { func AccountEdit(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
accountEditHead("account", w, r, user, header) accountEditHead("account", w, r, u, h)
if r.FormValue("avatar_updated") == "1" { if r.FormValue("avatar_updated") == "1" {
header.AddNotice("account_avatar_updated") h.AddNotice("account_avatar_updated")
} else if r.FormValue("username_updated") == "1" { } else if r.FormValue("name_updated") == "1" {
header.AddNotice("account_username_updated") h.AddNotice("account_name_updated")
} else if r.FormValue("mfa_setup_success") == "1" { } else if r.FormValue("mfa_setup_success") == "1" {
header.AddNotice("account_mfa_setup_success") h.AddNotice("account_mfa_setup_success")
} }
// TODO: Find a more efficient way of doing this // TODO: Find a more efficient way of doing this
mfaSetup := false mfaSetup := false
_, err := c.MFAstore.Get(user.ID) _, err := c.MFAstore.Get(u.ID)
if err != sql.ErrNoRows && err != nil { if err != sql.ErrNoRows && err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} else if err != sql.ErrNoRows { } else if err != sql.ErrNoRows {
@ -381,13 +385,13 @@ func AccountEdit(w http.ResponseWriter, r *http.Request, user *c.User, header *c
} }
// Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score // Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score
prevScore := c.GetLevelScore(user.Level) prevScore := c.GetLevelScore(u.Level)
currentScore := user.Score - prevScore currentScore := u.Score - prevScore
nextScore := c.GetLevelScore(user.Level+1) - prevScore nextScore := c.GetLevelScore(u.Level+1) - prevScore
perc := int(math.Ceil((float64(nextScore) / float64(currentScore)) * 100)) perc := int(math.Ceil((float64(nextScore) / float64(currentScore)) * 100))
pi := c.Account{header, "dashboard", "account_own_edit", c.AccountDashPage{header, mfaSetup, currentScore, nextScore, user.Level + 1, perc * 2}} pi := c.Account{h, "dashboard", "account_own_edit", c.AccountDashPage{h, mfaSetup, currentScore, nextScore, u.Level + 1, perc * 2}}
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, h, pi)
} }
//edit_password //edit_password
@ -481,16 +485,16 @@ func AccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, u *c.User
return ferr return ferr
} }
newUsername := c.SanitiseSingleLine(r.PostFormValue("account-new-username")) newName := c.SanitiseSingleLine(r.PostFormValue("new-name"))
if newUsername == "" { if newName == "" {
return c.LocalError("You can't leave your username blank", w, r, u) return c.LocalError("You can't leave your username blank", w, r, u)
} }
err := u.ChangeName(newUsername) err := u.ChangeName(newName)
if err != nil { if err != nil {
return c.LocalError("Unable to change the username. Does someone else already have this name?", w, r, u) return c.LocalError("Unable to change names. Does someone else already have this name?", w, r, u)
} }
http.Redirect(w, r, "/user/edit/?username_updated=1", http.StatusSeeOther) http.Redirect(w, r, "/user/edit/?name_updated=1", http.StatusSeeOther)
return nil return nil
} }
@ -568,18 +572,18 @@ func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user *c.U
} }
// TODO: Implement this // TODO: Implement this
func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
_, ferr := c.SimpleUserCheck(w, r, user) _, ferr := c.SimpleUserCheck(w, r, u)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
// Flash an error if mfa is already setup // Flash an error if mfa is already setup
mfaItem, err := c.MFAstore.Get(user.ID) mfaItem, err := c.MFAstore.Get(u.ID)
if err != sql.ErrNoRows && err != nil { if err != sql.ErrNoRows && err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} else if err == sql.ErrNoRows { } else if err == sql.ErrNoRows {
return c.LocalError("You don't have two-factor enabled on your account", w, r, user) return c.LocalError("You don't have two-factor enabled on your account", w, r, u)
} }
err = mfaItem.Delete() err = mfaItem.Delete()
@ -603,16 +607,16 @@ func AccountEditPrivacy(w http.ResponseWriter, r *http.Request, u *c.User, h *c.
return renderTemplate("account", w, r, h, pi) return renderTemplate("account", w, r, h, pi)
} }
func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
//headerLite, _ := c.SimpleUserCheck(w, r, user) //headerLite, _ := c.SimpleUserCheck(w, r, u)
sEnableEmbeds := r.FormValue("enable_embeds") sEnableEmbeds := r.FormValue("enable_embeds")
enableEmbeds, err := strconv.Atoi(sEnableEmbeds) enableEmbeds, err := strconv.Atoi(sEnableEmbeds)
if err != nil { if err != nil {
return c.LocalError("enable_embeds must be 0 or 1", w, r, user) return c.LocalError("enable_embeds must be 0 or 1", w, r, u)
} }
if sEnableEmbeds != r.FormValue("o_enable_embeds") { if sEnableEmbeds != r.FormValue("o_enable_embeds") {
err = user.UpdatePrivacy(enableEmbeds) err = u.UpdatePrivacy(enableEmbeds)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
@ -622,17 +626,17 @@ func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, user *c.Us
return nil return nil
} }
func AccountEditEmail(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError { func AccountEditEmail(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
accountEditHead("account_email", w, r, user, h) accountEditHead("account_email", w, r, u, h)
emails, err := c.Emails.GetEmailsByUser(user) emails, err := c.Emails.GetEmailsByUser(u)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// Was this site migrated from another forum software? Most of them don't have multiple emails for a single user. // Was this site migrated from another forum software? Most of them don't have multiple emails for a single user.
// This also applies when the admin switches site.EnableEmails on after having it off for a while. // This also applies when the admin switches site.EnableEmails on after having it off for a while.
if len(emails) == 0 && user.Email != "" { if len(emails) == 0 && u.Email != "" {
emails = append(emails, c.Email{UserID: user.ID, Email: user.Email, Validated: false, Primary: true}) emails = append(emails, c.Email{UserID: u.ID, Email: u.Email, Validated: false, Primary: true})
} }
if !c.Site.EnableEmails { if !c.Site.EnableEmails {
@ -677,22 +681,22 @@ func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user *c.U
return nil return nil
} }
func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
headerLite, _ := c.SimpleUserCheck(w, r, user) headerLite, _ := c.SimpleUserCheck(w, r, u)
email := r.PostFormValue("email") email := r.PostFormValue("email")
// Quick and dirty check // Quick and dirty check
_, err := c.Emails.Get(user, email) _, err := c.Emails.Get(u, email)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return c.LocalError("This email isn't set on this user.", w, r, user) return c.LocalError("This email isn't set on this user.", w, r, u)
} else if err != nil { } else if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
if headerLite.Settings["activation_type"] == 2 && user.Email == email { if headerLite.Settings["activation_type"] == 2 && u.Email == email {
return c.LocalError("You can't remove your primary email when mandatory email activation is enabled.", w, r, user) return c.LocalError("You can't remove your primary email when mandatory email activation is enabled.", w, r, u)
} }
err = c.Emails.Delete(user.ID, email) err = c.Emails.Delete(u.ID, email)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }

View File

@ -1164,7 +1164,7 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user *c.User) c.Rou
} }
vList = append(vList, viewList) vList = append(vList, viewList)
legendList = append(legendList, lName) legendList = append(legendList, lName)
if i >= 6 { if i >= 7 {
break break
} }
i++ i++

View File

@ -5,13 +5,13 @@
<span id="dash_username"> <span id="dash_username">
<form id="dash_username_form" action="/user/edit/username/submit/?s={{.CurrentUser.Session}}" method="post"></form> <form id="dash_username_form" action="/user/edit/username/submit/?s={{.CurrentUser.Session}}" method="post"></form>
<form id="revoke_avatar_form" action="/user/edit/avatar/revoke/submit/?s={{.CurrentUser.Session}}" method="post"></form> <form id="revoke_avatar_form" action="/user/edit/avatar/revoke/submit/?s={{.CurrentUser.Session}}" method="post"></form>
<input form="dash_username_form" name="account-new-username" value="{{.CurrentUser.Name}}"/> <input form="dash_username_form" name="new-name" value="{{.CurrentUser.Name}}">
<button form="dash_username_form" class="formbutton">{{lang "account_username_save"}}</button> <button form="dash_username_form" class="formbutton">{{lang "account_username_save"}}</button>
</span> </span>
<img src="{{.CurrentUser.Avatar}}"height="128px"> <img src="{{.CurrentUser.Avatar}}"height="128px">
<span id="dash_avatar_buttons"> <span id="dash_avatar_buttons">
{{if .CurrentUser.Perms.UploadAvatars}} {{if .CurrentUser.Perms.UploadAvatars}}
<input form="avatar_form" id="select_avatar" name="account-avatar" type="file" required class="auto_hide"/> <input form="avatar_form" id="select_avatar" name="account-avatar" type="file" required class="auto_hide">
<label for="select_avatar" class="formbutton">{{lang "account_avatar_select"}}</label> <label for="select_avatar" class="formbutton">{{lang "account_avatar_select"}}</label>
<button form="avatar_form" name="account-button" class="formbutton">{{lang "account_avatar_update_button"}}</button> <button form="avatar_form" name="account-button" class="formbutton">{{lang "account_avatar_update_button"}}</button>
{{else if .CurrentUser.RawAvatar}}<button form="revoke_avatar_form" id="revoke_avatars" name="revoke-button" class="formbutton">{{lang "account_avatar_revoke_button"}}</button>{{end}} {{else if .CurrentUser.RawAvatar}}<button form="revoke_avatar_form" id="revoke_avatars" name="revoke-button" class="formbutton">{{lang "account_avatar_revoke_button"}}</button>{{end}}

View File

@ -7,11 +7,11 @@
<form action="/accounts/login/submit/" method="post"> <form action="/accounts/login/submit/" method="post">
<div class="formrow login_name_row"> <div class="formrow login_name_row">
<div class="formitem formlabel"><a id="login_name_label">{{lang "login_account_name"}}</a></div> <div class="formitem formlabel"><a id="login_name_label">{{lang "login_account_name"}}</a></div>
<div class="formitem"><input name="username" type="text" placeholder="{{lang "login_account_name"}}" aria-labelledby="login_name_label" required /></div> <div class="formitem"><input name="username"type="text"placeholder="{{lang "login_account_name"}}" aria-labelledby="login_name_label" required></div>
</div> </div>
<div class="formrow login_password_row"> <div class="formrow login_password_row">
<div class="formitem formlabel"><a id="login_password_label">{{lang "login_account_password"}}</a></div> <div class="formitem formlabel"><a id="login_password_label">{{lang "login_account_password"}}</a></div>
<div class="formitem"><input name="password" type="password" autocomplete="current-password" placeholder="*****" aria-labelledby="login_password_label" required /></div> <div class="formitem"><input name="password"type="password"autocomplete="current-password"placeholder="*****"aria-labelledby="login_password_label" required></div>
</div> </div>
<div class="formrow login_button_row form_button_row"> <div class="formrow login_button_row form_button_row">
<div class="formitem"><button name="login-button" class="formbutton">{{lang "login_submit_button"}}</button></div> <div class="formitem"><button name="login-button" class="formbutton">{{lang "login_submit_button"}}</button></div>