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
mOrder := "mid, name, htmlID, cssClass, position, path, aria, tooltip, guestOnly, memberOnly, staffOnly, adminOnly"
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)
qgen.Install.SimpleInsert("menu_items", cols+", order", values+","+strconv.Itoa(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
}
@ -347,7 +362,7 @@ func writeInsertInnerJoins(a qgen.Adapter) error {
return nil
}
func writeFile(name string, content string) (err error) {
func writeFile(name, content string) (err error) {
f, err := os.Create(name)
if err != nil {
return err

View File

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

View File

@ -223,13 +223,13 @@
"alexa":"Alexa",
"lynx":"Lynx",
"semrush":"SemrushBot",
"semrush":"Semrush",
"dotbot":"DotBot",
"ahrefs":"Ahrefs",
"proximic":"Comscore",
"majestic":"MJ12bot",
"blexbot":"BLEXBot",
"aspiegel":"AspiegelBot",
"aspiegel":"Aspiegel",
"mail_ru":"Mail.ru bot",
"zgrab":"Zgrab App Scanner",
"curl":"curl",
@ -341,7 +341,7 @@
"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_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_verify_success":"Your email was successfully verified.",
"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: Test this
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)
ChangeColumn(name, table, colName string, col DBTableColumn) (string, error)
SetDefaultColumn(name, table, colName, colType, defaultStr string) (string, error)
AddIndex(name, table, iname, colname string) (string, error)
AddKey(name, table, col string, key DBTableKey) (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)
SimpleBulkInsert(name, table, cols string, fieldSet []string) (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
var tList []interface{}
func AccountLogin(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError {
if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user)
func AccountLogin(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
if u.Loggedin {
return c.LocalError("You're already logged in.", w, r, u)
}
h.Title = p.GetTitlePhrase("login")
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 {
bProvSession := []byte(provSession)
bSignedSession := []byte(signedSession)
bUid := []byte(strconv.Itoa(uid))
h := sha256.New()
h.Write([]byte(c.SessionSigningKeyBox.Load().(string)))
h.Write([]byte(provSession))
h.Write([]byte(strconv.Itoa(uid)))
h.Write(bProvSession)
h.Write(bUid)
expected := hex.EncodeToString(h.Sum(nil))
if subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1 {
if subtle.ConstantTimeCompare(bSignedSession, []byte(expected)) == 1 {
return true
}
h = sha256.New()
h.Write([]byte(c.OldSessionSigningKeyBox.Load().(string)))
h.Write([]byte(provSession))
h.Write([]byte(strconv.Itoa(uid)))
h.Write(bProvSession)
h.Write(bUid)
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 {
@ -354,26 +358,26 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user *c.User)
}
// 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.Path = "/user/edit/"
h.AddSheet(h.Theme.Name + "/account.css")
h.AddScriptAsync("account.js")
}
func AccountEdit(w http.ResponseWriter, r *http.Request, user *c.User, header *c.Header) c.RouteError {
accountEditHead("account", w, r, user, header)
func AccountEdit(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
accountEditHead("account", w, r, u, h)
if r.FormValue("avatar_updated") == "1" {
header.AddNotice("account_avatar_updated")
} else if r.FormValue("username_updated") == "1" {
header.AddNotice("account_username_updated")
h.AddNotice("account_avatar_updated")
} else if r.FormValue("name_updated") == "1" {
h.AddNotice("account_name_updated")
} 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
mfaSetup := false
_, err := c.MFAstore.Get(user.ID)
_, err := c.MFAstore.Get(u.ID)
if err != sql.ErrNoRows && err != nil {
return c.InternalError(err, w, r)
} 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
prevScore := c.GetLevelScore(user.Level)
currentScore := user.Score - prevScore
nextScore := c.GetLevelScore(user.Level+1) - prevScore
prevScore := c.GetLevelScore(u.Level)
currentScore := u.Score - prevScore
nextScore := c.GetLevelScore(u.Level+1) - prevScore
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}}
return renderTemplate("account", w, r, header, pi)
pi := c.Account{h, "dashboard", "account_own_edit", c.AccountDashPage{h, mfaSetup, currentScore, nextScore, u.Level + 1, perc * 2}}
return renderTemplate("account", w, r, h, pi)
}
//edit_password
@ -481,16 +485,16 @@ func AccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, u *c.User
return ferr
}
newUsername := c.SanitiseSingleLine(r.PostFormValue("account-new-username"))
if newUsername == "" {
newName := c.SanitiseSingleLine(r.PostFormValue("new-name"))
if newName == "" {
return c.LocalError("You can't leave your username blank", w, r, u)
}
err := u.ChangeName(newUsername)
err := u.ChangeName(newName)
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
}
@ -568,18 +572,18 @@ func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user *c.U
}
// TODO: Implement this
func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
_, ferr := c.SimpleUserCheck(w, r, user)
func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
_, ferr := c.SimpleUserCheck(w, r, u)
if ferr != nil {
return ferr
}
// 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 {
return c.InternalError(err, w, r)
} 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()
@ -603,16 +607,16 @@ func AccountEditPrivacy(w http.ResponseWriter, r *http.Request, u *c.User, h *c.
return renderTemplate("account", w, r, h, pi)
}
func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
//headerLite, _ := c.SimpleUserCheck(w, r, user)
func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
//headerLite, _ := c.SimpleUserCheck(w, r, u)
sEnableEmbeds := r.FormValue("enable_embeds")
enableEmbeds, err := strconv.Atoi(sEnableEmbeds)
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") {
err = user.UpdatePrivacy(enableEmbeds)
err = u.UpdatePrivacy(enableEmbeds)
if err != nil {
return c.InternalError(err, w, r)
}
@ -622,17 +626,17 @@ func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, user *c.Us
return nil
}
func AccountEditEmail(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError {
accountEditHead("account_email", w, r, user, h)
emails, err := c.Emails.GetEmailsByUser(user)
func AccountEditEmail(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
accountEditHead("account_email", w, r, u, h)
emails, err := c.Emails.GetEmailsByUser(u)
if err != nil {
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.
// This also applies when the admin switches site.EnableEmails on after having it off for a while.
if len(emails) == 0 && user.Email != "" {
emails = append(emails, c.Email{UserID: user.ID, Email: user.Email, Validated: false, Primary: true})
if len(emails) == 0 && u.Email != "" {
emails = append(emails, c.Email{UserID: u.ID, Email: u.Email, Validated: false, Primary: true})
}
if !c.Site.EnableEmails {
@ -677,22 +681,22 @@ func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user *c.U
return nil
}
func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
headerLite, _ := c.SimpleUserCheck(w, r, user)
func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
headerLite, _ := c.SimpleUserCheck(w, r, u)
email := r.PostFormValue("email")
// Quick and dirty check
_, err := c.Emails.Get(user, email)
_, err := c.Emails.Get(u, email)
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 {
return c.InternalError(err, w, r)
}
if headerLite.Settings["activation_type"] == 2 && user.Email == email {
return c.LocalError("You can't remove your primary email when mandatory email activation is enabled.", w, r, user)
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, u)
}
err = c.Emails.Delete(user.ID, email)
err = c.Emails.Delete(u.ID, email)
if err != nil {
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)
legendList = append(legendList, lName)
if i >= 6 {
if i >= 7 {
break
}
i++

View File

@ -5,13 +5,13 @@
<span id="dash_username">
<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>
<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>
</span>
<img src="{{.CurrentUser.Avatar}}"height="128px">
<span id="dash_avatar_buttons">
{{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>
<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}}

View File

@ -7,11 +7,11 @@
<form action="/accounts/login/submit/" method="post">
<div class="formrow login_name_row">
<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 class="formrow login_password_row">
<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 class="formrow login_button_row form_button_row">
<div class="formitem"><button name="login-button" class="formbutton">{{lang "login_submit_button"}}</button></div>