Add UseConvos permission.

Use UseConvos permission instead of ban flags in convo perm checks.
Stop users without the UseConvos permission from editing convo replies, although they can still delete them for privacy reasons.

Shorten some things and reduce the amount of boilerplate.
Add a few misc parser test cases.
Fix footer and tweak indentation.
This commit is contained in:
Azareal 2019-10-06 10:34:09 +10:00
parent ff48ec9d86
commit 5705252029
24 changed files with 868 additions and 1044 deletions

View File

@ -8,15 +8,14 @@ import (
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
// TODO: Make sure all the errors in this file propagate upwards properly // TODO: Make sure all the errors in this file propagate upwards properly
func main() { func main() {
// Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows // Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows
defer func() { defer func() {
r := recover() if r := recover(); r != nil {
if r != nil {
fmt.Println(r) fmt.Println(r)
debug.PrintStack() debug.PrintStack()
return return
@ -109,6 +108,8 @@ func writeStatements(adapter qgen.Adapter) error {
return nil return nil
} }
type si = map[string]interface{}
func seedTables(adapter qgen.Adapter) error { func seedTables(adapter qgen.Adapter) error {
qgen.Install.AddIndex("topics", "parentID", "parentID") qgen.Install.AddIndex("topics", "parentID", "parentID")
qgen.Install.AddIndex("replies", "tid", "tid") qgen.Install.AddIndex("replies", "tid", "tid")
@ -156,6 +157,9 @@ func seedTables(adapter qgen.Adapter) error {
Non-staff Global Permissions: Non-staff Global Permissions:
UploadFiles UploadFiles
UploadAvatars UploadAvatars
UseConvos
// CreateConvo ?
// CreateConvoReply ?
Forum Permissions: Forum Permissions:
ViewTopic ViewTopic
@ -172,11 +176,11 @@ func seedTables(adapter qgen.Adapter) error {
*/ */
// TODO: Set the permissions on a struct and then serialize the struct and insert that instead of writing raw JSON // TODO: Set the permissions on a struct and then serialize the struct and insert that instead of writing raw JSON
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, tag", `'Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,"Admin"`) qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, tag", `'Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,"Admin"`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, tag", `'Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,"Mod"`) qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, tag", `'Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,"Mod"`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms", `'Member','{"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'`) qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms", `'Member','{"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_banned", `'Banned','{"ViewTopic":true}','{}',1`) qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_banned", `'Banned','{"ViewTopic":true}','{}',1`)
@ -223,31 +227,31 @@ func seedTables(adapter qgen.Adapter) error {
qgen.Install.SimpleInsert("menus", "", "") qgen.Install.SimpleInsert("menus", "", "")
// Go maps have a random iteration order, so we have to do this, otherwise the schema files will become unstable and harder to audit // Go maps have a random iteration order, so we have to do this, otherwise the schema files will become unstable and harder to audit
var order = 0 order := 0
var 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"
var addMenuItem = func(data map[string]interface{}) { addMenuItem := func(data map[string]interface{}) {
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(map[string]interface{}{"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{"mid": 1, "name": "{lang.menu_forums}", "htmlID": "menu_forums", "position": "left", "path": "/forums/", "aria": "{lang.menu_forums_aria}", "tooltip": "{lang.menu_forums_tooltip}"})
addMenuItem(map[string]interface{}{"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{"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(map[string]interface{}{"mid": 1, "htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"}) addMenuItem(si{"mid": 1, "htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"})
addMenuItem(map[string]interface{}{"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{"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(map[string]interface{}{"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{"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(map[string]interface{}{"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{"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(map[string]interface{}{"mid": 1, "name": "{lang.menu_logout}", "cssClass": "menu_logout", "position": "left", "path": "/accounts/logout/?session={me.Session}", "aria": "{lang.menu_logout_aria}", "tooltip": "{lang.menu_logout_tooltip}", "memberOnly": 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(map[string]interface{}{"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{"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(map[string]interface{}{"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{"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})
return nil return nil
} }
@ -263,77 +267,77 @@ func seedTables(adapter qgen.Adapter) error {
type LitStr string type LitStr string
func writeSelects(adapter qgen.Adapter) error { func writeSelects(a qgen.Adapter) error {
build := adapter.Builder() b := a.Builder()
// Looking for getTopic? Your statement is in another castle // Looking for getTopic? Your statement is in another castle
//build.Select("isPluginInstalled").Table("plugins").Columns("installed").Where("uname = ?").Parse() //b.Select("isPluginInstalled").Table("plugins").Columns("installed").Where("uname = ?").Parse()
build.Select("forumEntryExists").Table("forums").Columns("fid").Where("name = ''").Orderby("fid ASC").Limit("0,1").Parse() b.Select("forumEntryExists").Table("forums").Columns("fid").Where("name = ''").Orderby("fid ASC").Limit("0,1").Parse()
build.Select("groupEntryExists").Table("users_groups").Columns("gid").Where("name = ''").Orderby("gid ASC").Limit("0,1").Parse() b.Select("groupEntryExists").Table("users_groups").Columns("gid").Where("name = ''").Orderby("gid ASC").Limit("0,1").Parse()
return nil return nil
} }
func writeLeftJoins(adapter qgen.Adapter) error { func writeLeftJoins(a qgen.Adapter) error {
adapter.SimpleLeftJoin("getForumTopics", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "topics.parentID = ?", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc", "") a.SimpleLeftJoin("getForumTopics", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "topics.parentID = ?", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc", "")
return nil return nil
} }
func writeInnerJoins(adapter qgen.Adapter) (err error) { func writeInnerJoins(a qgen.Adapter) (err error) {
return nil return nil
} }
func writeInserts(adapter qgen.Adapter) error { func writeInserts(a qgen.Adapter) error {
build := adapter.Builder() b := a.Builder()
build.Insert("addForumPermsToForum").Table("forums_permissions").Columns("gid,fid,preset,permissions").Fields("?,?,?,?").Parse() b.Insert("addForumPermsToForum").Table("forums_permissions").Columns("gid,fid,preset,permissions").Fields("?,?,?,?").Parse()
return nil return nil
} }
func writeUpdates(adapter qgen.Adapter) error { func writeUpdates(a qgen.Adapter) error {
build := adapter.Builder() b := a.Builder()
build.Update("updateEmail").Table("emails").Set("email = ?, uid = ?, validated = ?, token = ?").Where("email = ?").Parse() b.Update("updateEmail").Table("emails").Set("email = ?, uid = ?, validated = ?, token = ?").Where("email = ?").Parse()
build.Update("setTempGroup").Table("users").Set("temp_group = ?").Where("uid = ?").Parse() b.Update("setTempGroup").Table("users").Set("temp_group = ?").Where("uid = ?").Parse()
build.Update("bumpSync").Table("sync").Set("last_update = UTC_TIMESTAMP()").Parse() b.Update("bumpSync").Table("sync").Set("last_update = UTC_TIMESTAMP()").Parse()
return nil return nil
} }
func writeDeletes(adapter qgen.Adapter) error { func writeDeletes(a qgen.Adapter) error {
build := adapter.Builder() b := a.Builder()
//build.Delete("deleteForumPermsByForum").Table("forums_permissions").Where("fid = ?").Parse() //b.Delete("deleteForumPermsByForum").Table("forums_permissions").Where("fid = ?").Parse()
build.Delete("deleteActivityStreamMatch").Table("activity_stream_matches").Where("watcher = ? AND asid = ?").Parse() b.Delete("deleteActivityStreamMatch").Table("activity_stream_matches").Where("watcher = ? AND asid = ?").Parse()
//build.Delete("deleteActivityStreamMatchesByWatcher").Table("activity_stream_matches").Where("watcher = ?").Parse() //b.Delete("deleteActivityStreamMatchesByWatcher").Table("activity_stream_matches").Where("watcher = ?").Parse()
return nil return nil
} }
func writeSimpleCounts(adapter qgen.Adapter) error { func writeSimpleCounts(a qgen.Adapter) error {
return nil return nil
} }
func writeInsertSelects(adapter qgen.Adapter) error { func writeInsertSelects(a qgen.Adapter) error {
/*adapter.SimpleInsertSelect("addForumPermsToForumAdmins", /*a.SimpleInsertSelect("addForumPermsToForumAdmins",
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""},
)*/ )*/
/*adapter.SimpleInsertSelect("addForumPermsToForumStaff", /*a.SimpleInsertSelect("addForumPermsToForumStaff",
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""},
)*/ )*/
/*adapter.SimpleInsertSelect("addForumPermsToForumMembers", /*a.SimpleInsertSelect("addForumPermsToForumMembers",
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
)*/ )*/
@ -342,11 +346,11 @@ func writeInsertSelects(adapter qgen.Adapter) error {
} }
// nolint // nolint
func writeInsertLeftJoins(adapter qgen.Adapter) error { func writeInsertLeftJoins(a qgen.Adapter) error {
return nil return nil
} }
func writeInsertInnerJoins(adapter qgen.Adapter) error { func writeInsertInnerJoins(a qgen.Adapter) error {
return nil return nil
} }

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"log" "log"
"github.com/Azareal/Gosora/query_gen"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
qgen "github.com/Azareal/Gosora/query_gen"
) )
// TODO: Refactor the perms system // TODO: Refactor the perms system
@ -39,6 +39,7 @@ var GlobalPermList = []string{
"ViewIPs", "ViewIPs",
"UploadFiles", "UploadFiles",
"UploadAvatars", "UploadAvatars",
"UseConvos",
} }
// Permission Structure: ActionComponent[Subcomponent]Flag // Permission Structure: ActionComponent[Subcomponent]Flag
@ -65,8 +66,9 @@ type Perms struct {
ViewIPs bool ViewIPs bool
// Global non-staff permissions // Global non-staff permissions
UploadFiles bool UploadFiles bool
UploadAvatars bool UploadAvatars bool
UseConvos bool
// Forum permissions // Forum permissions
ViewTopic bool ViewTopic bool
@ -91,7 +93,7 @@ type Perms struct {
func init() { func init() {
BlankPerms = Perms{ BlankPerms = Perms{
//ExtData: make(map[string]bool), //ExtData: make(map[string]bool),
} }
GuestPerms = Perms{ GuestPerms = Perms{
@ -120,8 +122,9 @@ func init() {
ViewAdminLogs: true, ViewAdminLogs: true,
ViewIPs: true, ViewIPs: true,
UploadFiles: true, UploadFiles: true,
UploadAvatars: true, UploadAvatars: true,
UseConvos: true,
ViewTopic: true, ViewTopic: true,
LikeItem: true, LikeItem: true,
@ -188,7 +191,7 @@ func RebuildGroupPermissions(group *Group) error {
} }
tmpPerms := Perms{ tmpPerms := Perms{
//ExtData: make(map[string]bool), //ExtData: make(map[string]bool),
} }
err = json.Unmarshal(permstr, &tmpPerms) err = json.Unmarshal(permstr, &tmpPerms)
if err != nil { if err != nil {

View File

@ -54,14 +54,14 @@ func init() {
}) })
} }
func (setting *Setting) Copy() (out *Setting) { func (s *Setting) Copy() (out *Setting) {
out = &Setting{Name: ""} out = &Setting{Name: ""}
*out = *setting *out = *s
return out return out
} }
func LoadSettings() error { func LoadSettings() error {
var sBox = SettingMap(make(map[string]interface{})) sBox := SettingMap(make(map[string]interface{}))
settings, err := sBox.BypassGetAll() settings, err := sBox.BypassGetAll()
if err != nil { if err != nil {
return err return err
@ -122,9 +122,9 @@ func (sBox SettingMap) ParseSetting(sname string, scontent string, stype string,
} }
func (sBox SettingMap) BypassGet(name string) (*Setting, error) { func (sBox SettingMap) BypassGet(name string) (*Setting, error) {
setting := &Setting{Name: name} s := &Setting{Name: name}
err := settingStmts.get.QueryRow(name).Scan(&setting.Content, &setting.Type, &setting.Constraint) err := settingStmts.get.QueryRow(name).Scan(&s.Content, &s.Type, &s.Constraint)
return setting, err return s, err
} }
func (sBox SettingMap) BypassGetAll() (settingList []*Setting, err error) { func (sBox SettingMap) BypassGetAll() (settingList []*Setting, err error) {
@ -135,18 +135,18 @@ func (sBox SettingMap) BypassGetAll() (settingList []*Setting, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
setting := &Setting{Name: ""} s := &Setting{Name: ""}
err := rows.Scan(&setting.Name, &setting.Content, &setting.Type, &setting.Constraint) err := rows.Scan(&s.Name, &s.Content, &s.Type, &s.Constraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
settingList = append(settingList, setting) settingList = append(settingList, s)
} }
return settingList, rows.Err() return settingList, rows.Err()
} }
func (sBox SettingMap) Update(name string, content string) RouteError { func (sBox SettingMap) Update(name string, content string) RouteError {
setting, err := sBox.BypassGet(name) s, err := sBox.BypassGet(name)
if err == ErrNoRows { if err == ErrNoRows {
return FromError(err) return FromError(err)
} else if err != nil { } else if err != nil {
@ -154,7 +154,7 @@ func (sBox SettingMap) Update(name string, content string) RouteError {
} }
// TODO: Why is this here and not in a common function? // TODO: Why is this here and not in a common function?
if setting.Type == "bool" { if s.Type == "bool" {
if content == "on" || content == "1" { if content == "on" || content == "1" {
content = "1" content = "1"
} else { } else {
@ -162,7 +162,7 @@ func (sBox SettingMap) Update(name string, content string) RouteError {
} }
} }
err = sBox.ParseSetting(name, content, setting.Type, setting.Constraint) err = sBox.ParseSetting(name, content, s.Type, s.Constraint)
if err != nil { if err != nil {
return FromError(err) return FromError(err)
} }

View File

@ -374,8 +374,7 @@ func BenchmarkBadRouteGuestRouteParallelWithRouter(b *testing.B) {
func binit(b *testing.B) { func binit(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@ -785,8 +784,7 @@ func BenchmarkRoutesSerial(b *testing.B) {
func BenchmarkQueryTopicParallel(b *testing.B) { func BenchmarkQueryTopicParallel(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -807,8 +805,7 @@ func BenchmarkQueryTopicParallel(b *testing.B) {
func BenchmarkQueryPreparedTopicParallel(b *testing.B) { func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -836,8 +833,7 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
func BenchmarkUserGet(b *testing.B) { func BenchmarkUserGet(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -855,8 +851,7 @@ func BenchmarkUserGet(b *testing.B) {
func BenchmarkUserBypassGet(b *testing.B) { func BenchmarkUserBypassGet(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -972,149 +967,62 @@ func BenchmarkParserSerial(b *testing.B) {
func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) { func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { f := func(name string, msg string) {
for i := 0; i < b.N; i++ { b.Run(name, func(b *testing.B) {
_ = bbcodeRegexParse("") for i := 0; i < b.N; i++ {
} _ = bbcodeRegexParse(msg)
}) }
b.Run("short_post", func(b *testing.B) { })
for i := 0; i < b.N; i++ { }
_ = bbcodeRegexParse("Hey everyone, how's it going?") f("empty_post","")
} f("short_post","Hey everyone, how's it going?")
}) f("one_smily","Hey everyone, how's it going? :)")
b.Run("one_smily", func(b *testing.B) { f("five_smilies","Hey everyone, how's it going? :):):):):)")
for i := 0; i < b.N; i++ { f("ten_smilies","Hey everyone, how's it going? :):):):):):):):):):)")
_ = bbcodeRegexParse("Hey everyone, how's it going? :)") f("twenty_smilies","Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
} f("one_bold","[b]H[/b]ey everyone, how's it going?")
}) f("five_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
b.Run("five_smilies", func(b *testing.B) { f("ten_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
b.Run("one_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("[b]H[/b]ey everyone, how's it going?")
}
})
b.Run("five_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
}
})
b.Run("ten_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeRegexParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
}
})
} }
func BenchmarkBBCodePluginWithoutCodeTagSerial(b *testing.B) { func BenchmarkBBCodePluginWithoutCodeTagSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { f := func(name string, msg string) {
for i := 0; i < b.N; i++ { b.Run(name, func(b *testing.B) {
_ = bbcodeParseWithoutCode("") for i := 0; i < b.N; i++ {
} _ = bbcodeParseWithoutCode(msg)
}) }
b.Run("short_post", func(b *testing.B) { })
for i := 0; i < b.N; i++ { }
_ = bbcodeParseWithoutCode("Hey everyone, how's it going?") f("empty_post","")
} f("short_post","Hey everyone, how's it going?")
}) f("one_smily","Hey everyone, how's it going? :)")
b.Run("one_smily", func(b *testing.B) { f("five_smilies","Hey everyone, how's it going? :):):):):)")
for i := 0; i < b.N; i++ { f("ten_smilies","Hey everyone, how's it going? :):):):):):):):):):)")
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :)") f("twenty_smilies","Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
} f("one_bold","[b]H[/b]ey everyone, how's it going?")
}) f("five_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
b.Run("five_smilies", func(b *testing.B) { f("ten_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
b.Run("one_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("[b]H[/b]ey everyone, how's it going?")
}
})
b.Run("five_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
}
})
b.Run("ten_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeParseWithoutCode("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
}
})
} }
func BenchmarkBBCodePluginWithFullParserSerial(b *testing.B) { func BenchmarkBBCodePluginWithFullParserSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { f := func(name string, msg string) {
for i := 0; i < b.N; i++ { b.Run(name, func(b *testing.B) {
_ = bbcodeFullParse("") for i := 0; i < b.N; i++ {
} _ = bbcodeFullParse(msg)
}) }
b.Run("short_post", func(b *testing.B) { })
for i := 0; i < b.N; i++ { }
_ = bbcodeFullParse("Hey everyone, how's it going?") f("empty_post","")
} f("short_post","Hey everyone, how's it going?")
}) f("one_smily","Hey everyone, how's it going? :)")
b.Run("one_smily", func(b *testing.B) { f("five_smilies","Hey everyone, how's it going? :):):):):)")
for i := 0; i < b.N; i++ { f("ten_smilies","Hey everyone, how's it going? :):):):):):):):):):)")
_ = bbcodeFullParse("Hey everyone, how's it going? :)") f("twenty_smilies","Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
} f("one_bold","[b]H[/b]ey everyone, how's it going?")
}) f("five_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
b.Run("five_smilies", func(b *testing.B) { f("ten_bold","[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
b.Run("one_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("[b]H[/b]ey everyone, how's it going?")
}
})
b.Run("five_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
}
})
b.Run("ten_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcodeFullParse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
}
})
} }
func TestLevels(t *testing.T) { func TestLevels(t *testing.T) {
@ -1209,19 +1117,19 @@ func TestForumsAdminRoute(t *testing.T) {
if !admin.Is_Admin { if !admin.Is_Admin {
t.Fatal("UID1 is not an admin") t.Fatal("UID1 is not an admin")
} }
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year} adminUidCookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year} adminSessionCookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
forums_w := httptest.NewRecorder() forumsW := httptest.NewRecorder()
forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil)) forumsReq := httptest.NewRequest("get","/forums/",bytes.NewReader(nil))
forums_req_admin := forums_req forumsReqAdmin := forums_req
forums_req_admin.AddCookie(&admin_uid_cookie) forumsReqAdmin.AddCookie(&adminUidCookie)
forums_req_admin.AddCookie(&admin_session_cookie) forumsReqAdmin.AddCookie(&adminSessionCookie)
forums_handler := http.HandlerFunc(route_forums) forumsHandler := http.HandlerFunc(route_forums)
forums_handler.ServeHTTP(forums_w,forums_req_admin) forumsHandler.ServeHTTP(forumsW,forumsReqAdmin)
if forums_w.Code != 200 { if forumsW.Code != 200 {
t.Fatal(forums_w.Body) t.Fatal(forumsW.Body)
} }
} }
@ -1316,7 +1224,7 @@ func TestForumsGuestRoute(t *testing.T) {
func TestSplittyThing(t *testing.T) { func TestSplittyThing(t *testing.T) {
var extraData string var extraData string
var path = "/pages/hohoho" path := "/pages/hohoho"
t.Log("Raw Path:", path) t.Log("Raw Path:", path)
if path[len(path)-1] != '/' { if path[len(path)-1] != '/' {
extraData = path[strings.LastIndexByte(path, '/')+1:] extraData = path[strings.LastIndexByte(path, '/')+1:]

View File

@ -29,7 +29,8 @@
"ViewIPs": "Can view IP addresses", "ViewIPs": "Can view IP addresses",
"UploadFiles": "Can upload files", "UploadFiles": "Can upload files",
"UploadAvatars": "Can upload avatars" "UploadAvatars": "Can upload avatars",
"UseConvos":"Can use conversations"
}, },
"LocalPerms": { "LocalPerms": {

55
main.go
View File

@ -25,8 +25,8 @@ import (
"time" "time"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" co "github.com/Azareal/Gosora/common/counters"
"github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
"github.com/Azareal/Gosora/routes" "github.com/Azareal/Gosora/routes"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -143,40 +143,33 @@ func storeInit() (err error) {
return errors.WithStack(err) return errors.WithStack(err)
} }
err = phrases.InitPhrases(c.Site.Language) if err = p.InitPhrases(c.Site.Language); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
err = c.InitEmoji() if err = c.InitEmoji(); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
log.Print("Loading the static files.") log.Print("Loading the static files.")
err = c.Themes.LoadStaticFiles() if err = c.Themes.LoadStaticFiles(); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
err = c.StaticFiles.Init() if err = c.StaticFiles.Init(); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
err = c.StaticFiles.JSTmplInit() if err = c.StaticFiles.JSTmplInit(); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
log.Print("Initialising the widgets") log.Print("Initialising the widgets")
c.Widgets = c.NewDefaultWidgetStore() c.Widgets = c.NewDefaultWidgetStore()
err = c.InitWidgets() if err = c.InitWidgets(); err != nil {
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
log.Print("Initialising the menu item list") log.Print("Initialising the menu item list")
c.Menus = c.NewDefaultMenuStore() c.Menus = c.NewDefaultMenuStore()
err = c.Menus.Load(1) // 1 = the default menu if err = c.Menus.Load(1); err != nil { // 1 = the default menu
if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
menuHold, err := c.Menus.Get(1) menuHold, err := c.Menus.Get(1)
@ -269,47 +262,47 @@ func storeInit() (err error) {
c.Thumbnailer = c.NewCaireThumbnailer() c.Thumbnailer = c.NewCaireThumbnailer()
log.Print("Initialising the view counters") log.Print("Initialising the view counters")
counters.GlobalViewCounter, err = counters.NewGlobalViewCounter(acc) co.GlobalViewCounter, err = co.NewGlobalViewCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.AgentViewCounter, err = counters.NewDefaultAgentViewCounter(acc) co.AgentViewCounter, err = co.NewDefaultAgentViewCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.OSViewCounter, err = counters.NewDefaultOSViewCounter(acc) co.OSViewCounter, err = co.NewDefaultOSViewCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.LangViewCounter, err = counters.NewDefaultLangViewCounter(acc) co.LangViewCounter, err = co.NewDefaultLangViewCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter(acc) co.RouteViewCounter, err = co.NewDefaultRouteViewCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.PostCounter, err = counters.NewPostCounter() co.PostCounter, err = co.NewPostCounter()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.TopicCounter, err = counters.NewTopicCounter() co.TopicCounter, err = co.NewTopicCounter()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.TopicViewCounter, err = counters.NewDefaultTopicViewCounter() co.TopicViewCounter, err = co.NewDefaultTopicViewCounter()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.ForumViewCounter, err = counters.NewDefaultForumViewCounter() co.ForumViewCounter, err = co.NewDefaultForumViewCounter()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.ReferrerTracker, err = counters.NewDefaultReferrerTracker() co.ReferrerTracker, err = co.NewDefaultReferrerTracker()
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
counters.MemoryCounter, err = counters.NewMemoryCounter(acc) co.MemoryCounter, err = co.NewMemoryCounter(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -422,8 +415,8 @@ func main() {
defer watcher.Close() defer watcher.Close()
go func() { go func() {
var modifiedFileEvent = func(path string) error { modifiedFileEvent := func(path string) error {
var pathBits = strings.Split(path, "\\") pathBits := strings.Split(path, "\\")
if len(pathBits) == 0 { if len(pathBits) == 0 {
return nil return nil
} }
@ -503,7 +496,7 @@ func main() {
var lastEvictedCount int var lastEvictedCount int
var couldNotDealloc bool var couldNotDealloc bool
var secondTicker = time.NewTicker(time.Second) secondTicker := time.NewTicker(time.Second)
for { for {
select { select {
case <-secondTicker.C: case <-secondTicker.C:
@ -576,7 +569,7 @@ func main() {
func startServer() { func startServer() {
// We might not need the timeouts, if we're behind a reverse-proxy like Nginx // We might not need the timeouts, if we're behind a reverse-proxy like Nginx
var newServer = func(addr string, handler http.Handler) *http.Server { newServer := func(addr string, handler http.Handler) *http.Server {
rtime := c.Config.ReadTimeout rtime := c.Config.ReadTimeout
if rtime == 0 { if rtime == 0 {
rtime = 8 rtime = 8

View File

@ -15,8 +15,7 @@ import (
) )
func miscinit(t *testing.T) { func miscinit(t *testing.T) {
err := gloinit() if err := gloinit(); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -85,7 +84,7 @@ func userStoreTest(t *testing.T, newUserID int) {
user, err := c.Users.Get(1) user, err := c.Users.Get(1)
recordMustExist(t, err, "Couldn't find UID #1") recordMustExist(t, err, "Couldn't find UID #1")
var expectW = func(cond bool, expec bool, prefix string, suffix string) { expectW := func(cond bool, expec bool, prefix string, suffix string) {
midfix := "should not be" midfix := "should not be"
if expec { if expec {
midfix = "should be" midfix = "should be"
@ -94,15 +93,15 @@ func userStoreTest(t *testing.T, newUserID int) {
} }
// TODO: Add email checks too? Do them separately? // TODO: Add email checks too? Do them separately?
var expectUser = func(user *c.User, uid int, name string, group int, super bool, admin bool, mod bool, banned bool) { expectUser := func(u *c.User, uid int, name string, group int, super bool, admin bool, mod bool, banned bool) {
expect(t, user.ID == uid, fmt.Sprintf("user.ID should be %d. Got '%d' instead.", uid, user.ID)) expect(t, u.ID == uid, fmt.Sprintf("u.ID should be %d. Got '%d' instead.", uid, u.ID))
expect(t, user.Name == name, fmt.Sprintf("user.Name should be '%s', not '%s'", name, user.Name)) expect(t, u.Name == name, fmt.Sprintf("u.Name should be '%s', not '%s'", name, u.Name))
expectW(user.Group == group, true, user.Name, "in group"+strconv.Itoa(group)) expectW(u.Group == group, true, u.Name, "in group"+strconv.Itoa(group))
expectW(user.IsSuperAdmin == super, super, user.Name, "a super admin") expectW(u.IsSuperAdmin == super, super, u.Name, "a super admin")
expectW(user.IsAdmin == admin, admin, user.Name, "an admin") expectW(u.IsAdmin == admin, admin, u.Name, "an admin")
expectW(user.IsSuperMod == mod, mod, user.Name, "a super mod") expectW(u.IsSuperMod == mod, mod, u.Name, "a super mod")
expectW(user.IsMod == mod, mod, user.Name, "a mod") expectW(u.IsMod == mod, mod, u.Name, "a mod")
expectW(user.IsBanned == banned, banned, user.Name, "banned") expectW(u.IsBanned == banned, banned, u.Name, "banned")
} }
expectUser(user, 1, "Admin", 1, true, true, true, false) expectUser(user, 1, "Admin", 1, true, true, true, false)
@ -111,7 +110,6 @@ func userStoreTest(t *testing.T, newUserID int) {
if ucache != nil { if ucache != nil {
expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d") expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
_, err = ucache.Get(-1) _, err = ucache.Get(-1)
recordMustNotExist(t, err, "UID #-1 shouldn't exist, even in the cache") recordMustNotExist(t, err, "UID #-1 shouldn't exist, even in the cache")
_, err = ucache.Get(0) _, err = ucache.Get(0)
@ -167,7 +165,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expect(t, isCacheLengthZero(ucache), fmt.Sprintf("User cache length should be 0, not %d", cacheLength(ucache))) expect(t, isCacheLengthZero(ucache), fmt.Sprintf("User cache length should be 0, not %d", cacheLength(ucache)))
expectIntToBeX(t, c.Users.Count(), 1, "The number of users should be one, not %d") expectIntToBeX(t, c.Users.Count(), 1, "The number of users should be one, not %d")
var awaitingActivation = 5 awaitingActivation := 5
// TODO: Write tests for the registration validators // TODO: Write tests for the registration validators
uid, err := c.Users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false) uid, err := c.Users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, false)
expectNilErr(t, err) expectNilErr(t, err)
@ -215,7 +213,7 @@ func userStoreTest(t *testing.T, newUserID int) {
expectIntToBeX(t, user.Group, 5, "Sam should still be in group 5 in this copy") expectIntToBeX(t, user.Group, 5, "Sam should still be in group 5 in this copy")
// ? - What if we change the caching mechanism so it isn't hard purged and reloaded? We'll deal with that when we come to it, but for now, this is a sign of a cache bug // ? - What if we change the caching mechanism so it isn't hard purged and reloaded? We'll deal with that when we come to it, but for now, this is a sign of a cache bug
var afterUserFlush = func(uid int) { afterUserFlush := func(uid int) {
if ucache != nil { if ucache != nil {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d") expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.Get(uid) _, err = ucache.Get(uid)
@ -252,15 +250,15 @@ func userStoreTest(t *testing.T, newUserID int) {
recordMustExist(t, err, "Couldn't find UID #%d", newUserID) recordMustExist(t, err, "Couldn't find UID #%d", newUserID)
expectUser(user, newUserID, "Sam", c.Config.DefaultGroup, false, false, false, false) expectUser(user, newUserID, "Sam", c.Config.DefaultGroup, false, false, false, false)
var reportsForumID = 1 // TODO: Use the constant in common? reportsForumID := 1 // TODO: Use the constant in common?
var generalForumID = 2 generalForumID := 2
dummyResponseRecorder := httptest.NewRecorder() dummyResponseRecorder := httptest.NewRecorder()
bytesBuffer := bytes.NewBuffer([]byte("")) bytesBuffer := bytes.NewBuffer([]byte(""))
dummyRequest1 := httptest.NewRequest("", "/forum/"+strconv.Itoa(reportsForumID), bytesBuffer) dummyRequest1 := httptest.NewRequest("", "/forum/"+strconv.Itoa(reportsForumID), bytesBuffer)
dummyRequest2 := httptest.NewRequest("", "/forum/"+strconv.Itoa(generalForumID), bytesBuffer) dummyRequest2 := httptest.NewRequest("", "/forum/"+strconv.Itoa(generalForumID), bytesBuffer)
var user2 *c.User var user2 *c.User
var changeGroupTest = func(oldGroup int, newGroup int) { changeGroupTest := func(oldGroup int, newGroup int) {
err = user.ChangeGroup(newGroup) err = user.ChangeGroup(newGroup)
expectNilErr(t, err) expectNilErr(t, err)
// ! I don't think ChangeGroup should be changing the value of user... Investigate this. // ! I don't think ChangeGroup should be changing the value of user... Investigate this.
@ -272,7 +270,7 @@ func userStoreTest(t *testing.T, newUserID int) {
*user2 = *user *user2 = *user
} }
var changeGroupTest2 = func(rank string, firstShouldBe bool, secondShouldBe bool) { changeGroupTest2 := func(rank string, firstShouldBe bool, secondShouldBe bool) {
head, err := c.UserCheck(dummyResponseRecorder, dummyRequest1, user) head, err := c.UserCheck(dummyResponseRecorder, dummyRequest1, user)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -490,7 +488,7 @@ func topicStoreTest(t *testing.T, newID int) {
count = c.Topics.Count() count = c.Topics.Count()
expect(t, count == 2, fmt.Sprintf("Global count for topics should be 2, not %d", count)) expect(t, count == 2, fmt.Sprintf("Global count for topics should be 2, not %d", count))
var iFrag = func(cond bool) string { iFrag := func(cond bool) string {
if !cond { if !cond {
return "n't" return "n't"
} }
@ -513,7 +511,7 @@ func topicStoreTest(t *testing.T, newID int) {
} }
tcache := c.Topics.GetCache() tcache := c.Topics.GetCache()
var shouldNotBeIn = func(tid int) { shouldNotBeIn := func(tid int) {
if tcache != nil { if tcache != nil {
_, err = tcache.Get(tid) _, err = tcache.Get(tid)
recordMustNotExist(t, err, "Topic cache should be empty") recordMustNotExist(t, err, "Topic cache should be empty")
@ -581,7 +579,7 @@ func TestForumStore(t *testing.T) {
// TODO: Check the preset and forum permissions // TODO: Check the preset and forum permissions
expect(t, forum.Name == "Reports", fmt.Sprintf("FID #0 is named '%s' and not 'Reports'", forum.Name)) expect(t, forum.Name == "Reports", fmt.Sprintf("FID #0 is named '%s' and not 'Reports'", forum.Name))
expect(t, !forum.Active, fmt.Sprintf("The reports forum shouldn't be active")) expect(t, !forum.Active, fmt.Sprintf("The reports forum shouldn't be active"))
var expectDesc = "All the reports go here" expectDesc := "All the reports go here"
expect(t, forum.Desc == expectDesc, fmt.Sprintf("The forum description should be '%s' not '%s'", expectDesc, forum.Desc)) expect(t, forum.Desc == expectDesc, fmt.Sprintf("The forum description should be '%s' not '%s'", expectDesc, forum.Desc))
forum, err = c.Forums.BypassGet(1) forum, err = c.Forums.BypassGet(1)
recordMustExist(t, err, "Couldn't find FID #1") recordMustExist(t, err, "Couldn't find FID #1")
@ -732,48 +730,24 @@ func TestForumPermsStore(t *testing.T) {
c.InitPlugins() c.InitPlugins()
} }
var initialState = func() { f := func(fid int, gid int, msg string, inv ...bool) {
fid := 1 fp, err := c.FPStore.Get(fid,gid)
gid := 1 expectNilErr(t,err)
fperms, err := c.FPStore.Get(fid,gid) vt := fp.ViewTopic
expectNilErr(t,err) if len(inv) > 0 && inv[0] == true {
expect(t,fperms.ViewTopic,"admins should be able to see reports") vt = !vt
}
expect(t,vt,msg)
}
fid = 1 initialState := func() {
gid = 2 f(1,1,"admins should be able to see reports")
fperms, err = c.FPStore.Get(fid,gid) f(1,2,"mods should be able to see reports")
expectNilErr(t,err) f(1,3,"members should not be able to see reports",true)
expect(t,fperms.ViewTopic,"mods should be able to see reports") f(1,4,"banned users should not be able to see reports",true)
f(2,1,"admins should be able to see general")
fid = 1 f(2,3,"members should be able to see general")
gid = 3 f(2,6,"guests should be able to see general")
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,!fperms.ViewTopic,"members should not be able to see reports")
fid = 1
gid = 4
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,!fperms.ViewTopic,"banned users should not be able to see reports")
fid = 2
gid = 1
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"admins should be able to see general")
fid = 2
gid = 3
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"members should be able to see general")
fid = 2
gid = 6
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"guests should be able to see general")
} }
initialState() initialState()
@ -811,9 +785,9 @@ func TestGroupStore(t *testing.T) {
expect(t, c.Groups.Exists(0), "GID #0 should exist") expect(t, c.Groups.Exists(0), "GID #0 should exist")
expect(t, c.Groups.Exists(1), "GID #1 should exist") expect(t, c.Groups.Exists(1), "GID #1 should exist")
var isAdmin = true isAdmin := true
var isMod = true isMod := true
var isBanned = false isBanned := false
gid, err := c.Groups.Create("Testing", "Test", isAdmin, isMod, isBanned) gid, err := c.Groups.Create("Testing", "Test", isAdmin, isMod, isBanned)
expectNilErr(t, err) expectNilErr(t, err)
expect(t, c.Groups.Exists(gid), "The group we just made doesn't exist") expect(t, c.Groups.Exists(gid), "The group we just made doesn't exist")
@ -1032,7 +1006,7 @@ func TestProfileReplyStore(t *testing.T) {
//err = profileReply.Delete() //err = profileReply.Delete()
//expect(t,err != nil,"You shouldn't be able to delete profile replies which don't exist") //expect(t,err != nil,"You shouldn't be able to delete profile replies which don't exist")
var profileID = 1 profileID := 1
prid, err := c.Prstore.Create(profileID, "Haha", 1, "::1") prid, err := c.Prstore.Create(profileID, "Haha", 1, "::1")
expectNilErr(t, err) expectNilErr(t, err)
expect(t, prid == 1, "The first profile reply should have an ID of 1") expect(t, prid == 1, "The first profile reply should have an ID of 1")
@ -1265,10 +1239,14 @@ func TestPluginManager(t *testing.T) {
} }
func TestPhrases(t *testing.T) { func TestPhrases(t *testing.T) {
expect(t, phrases.GetGlobalPermPhrase("BanUsers") == "Can ban users", "Not the expected phrase") getPhrase := phrases.GetGlobalPermPhrase
expect(t, phrases.GetGlobalPermPhrase("NoSuchPerm") == "{lang.perms[NoSuchPerm]}", "Not the expected phrase") tp := func(name string, expects string) {
expect(t, phrases.GetLocalPermPhrase("ViewTopic") == "Can view topics", "Not the expected phrase") expect(t, getPhrase(name) == expects, "Not the expected phrase")
expect(t, phrases.GetLocalPermPhrase("NoSuchPerm") == "{lang.perms[NoSuchPerm]}", "Not the expected phrase") }
tp("BanUsers","Can ban users")
tp("NoSuchPerm","{lang.perms[NoSuchPerm]}")
tp("ViewTopic","Can view topics")
tp("NoSuchPerm","{lang.perms[NoSuchPerm]}")
// TODO: Cover the other phrase types, also try switching between languages to see if anything strange happens // TODO: Cover the other phrase types, also try switching between languages to see if anything strange happens
} }
@ -1326,34 +1304,33 @@ func TestWordFilters(t *testing.T) {
// TODO: Expand upon the valid characters which can go in URLs? // TODO: Expand upon the valid characters which can go in URLs?
func TestSlugs(t *testing.T) { func TestSlugs(t *testing.T) {
var res string l := &MEPairList{nil}
var msgList = &MEPairList{nil}
c.Config.BuildSlugs = true // Flip this switch, otherwise all the tests will fail c.Config.BuildSlugs = true // Flip this switch, otherwise all the tests will fail
msgList.Add("Unknown", "unknown") l.Add("Unknown", "unknown")
msgList.Add("Unknown2", "unknown2") l.Add("Unknown2", "unknown2")
msgList.Add("Unknown ", "unknown") l.Add("Unknown ", "unknown")
msgList.Add("Unknown 2", "unknown-2") l.Add("Unknown 2", "unknown-2")
msgList.Add("Unknown 2", "unknown-2") l.Add("Unknown 2", "unknown-2")
msgList.Add("Admin Alice", "admin-alice") l.Add("Admin Alice", "admin-alice")
msgList.Add("Admin_Alice", "adminalice") l.Add("Admin_Alice", "adminalice")
msgList.Add("Admin_Alice-", "adminalice") l.Add("Admin_Alice-", "adminalice")
msgList.Add("-Admin_Alice-", "adminalice") l.Add("-Admin_Alice-", "adminalice")
msgList.Add("-Admin@Alice-", "adminalice") l.Add("-Admin@Alice-", "adminalice")
msgList.Add("-Admin😀Alice-", "adminalice") l.Add("-Admin😀Alice-", "adminalice")
msgList.Add("u", "u") l.Add("u", "u")
msgList.Add("", "untitled") l.Add("", "untitled")
msgList.Add(" ", "untitled") l.Add(" ", "untitled")
msgList.Add("-", "untitled") l.Add("-", "untitled")
msgList.Add("--", "untitled") l.Add("--", "untitled")
msgList.Add("é", "é") l.Add("é", "é")
msgList.Add("-é-", "é") l.Add("-é-", "é")
msgList.Add("-你好-", "untitled") l.Add("-你好-", "untitled")
msgList.Add("-こにちは-", "untitled") l.Add("-こにちは-", "untitled")
for _, item := range msgList.Items { for _, item := range l.Items {
t.Log("Testing string '" + item.Msg + "'") t.Log("Testing string '" + item.Msg + "'")
res = c.NameToSlug(item.Msg) res := c.NameToSlug(item.Msg)
if res != item.Expects { if res != item.Expects {
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", item.Expects) t.Error("Expected:", item.Expects)
@ -1523,14 +1500,14 @@ type METriList struct {
Items []METri Items []METri
} }
func (tlist *METriList) Add(args ...string) { func (l *METriList) Add(args ...string) {
if len(args) < 2 { if len(args) < 2 {
panic("need 2 or more args") panic("need 2 or more args")
} }
if len(args) > 2 { if len(args) > 2 {
tlist.Items = append(tlist.Items, METri{args[0], args[1], args[2]}) l.Items = append(l.Items, METri{args[0], args[1], args[2]})
} else { } else {
tlist.Items = append(tlist.Items, METri{"", args[0], args[1]}) l.Items = append(l.Items, METri{"", args[0], args[1]})
} }
} }
@ -1544,37 +1521,36 @@ type CountTestList struct {
Items []CountTest Items []CountTest
} }
func (tlist *CountTestList) Add(name string, msg string, expects int) { func (l *CountTestList) Add(name string, msg string, expects int) {
tlist.Items = append(tlist.Items, CountTest{name, msg, expects}) l.Items = append(l.Items, CountTest{name, msg, expects})
} }
func TestWordCount(t *testing.T) { func TestWordCount(t *testing.T) {
var msgList = &CountTestList{nil} l := &CountTestList{nil}
l.Add("blank", "", 0)
l.Add("single-letter", "h", 1)
l.Add("single-kana", "お", 1)
l.Add("single-letter-words", "h h", 2)
l.Add("two-letter", "h", 1)
l.Add("two-kana", "おは", 1)
l.Add("two-letter-words", "hh hh", 2)
l.Add("", "h,h", 2)
l.Add("", "h,,h", 2)
l.Add("", "h, h", 2)
l.Add("", " h, h", 2)
l.Add("", "h, h ", 2)
l.Add("", " h, h ", 2)
l.Add("", "h, h", 2)
l.Add("", "h\nh", 2)
l.Add("", "h\"h", 2)
l.Add("", "h[r]h", 3)
l.Add("", "お,お", 2)
l.Add("", "お、お", 2)
l.Add("", "お\nお", 2)
l.Add("", "お”お", 2)
l.Add("", "お「あ」お", 3)
msgList.Add("blank", "", 0) for _, item := range l.Items {
msgList.Add("single-letter", "h", 1)
msgList.Add("single-kana", "お", 1)
msgList.Add("single-letter-words", "h h", 2)
msgList.Add("two-letter", "h", 1)
msgList.Add("two-kana", "おは", 1)
msgList.Add("two-letter-words", "hh hh", 2)
msgList.Add("", "h,h", 2)
msgList.Add("", "h,,h", 2)
msgList.Add("", "h, h", 2)
msgList.Add("", " h, h", 2)
msgList.Add("", "h, h ", 2)
msgList.Add("", " h, h ", 2)
msgList.Add("", "h, h", 2)
msgList.Add("", "h\nh", 2)
msgList.Add("", "h\"h", 2)
msgList.Add("", "h[r]h", 3)
msgList.Add("", "お,お", 2)
msgList.Add("", "お、お", 2)
msgList.Add("", "お\nお", 2)
msgList.Add("", "お”お", 2)
msgList.Add("", "お「あ」お", 3)
for _, item := range msgList.Items {
res := c.WordCount(item.Msg) res := c.WordCount(item.Msg)
if res != item.Expects { if res != item.Expects {
if item.Name != "" { if item.Name != "" {

View File

@ -13,114 +13,115 @@ func TestPreparser(t *testing.T) {
if !c.PluginsInited { if !c.PluginsInited {
c.InitPlugins() c.InitPlugins()
} }
var msgList = &METriList{nil} l := &METriList{nil}
// Note: The open tag is evaluated without knowledge of the close tag for efficiency and simplicity, so the parser autofills the associated close tag when it finds an open tag without a partner // Note: The open tag is evaluated without knowledge of the close tag for efficiency and simplicity, so the parser autofills the associated close tag when it finds an open tag without a partner
msgList.Add("", "") l.Add("", "")
msgList.Add(" ", "") l.Add(" ", "")
msgList.Add(" hi", "hi") l.Add(" hi", "hi")
msgList.Add("hi ", "hi") l.Add("hi ", "hi")
msgList.Add("hi", "hi") l.Add("hi", "hi")
msgList.Add(":grinning:", "😀") l.Add(":grinning:", "😀")
msgList.Add("😀", "😀") l.Add("😀", "😀")
msgList.Add("&nbsp;", "") l.Add("&nbsp;", "")
msgList.Add("<p>", "") l.Add("<p>", "")
msgList.Add("</p>", "") l.Add("</p>", "")
msgList.Add("<p></p>", "") l.Add("<p></p>", "")
msgList.Add("<", "&lt;") l.Add("<", "&lt;")
msgList.Add(">", "&gt;") l.Add(">", "&gt;")
msgList.Add("<meow>", "&lt;meow&gt;") l.Add("<meow>", "&lt;meow&gt;")
msgList.Add("&lt;", "&amp;lt;") l.Add("&lt;", "&amp;lt;")
msgList.Add("&", "&amp;") l.Add("&", "&amp;")
// Note: strings.TrimSpace strips newlines, if there's nothing before or after them // Note: strings.TrimSpace strips newlines, if there's nothing before or after them
msgList.Add("<br>", "") l.Add("<br>", "")
msgList.Add("<br />", "") l.Add("<br />", "")
msgList.Add("\\n", "\n", "") l.Add("\\n", "\n", "")
msgList.Add("\\n\\n", "\n\n", "") l.Add("\\n\\n", "\n\n", "")
msgList.Add("\\n\\n\\n", "\n\n\n", "") l.Add("\\n\\n\\n", "\n\n\n", "")
msgList.Add("\\r\\n", "\r\n", "") // Windows style line ending l.Add("\\r\\n", "\r\n", "") // Windows style line ending
msgList.Add("\\n\\r", "\n\r", "") l.Add("\\n\\r", "\n\r", "")
msgList.Add("ho<br>ho", "ho\n\nho") l.Add("ho<br>ho", "ho\n\nho")
msgList.Add("ho<br />ho", "ho\n\nho") l.Add("ho<br />ho", "ho\n\nho")
msgList.Add("ho\\nho", "ho\nho", "ho\nho") l.Add("ho\\nho", "ho\nho", "ho\nho")
msgList.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho") l.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho")
//msgList.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho") //l.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho")
msgList.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending l.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending
msgList.Add("ho\\n\\rho", "ho\n\rho", "ho\nho") l.Add("ho\\n\\rho", "ho\n\rho", "ho\nho")
msgList.Add("<b></b>", "<strong></strong>") l.Add("<b></b>", "<strong></strong>")
msgList.Add("<b>hi</b>", "<strong>hi</strong>") l.Add("<b>hi</b>", "<strong>hi</strong>")
msgList.Add("<b>h</b>", "<strong>h</strong>") l.Add("<b>h</b>", "<strong>h</strong>")
msgList.Add("<s>hi</s>", "<del>hi</del>") l.Add("<s>hi</s>", "<del>hi</del>")
msgList.Add("<del>hi</del>", "<del>hi</del>") l.Add("<del>hi</del>", "<del>hi</del>")
msgList.Add("<u>hi</u>", "<u>hi</u>") l.Add("<u>hi</u>", "<u>hi</u>")
msgList.Add("<em>hi</em>", "<em>hi</em>") l.Add("<em>hi</em>", "<em>hi</em>")
msgList.Add("<i>hi</i>", "<em>hi</em>") l.Add("<i>hi</i>", "<em>hi</em>")
msgList.Add("<strong>hi</strong>", "<strong>hi</strong>") l.Add("<strong>hi</strong>", "<strong>hi</strong>")
msgList.Add("<b><i>hi</i></b>", "<strong><em>hi</em></strong>") l.Add("<b><i>hi</i></b>", "<strong><em>hi</em></strong>")
msgList.Add("<strong><em>hi</em></strong>", "<strong><em>hi</em></strong>") l.Add("<strong><em>hi</em></strong>", "<strong><em>hi</em></strong>")
msgList.Add("<b><i><b>hi</b></i></b>", "<strong><em><strong>hi</strong></em></strong>") l.Add("<b><i><b>hi</b></i></b>", "<strong><em><strong>hi</strong></em></strong>")
msgList.Add("<strong><em><strong>hi</strong></em></strong>", "<strong><em><strong>hi</strong></em></strong>") l.Add("<strong><em><strong>hi</strong></em></strong>", "<strong><em><strong>hi</strong></em></strong>")
msgList.Add("<div>hi</div>", "&lt;div&gt;hi&lt;/div&gt;") l.Add("<div>hi</div>", "&lt;div&gt;hi&lt;/div&gt;")
msgList.Add("<span>hi</span>", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans l.Add("<span>hi</span>", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans
msgList.Add("<span >hi</span>", "hi") l.Add("<span >hi</span>", "hi")
msgList.Add("<span style='background-color: yellow;'>hi</span>", "hi") l.Add("<span style='background-color: yellow;'>hi</span>", "hi")
msgList.Add("<span style='background-color: yellow;'>>hi</span>", "&gt;hi") l.Add("<span style='background-color: yellow;'>>hi</span>", "&gt;hi")
msgList.Add("<b>hi", "<strong>hi</strong>") l.Add("<b>hi", "<strong>hi</strong>")
msgList.Add("hi</b>", "hi&lt;/b&gt;") l.Add("hi</b>", "hi&lt;/b&gt;")
msgList.Add("</b>", "&lt;/b&gt;") l.Add("</b>", "&lt;/b&gt;")
msgList.Add("</del>", "&lt;/del&gt;") l.Add("</del>", "&lt;/del&gt;")
msgList.Add("</strong>", "&lt;/strong&gt;") l.Add("</strong>", "&lt;/strong&gt;")
msgList.Add("<b>", "<strong></strong>") l.Add("<b>", "<strong></strong>")
msgList.Add("<span style='background-color: yellow;'>hi", "hi") l.Add("<span style='background-color: yellow;'>hi", "hi")
msgList.Add("hi</span>", "hi") l.Add("<span style='background-color:yellow;'>hi", "hi")
msgList.Add("</span>", "") l.Add("hi</span>", "hi")
msgList.Add("<span></span>", "") l.Add("</span>", "")
msgList.Add("<span ></span>", "") l.Add("<span></span>", "")
msgList.Add("<span><span></span></span>", "") l.Add("<span ></span>", "")
msgList.Add("<span><b></b></span>", "<strong></strong>") l.Add("<span><span></span></span>", "")
msgList.Add("<h1>t</h1>", "<h2>t</h2>") l.Add("<span><b></b></span>", "<strong></strong>")
msgList.Add("<h2>t</h2>", "<h3>t</h3>") l.Add("<h1>t</h1>", "<h2>t</h2>")
msgList.Add("<h3>t</h3>", "<h4>t</h4>") l.Add("<h2>t</h2>", "<h3>t</h3>")
msgList.Add("<></>", "&lt;&gt;&lt;/&gt;") l.Add("<h3>t</h3>", "<h4>t</h4>")
msgList.Add("</><>", "&lt;/&gt;&lt;&gt;") l.Add("<></>", "&lt;&gt;&lt;/&gt;")
msgList.Add("<>", "&lt;&gt;") l.Add("</><>", "&lt;/&gt;&lt;&gt;")
msgList.Add("</>", "&lt;/&gt;") l.Add("<>", "&lt;&gt;")
msgList.Add("<p>hi</p>", "hi") l.Add("</>", "&lt;/&gt;")
msgList.Add("<p></p>", "") l.Add("<p>hi</p>", "hi")
msgList.Add("<blockquote>hi</blockquote>", "<blockquote>hi</blockquote>") l.Add("<p></p>", "")
msgList.Add("<blockquote><b>hi</b></blockquote>", "<blockquote><strong>hi</strong></blockquote>") l.Add("<blockquote>hi</blockquote>", "<blockquote>hi</blockquote>")
msgList.Add("<blockquote><meow>hi</meow></blockquote>", "<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>") l.Add("<blockquote><b>hi</b></blockquote>", "<blockquote><strong>hi</strong></blockquote>")
msgList.Add("\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;") l.Add("<blockquote><meow>hi</meow></blockquote>", "<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>")
//msgList.Add("\\\\<blockquote><meow>hi</meow></blockquote>", "\\<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>") // TODO: Double escapes should print a literal backslash l.Add("\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;")
//msgList.Add("&lt;blockquote&gt;hi&lt;/blockquote&gt;", "&lt;blockquote&gt;hi&lt;/blockquote&gt;") // TODO: Stop double-entitising this //l.Add("\\\\<blockquote><meow>hi</meow></blockquote>", "\\<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>") // TODO: Double escapes should print a literal backslash
msgList.Add("\\<blockquote>hi</blockquote>\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;&lt;blockquote&gt;hi&lt;/blockquote&gt;") //l.Add("&lt;blockquote&gt;hi&lt;/blockquote&gt;", "&lt;blockquote&gt;hi&lt;/blockquote&gt;") // TODO: Stop double-entitising this
msgList.Add("\\<a itemprop=\"author\">Admin</a>", "&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;") l.Add("\\<blockquote>hi</blockquote>\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;&lt;blockquote&gt;hi&lt;/blockquote&gt;")
msgList.Add("<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>") l.Add("\\<a itemprop=\"author\">Admin</a>", "&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;")
msgList.Add("\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\n", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>") l.Add("<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>")
msgList.Add("tt\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\ntt", "tt\n<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>\ntt") l.Add("\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\n", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>")
msgList.Add("@", "@") l.Add("tt\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\ntt", "tt\n<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>\ntt")
msgList.Add("@Admin", "@1") l.Add("@", "@")
msgList.Add("@Bah", "@Bah") l.Add("@Admin", "@1")
msgList.Add(" @Admin", "@1") l.Add("@Bah", "@Bah")
msgList.Add("\n@Admin", "@1") l.Add(" @Admin", "@1")
msgList.Add("@Admin\n", "@1") l.Add("\n@Admin", "@1")
msgList.Add("@Admin\ndd", "@1\ndd") l.Add("@Admin\n", "@1")
msgList.Add("d@Admin", "d@Admin") l.Add("@Admin\ndd", "@1\ndd")
msgList.Add("\\@Admin", "@Admin") l.Add("d@Admin", "d@Admin")
msgList.Add("@元気", "@元気") l.Add("\\@Admin", "@Admin")
l.Add("@元気", "@元気")
// TODO: More tests for unicode names? // TODO: More tests for unicode names?
//msgList.Add("\\\\@Admin", "@1") //l.Add("\\\\@Admin", "@1")
//msgList.Add("byte 0", string([]byte{0}), "") //l.Add("byte 0", string([]byte{0}), "")
msgList.Add("byte 'a'", string([]byte{'a'}), "a") l.Add("byte 'a'", string([]byte{'a'}), "a")
//msgList.Add("byte 255", string([]byte{255}), "") //l.Add("byte 255", string([]byte{255}), "")
//msgList.Add("rune 0", string([]rune{0}), "") //l.Add("rune 0", string([]rune{0}), "")
// TODO: Do a test with invalid UTF-8 input // TODO: Do a test with invalid UTF-8 input
for _, item := range msgList.Items { for _, item := range l.Items {
res := c.PreparseMessage(item.Msg) res := c.PreparseMessage(item.Msg)
if res != item.Expects { if res != item.Expects {
if item.Name != "" { if item.Name != "" {
@ -139,145 +140,148 @@ func TestParser(t *testing.T) {
if !c.PluginsInited { if !c.PluginsInited {
c.InitPlugins() c.InitPlugins()
} }
var msgList = &METriList{nil} l := &METriList{nil}
url := "github.com/Azareal/Gosora" url := "github.com/Azareal/Gosora"
msgList.Add("", "") l.Add("", "")
msgList.Add("haha", "haha") l.Add("haha", "haha")
msgList.Add("<b>t</b>", "<b>t</b>") l.Add("<b>t</b>", "<b>t</b>")
msgList.Add("//", "//") l.Add("//", "//")
msgList.Add("http://", "<red>[Invalid URL]</red>") l.Add("http://", "<red>[Invalid URL]</red>")
msgList.Add("https://", "<red>[Invalid URL]</red>") l.Add("https://", "<red>[Invalid URL]</red>")
msgList.Add("ftp://", "<red>[Invalid URL]</red>") l.Add("ftp://", "<red>[Invalid URL]</red>")
msgList.Add("git://", "<red>[Invalid URL]</red>") l.Add("git://", "<red>[Invalid URL]</red>")
msgList.Add("ssh://", "ssh://") l.Add("ssh://", "ssh://")
msgList.Add("// ", "// ") l.Add("// ", "// ")
msgList.Add("// //", "// //") l.Add("// //", "// //")
msgList.Add("// // //", "// // //") l.Add("// // //", "// // //")
msgList.Add("http:// ", "<red>[Invalid URL]</red> ") l.Add("http:// ", "<red>[Invalid URL]</red> ")
msgList.Add("https:// ", "<red>[Invalid URL]</red> ") l.Add("https:// ", "<red>[Invalid URL]</red> ")
msgList.Add("ftp:// ", "<red>[Invalid URL]</red> ") l.Add("ftp:// ", "<red>[Invalid URL]</red> ")
msgList.Add("git:// ", "<red>[Invalid URL]</red> ") l.Add("git:// ", "<red>[Invalid URL]</red> ")
msgList.Add("ssh:// ", "ssh:// ") l.Add("ssh:// ", "ssh:// ")
msgList.Add("// t", "// t") l.Add("// t", "// t")
msgList.Add("http:// t", "<red>[Invalid URL]</red> t") l.Add("http:// t", "<red>[Invalid URL]</red> t")
msgList.Add("http:", "http:") l.Add("http:", "http:")
msgList.Add("https:", "https:") l.Add("https:", "https:")
msgList.Add("ftp:", "ftp:") l.Add("ftp:", "ftp:")
msgList.Add("git:", "git:") l.Add("git:", "git:")
msgList.Add("ssh:", "ssh:") l.Add("ssh:", "ssh:")
msgList.Add("http", "http") l.Add("http", "http")
msgList.Add("https", "https") l.Add("https", "https")
msgList.Add("ftp", "ftp") l.Add("ftp", "ftp")
msgList.Add("git", "git") l.Add("git", "git")
msgList.Add("ssh", "ssh") l.Add("ssh", "ssh")
msgList.Add("ht", "ht") l.Add("ht", "ht")
msgList.Add("htt", "htt") l.Add("htt", "htt")
msgList.Add("ft", "ft") l.Add("ft", "ft")
msgList.Add("gi", "gi") l.Add("gi", "gi")
msgList.Add("ss", "ss") l.Add("ss", "ss")
msgList.Add("haha\nhaha\nhaha", "haha<br>haha<br>haha") l.Add("haha\nhaha\nhaha", "haha<br>haha<br>haha")
msgList.Add("//"+url, "<a href='//"+url+"'>//"+url+"</a>") l.Add("//"+url, "<a rel='ugc' href='//"+url+"'>//"+url+"</a>")
msgList.Add("//a", "<a href='//a'>//a</a>") l.Add("//a", "<a rel='ugc' href='//a'>//a</a>")
msgList.Add(" //a", " <a href='//a'>//a</a>") l.Add(" //a", " <a rel='ugc' href='//a'>//a</a>")
msgList.Add("//a ", "<a href='//a'>//a</a> ") l.Add("//a ", "<a rel='ugc' href='//a'>//a</a> ")
msgList.Add(" //a ", " <a href='//a'>//a</a> ") l.Add(" //a ", " <a rel='ugc' href='//a'>//a</a> ")
msgList.Add("d //a ", "d <a href='//a'>//a</a> ") l.Add("d //a ", "d <a rel='ugc' href='//a'>//a</a> ")
msgList.Add("ddd ddd //a ", "ddd ddd <a href='//a'>//a</a> ") l.Add("ddd ddd //a ", "ddd ddd <a rel='ugc' href='//a'>//a</a> ")
msgList.Add("https://"+url, "<a href='https://"+url+"'>https://"+url+"</a>") l.Add("https://"+url, "<a rel='ugc' href='https://"+url+"'>https://"+url+"</a>")
msgList.Add("https://t", "<a href='https://t'>https://t</a>") l.Add("https://t", "<a href='https://t'>https://t</a>")
msgList.Add("http://"+url, "<a href='http://"+url+"'>http://"+url+"</a>") l.Add("http://"+url, "<a href='http://"+url+"'>http://"+url+"</a>")
msgList.Add("#http://"+url, "#http://"+url) l.Add("#http://"+url, "#http://"+url)
msgList.Add("@http://"+url, "<red>[Invalid Profile]</red>ttp://"+url) l.Add("@http://"+url, "<red>[Invalid Profile]</red>ttp://"+url)
msgList.Add("//"+url+"\n", "<a href='//"+url+"'>//"+url+"</a><br>") l.Add("//"+url+"\n", "<a href='//"+url+"'>//"+url+"</a><br>")
msgList.Add("\n//"+url, "<br><a href='//"+url+"'>//"+url+"</a>") l.Add("\n//"+url, "<br><a href='//"+url+"'>//"+url+"</a>")
msgList.Add("\n//"+url+"\n", "<br><a href='//"+url+"'>//"+url+"</a><br>") l.Add("\n//"+url+"\n", "<br><a href='//"+url+"'>//"+url+"</a><br>")
msgList.Add("\n//"+url+"\n\n", "<br><a href='//"+url+"'>//"+url+"</a><br><br>") l.Add("\n//"+url+"\n\n", "<br><a href='//"+url+"'>//"+url+"</a><br><br>")
msgList.Add("//"+url+"\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><a href='//"+url+"'>//"+url+"</a>") l.Add("//"+url+"\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><a href='//"+url+"'>//"+url+"</a>")
msgList.Add("//"+url+"\n\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><br><a href='//"+url+"'>//"+url+"</a>") l.Add("//"+url+"\n\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><br><a href='//"+url+"'>//"+url+"</a>")
msgList.Add("//"+c.Site.URL, "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a>") l.Add("//"+c.Site.URL, "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a>")
msgList.Add("//"+c.Site.URL+"\n", "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a><br>") l.Add("//"+c.Site.URL+"\n", "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a><br>")
msgList.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a><br><a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a>") l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a><br><a href='//"+c.Site.URL+"'>//"+c.Site.URL+"</a>")
var local = func(url string) { local := func(url string) {
msgList.Add("//"+url, "<a href='//"+url+"'>//"+url+"</a>") l.Add("//"+url, "<a href='//"+url+"'>//"+url+"</a>")
msgList.Add("//"+url+"\n", "<a href='//"+url+"'>//"+url+"</a><br>") l.Add("//"+url+"\n", "<a href='//"+url+"'>//"+url+"</a><br>")
msgList.Add("//"+url+"\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><a href='//"+url+"'>//"+url+"</a>") l.Add("//"+url+"\n//"+url, "<a href='//"+url+"'>//"+url+"</a><br><a href='//"+url+"'>//"+url+"</a>")
} }
local("localhost") local("localhost")
local("127.0.0.1") local("127.0.0.1")
local("[::1]") local("[::1]")
msgList.Add("https://www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
//msgList.Add("https://www.youtube.com/watch?v=;","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/;' frameborder=0 allowfullscreen></iframe>") //l.Add("https://www.youtube.com/watch?v=;","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/;' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://www.youtube.com/watch?v=d;","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/d' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v=d;","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/d' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://www.youtube.com/watch?v=d;d","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/d' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v=d;d","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/d' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://www.youtube.com/watch?v=alert()","<red>[Invalid URL]</red>()") l.Add("https://www.youtube.com/watch?v=alert()","<red>[Invalid URL]</red>()")
msgList.Add("https://www.youtube.com/watch?v=js:alert()","<red>[Invalid URL]</red>()") l.Add("https://www.youtube.com/watch?v=alert()()","<red>[Invalid URL]</red>()()")
msgList.Add("https://www.youtube.com/watch?v='+><script>alert(\"\")</script><+'","<red>[Invalid URL]</red>'+><script>alert(\"\")</script><+'") l.Add("https://www.youtube.com/watch?v=js:alert()","<red>[Invalid URL]</red>()")
msgList.Add("https://www.youtube.com/watch?v='+onready='alert(\"\")'+'","<red>[Invalid URL]</red>'+onready='alert(\"\")'+'") l.Add("https://www.youtube.com/watch?v='+><script>alert(\"\")</script><+'","<red>[Invalid URL]</red>'+><script>alert(\"\")</script><+'")
msgList.Add(" https://www.youtube.com/watch?v=lalalalala"," <iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v='+onready='alert(\"\")'+'","<red>[Invalid URL]</red>'+onready='alert(\"\")'+'")
msgList.Add("https://www.youtube.com/watch?v=lalalalala tt","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe> tt") l.Add(" https://www.youtube.com/watch?v=lalalalala"," <iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://www.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v=lalalalala tt","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe> tt")
msgList.Add("https://gaming.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://www.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://gaming.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://gaming.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://m.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://gaming.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("https://m.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://m.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("http://www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("https://m.youtube.com/watch?v=lalalalala&d=haha","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("//www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("http://www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
//msgList.Add("www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>") l.Add("//www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
//l.Add("www.youtube.com/watch?v=lalalalala","<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/lalalalala' frameborder=0 allowfullscreen></iframe>")
msgList.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>") l.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
msgList.Add("##tid-1", "##tid-1") l.Add("##tid-1", "##tid-1")
msgList.Add("# #tid-1", "# #tid-1") l.Add("# #tid-1", "# #tid-1")
msgList.Add("@ #tid-1", "<red>[Invalid Profile]</red>#tid-1") l.Add("@ #tid-1", "<red>[Invalid Profile]</red>#tid-1")
msgList.Add("@#tid-1", "<red>[Invalid Profile]</red>tid-1") l.Add("@#tid-1", "<red>[Invalid Profile]</red>tid-1")
msgList.Add("@ #tid-@", "<red>[Invalid Profile]</red>#tid-@") l.Add("@ #tid-@", "<red>[Invalid Profile]</red>#tid-@")
msgList.Add("#tid-1 #tid-1", "<a href='/topic/1'>#tid-1</a> <a href='/topic/1'>#tid-1</a>") l.Add("#tid-1 #tid-1", "<a href='/topic/1'>#tid-1</a> <a href='/topic/1'>#tid-1</a>")
msgList.Add("#tid-0", "<red>[Invalid Topic]</red>") l.Add("#tid-0", "<red>[Invalid Topic]</red>")
msgList.Add("https://"+url+"/#tid-1", "<a href='https://"+url+"/#tid-1'>https://"+url+"/#tid-1</a>") l.Add("https://"+url+"/#tid-1", "<a href='https://"+url+"/#tid-1'>https://"+url+"/#tid-1</a>")
msgList.Add("https://"+url+"/?hi=2", "<a href='https://"+url+"/?hi=2'>https://"+url+"/?hi=2</a>") l.Add("https://"+url+"/?hi=2", "<a href='https://"+url+"/?hi=2'>https://"+url+"/?hi=2</a>")
msgList.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>") l.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>")
msgList.Add(" #fid-1", " <a href='/forum/1'>#fid-1</a>") l.Add(" #fid-1", " <a href='/forum/1'>#fid-1</a>")
msgList.Add("#fid-0", "<red>[Invalid Forum]</red>") l.Add("#fid-0", "<red>[Invalid Forum]</red>")
msgList.Add(" #fid-0", " <red>[Invalid Forum]</red>") l.Add(" #fid-0", " <red>[Invalid Forum]</red>")
msgList.Add("#", "#") l.Add("#", "#")
msgList.Add("# ", "# ") l.Add("# ", "# ")
msgList.Add(" @", " @") l.Add(" @", " @")
msgList.Add(" #", " #") l.Add(" #", " #")
msgList.Add("#@", "#@") l.Add("#@", "#@")
msgList.Add("#@ ", "#@ ") l.Add("#@ ", "#@ ")
msgList.Add("#@1", "#@1") l.Add("#@1", "#@1")
msgList.Add("#f", "#f") l.Add("#f", "#f")
msgList.Add("#ff", "#ff") l.Add("f#f", "f#f")
msgList.Add("#ffffid-0", "#ffffid-0") l.Add("f#", "f#")
//msgList.Add("#ffffid-0", "#ffffid-0") l.Add("#ff", "#ff")
msgList.Add("#nid-0", "#nid-0") l.Add("#ffffid-0", "#ffffid-0")
msgList.Add("#nnid-0", "#nnid-0") //l.Add("#ffffid-0", "#ffffid-0")
msgList.Add("@@", "<red>[Invalid Profile]</red>") l.Add("#nid-0", "#nid-0")
msgList.Add("@@ @@", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>") l.Add("#nnid-0", "#nnid-0")
msgList.Add("@@1", "<red>[Invalid Profile]</red>1") l.Add("@@", "<red>[Invalid Profile]</red>")
msgList.Add("@#1", "<red>[Invalid Profile]</red>1") l.Add("@@ @@", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>")
msgList.Add("@##1", "<red>[Invalid Profile]</red>#1") l.Add("@@1", "<red>[Invalid Profile]</red>1")
msgList.Add("@2", "<red>[Invalid Profile]</red>") l.Add("@#1", "<red>[Invalid Profile]</red>1")
msgList.Add("@2t", "<red>[Invalid Profile]</red>t") l.Add("@##1", "<red>[Invalid Profile]</red>#1")
msgList.Add("@2 t", "<red>[Invalid Profile]</red> t") l.Add("@2", "<red>[Invalid Profile]</red>")
msgList.Add("@2 ", "<red>[Invalid Profile]</red> ") l.Add("@2t", "<red>[Invalid Profile]</red>t")
msgList.Add("@2 @2", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>") l.Add("@2 t", "<red>[Invalid Profile]</red> t")
msgList.Add("@1", "<a href='/user/admin.1' class='mention'>@Admin</a>") l.Add("@2 ", "<red>[Invalid Profile]</red> ")
msgList.Add(" @1", " <a href='/user/admin.1' class='mention'>@Admin</a>") l.Add("@2 @2", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>")
msgList.Add("@1t", "<a href='/user/admin.1' class='mention'>@Admin</a>t") l.Add("@1", "<a href='/user/admin.1' class='mention'>@Admin</a>")
msgList.Add("@1 ", "<a href='/user/admin.1' class='mention'>@Admin</a> ") l.Add(" @1", " <a href='/user/admin.1' class='mention'>@Admin</a>")
msgList.Add("@1 @1", "<a href='/user/admin.1' class='mention'>@Admin</a> <a href='/user/admin.1' class='mention'>@Admin</a>") l.Add("@1t", "<a href='/user/admin.1' class='mention'>@Admin</a>t")
msgList.Add("@0", "<red>[Invalid Profile]</red>") l.Add("@1 ", "<a href='/user/admin.1' class='mention'>@Admin</a> ")
msgList.Add("@-1", "<red>[Invalid Profile]</red>1") l.Add("@1 @1", "<a href='/user/admin.1' class='mention'>@Admin</a> <a href='/user/admin.1' class='mention'>@Admin</a>")
l.Add("@0", "<red>[Invalid Profile]</red>")
l.Add("@-1", "<red>[Invalid Profile]</red>1")
for _, item := range msgList.Items { for _, item := range l.Items {
res := c.ParseMessage(item.Msg, 1, "forums") res := c.ParseMessage(item.Msg, 1, "forums")
if res != item.Expects { if res != item.Expects {
if item.Name != "" { if item.Name != "" {

View File

@ -4,7 +4,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
) )
// go test -v // go test -v
@ -20,61 +20,61 @@ type MEPairList struct {
Items []MEPair Items []MEPair
} }
func (tlist *MEPairList) Add(msg string, expects string) { func (l *MEPairList) Add(msg string, expects string) {
tlist.Items = append(tlist.Items, MEPair{msg, expects}) l.Items = append(l.Items, MEPair{msg, expects})
} }
func TestBBCodeRender(t *testing.T) { func TestBBCodeRender(t *testing.T) {
//t.Skip() //t.Skip()
err := initBbcode(common.Plugins["bbcode"]) err := initBbcode(c.Plugins["bbcode"])
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
var res string var res string
var msgList = &MEPairList{nil} l := &MEPairList{nil}
msgList.Add("", "") l.Add("", "")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add("[b]", "<b></b>") l.Add("[b]", "<b></b>")
msgList.Add("[b][/b]", "<b></b>") l.Add("[b][/b]", "<b></b>")
msgList.Add("hi", "hi") l.Add("hi", "hi")
msgList.Add("😀", "😀") l.Add("😀", "😀")
msgList.Add("[b]😀[/b]", "<b>😀</b>") l.Add("[b]😀[/b]", "<b>😀</b>")
msgList.Add("[b]😀😀😀[/b]", "<b>😀😀😀</b>") l.Add("[b]😀😀😀[/b]", "<b>😀😀😀</b>")
msgList.Add("[b]hi[/b]", "<b>hi</b>") l.Add("[b]hi[/b]", "<b>hi</b>")
msgList.Add("[u]hi[/u]", "<u>hi</u>") l.Add("[u]hi[/u]", "<u>hi</u>")
msgList.Add("[i]hi[/i]", "<i>hi</i>") l.Add("[i]hi[/i]", "<i>hi</i>")
msgList.Add("[s]hi[/s]", "<s>hi</s>") l.Add("[s]hi[/s]", "<s>hi</s>")
msgList.Add("[c]hi[/c]", "[c]hi[/c]") l.Add("[c]hi[/c]", "[c]hi[/c]")
msgList.Add("[h1]hi", "[h1]hi") l.Add("[h1]hi", "[h1]hi")
msgList.Add("[h1]hi[/h1]", "<h2>hi</h2>") l.Add("[h1]hi[/h1]", "<h2>hi</h2>")
if !testing.Short() { if !testing.Short() {
//msgList.Add("[b]hi[/i]", "[b]hi[/i]") //l.Add("[b]hi[/i]", "[b]hi[/i]")
//msgList.Add("[/b]hi[b]", "[/b]hi[b]") //l.Add("[/b]hi[b]", "[/b]hi[b]")
//msgList.Add("[/b]hi[/b]", "[/b]hi[/b]") //l.Add("[/b]hi[/b]", "[/b]hi[/b]")
//msgList.Add("[b][b]hi[/b]", "<b>hi</b>") //l.Add("[b][b]hi[/b]", "<b>hi</b>")
//msgList.Add("[b][b]hi", "[b][b]hi") //l.Add("[b][b]hi", "[b][b]hi")
//msgList.Add("[b][b][b]hi", "[b][b][b]hi") //l.Add("[b][b][b]hi", "[b][b][b]hi")
//msgList.Add("[/b]hi", "[/b]hi") //l.Add("[/b]hi", "[/b]hi")
} }
msgList.Add("[code]hi[/code]", "<span class='codequotes'>hi</span>") l.Add("[code]hi[/code]", "<span class='codequotes'>hi</span>")
msgList.Add("[code][b]hi[/b][/code]", "<span class='codequotes'>[b]hi[/b]</span>") l.Add("[code][b]hi[/b][/code]", "<span class='codequotes'>[b]hi[/b]</span>")
msgList.Add("[code][b]hi[/code][/b]", "<span class='codequotes'>[b]hi</span>[/b]") l.Add("[code][b]hi[/code][/b]", "<span class='codequotes'>[b]hi</span>[/b]")
msgList.Add("[quote]hi[/quote]", "<blockquote>hi</blockquote>") l.Add("[quote]hi[/quote]", "<blockquote>hi</blockquote>")
msgList.Add("[quote][b]hi[/b][/quote]", "<blockquote><b>hi</b></blockquote>") l.Add("[quote][b]hi[/b][/quote]", "<blockquote><b>hi</b></blockquote>")
msgList.Add("[quote][b]h[/b][/quote]", "<blockquote><b>h</b></blockquote>") l.Add("[quote][b]h[/b][/quote]", "<blockquote><b>h</b></blockquote>")
msgList.Add("[quote][b][/b][/quote]", "<blockquote><b></b></blockquote>") l.Add("[quote][b][/b][/quote]", "<blockquote><b></b></blockquote>")
msgList.Add("[url][/url]", "<a href=''></a>") l.Add("[url][/url]", "<a href=''></a>")
msgList.Add("[url]https://github.com/Azareal/Gosora[/url]", "<a href='https://github.com/Azareal/Gosora'>https://github.com/Azareal/Gosora</a>") l.Add("[url]https://github.com/Azareal/Gosora[/url]", "<a href='https://github.com/Azareal/Gosora'>https://github.com/Azareal/Gosora</a>")
msgList.Add("[url]http://github.com/Azareal/Gosora[/url]", "<a href='http://github.com/Azareal/Gosora'>http://github.com/Azareal/Gosora</a>") l.Add("[url]http://github.com/Azareal/Gosora[/url]", "<a href='http://github.com/Azareal/Gosora'>http://github.com/Azareal/Gosora</a>")
msgList.Add("[url]//github.com/Azareal/Gosora[/url]", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>") l.Add("[url]//github.com/Azareal/Gosora[/url]", "<a href='//github.com/Azareal/Gosora'>//github.com/Azareal/Gosora</a>")
msgList.Add("-你好-", "-你好-") l.Add("-你好-", "-你好-")
msgList.Add("[i]-你好-[/i]", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.? l.Add("[i]-你好-[/i]", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.?
t.Log("Testing bbcodeFullParse") t.Log("Testing bbcodeFullParse")
for _, item := range msgList.Items { for _, item := range l.Items {
res = bbcodeFullParse(item.Msg) res = bbcodeFullParse(item.Msg)
if res != item.Expects { if res != item.Expects {
t.Error("Testing string '" + item.Msg + "'") t.Error("Testing string '" + item.Msg + "'")
@ -83,77 +83,26 @@ func TestBBCodeRender(t *testing.T) {
} }
} }
var msg string f := func(msg, expects string) {
var expects string t.Log("Testing string '" + msg + "'")
res := bbcodeFullParse(msg)
msg = "[rand][/rand]" if res != expects {
expects = "<red>[Invalid Number]</red>[rand][/rand]" t.Error("Bad output:", "'"+res+"'")
t.Log("Testing string '" + msg + "'") t.Error("Expected:", "'"+expects+"'")
res = bbcodeFullParse(msg) }
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
} }
f("[rand][/rand]","<red>[Invalid Number]</red>[rand][/rand]")
f("[rand]-1[/rand]","<red>[No Negative Numbers]</red>[rand]-1[/rand]")
f("[rand]-01[/rand]","<red>[No Negative Numbers]</red>[rand]-01[/rand]")
f("[rand]NaN[/rand]","<red>[Invalid Number]</red>[rand]NaN[/rand]")
f("[rand]Inf[/rand]","<red>[Invalid Number]</red>[rand]Inf[/rand]")
f("[rand]+[/rand]","<red>[Invalid Number]</red>[rand]+[/rand]")
f("[rand]1+1[/rand]","<red>[Invalid Number]</red>[rand]1+1[/rand]")
msg = "[rand]-1[/rand]" msg := "[rand]1[/rand]"
expects = "<red>[No Negative Numbers]</red>[rand]-1[/rand]"
t.Log("Testing string '" + msg + "'") t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg) res = bbcodeFullParse(msg)
if res != expects { conv, err := strconv.Atoi(res)
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
msg = "[rand]-01[/rand]"
expects = "<red>[No Negative Numbers]</red>[rand]-01[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
msg = "[rand]NaN[/rand]"
expects = "<red>[Invalid Number]</red>[rand]NaN[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
msg = "[rand]Inf[/rand]"
expects = "<red>[Invalid Number]</red>[rand]Inf[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
msg = "[rand]+[/rand]"
expects = "<red>[Invalid Number]</red>[rand]+[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
msg = "[rand]1+1[/rand]"
expects = "<red>[Invalid Number]</red>[rand]1+1[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
if res != expects {
t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", "'"+expects+"'")
}
var conv int
msg = "[rand]1[/rand]"
t.Log("Testing string '" + msg + "'")
res = bbcodeFullParse(msg)
conv, err = strconv.Atoi(res)
if err != nil || (conv > 1 || conv < 0) { if err != nil || (conv > 1 || conv < 0) {
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
t.Error("Expected a number in the range 0-1") t.Error("Expected a number in the range 0-1")
@ -205,7 +154,7 @@ func TestBBCodeRender(t *testing.T) {
} }
/*t.Log("Testing bbcode_regex_parse") /*t.Log("Testing bbcode_regex_parse")
for _, item := range msgList { for _, item := range l.Items {
t.Log("Testing string '" + item.Msg + "'") t.Log("Testing string '" + item.Msg + "'")
res = bbcodeRegexParse(item.Msg) res = bbcodeRegexParse(item.Msg)
if res != item.Expects { if res != item.Expects {
@ -217,94 +166,92 @@ func TestBBCodeRender(t *testing.T) {
func TestMarkdownRender(t *testing.T) { func TestMarkdownRender(t *testing.T) {
//t.Skip() //t.Skip()
err := initMarkdown(common.Plugins["markdown"]) err := initMarkdown(c.Plugins["markdown"])
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
var res string l := &MEPairList{nil}
var msgList = &MEPairList{nil} l2 := &MEPairList{nil}
var msgList2 = &MEPairList{nil}
// TODO: Fix more of these odd cases // TODO: Fix more of these odd cases
msgList.Add("", "") l.Add("", "")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add(" ", " ") l.Add(" ", " ")
msgList.Add("\t", "\t") l.Add("\t", "\t")
msgList.Add("\n", "\n") l.Add("\n", "\n")
msgList.Add("*", "*") l.Add("*", "*")
msgList.Add("`", "`") l.Add("`", "`")
//msgList.Add("**", "<i></i>") //l.Add("**", "<i></i>")
msgList.Add("h", "h") l.Add("h", "h")
msgList.Add("hi", "hi") l.Add("hi", "hi")
msgList.Add("**h**", "<b>h</b>") l.Add("**h**", "<b>h</b>")
msgList.Add("**hi**", "<b>hi</b>") l.Add("**hi**", "<b>hi</b>")
msgList.Add("_h_", "<u>h</u>") l.Add("_h_", "<u>h</u>")
msgList.Add("_hi_", "<u>hi</u>") l.Add("_hi_", "<u>hi</u>")
msgList.Add("*h*", "<i>h</i>") l.Add("*h*", "<i>h</i>")
msgList.Add("*hi*", "<i>hi</i>") l.Add("*hi*", "<i>hi</i>")
msgList.Add("~h~", "<s>h</s>") l.Add("~h~", "<s>h</s>")
msgList.Add("~hi~", "<s>hi</s>") l.Add("~hi~", "<s>hi</s>")
msgList.Add("`hi`", "<blockquote>hi</blockquote>") l.Add("`hi`", "<blockquote>hi</blockquote>")
// TODO: Hide the backslash after escaping the item // TODO: Hide the backslash after escaping the item
// TODO: Doesn't behave consistently with d in-front of it // TODO: Doesn't behave consistently with d in-front of it
msgList2.Add("\\`hi`", "\\`hi`") l2.Add("\\`hi`", "\\`hi`")
msgList2.Add("#", "#") l2.Add("#", "#")
msgList2.Add("#h", "<h2>h</h2>") l2.Add("#h", "<h2>h</h2>")
msgList2.Add("#hi", "<h2>hi</h2>") l2.Add("#hi", "<h2>hi</h2>")
msgList2.Add("# hi", "<h2>hi</h2>") l2.Add("# hi", "<h2>hi</h2>")
msgList2.Add("# hi", "<h2>hi</h2>") l2.Add("# hi", "<h2>hi</h2>")
msgList.Add("\n#", "\n#") l.Add("\n#", "\n#")
msgList.Add("\n#h", "\n<h2>h</h2>") l.Add("\n#h", "\n<h2>h</h2>")
msgList.Add("\n#hi", "\n<h2>hi</h2>") l.Add("\n#hi", "\n<h2>hi</h2>")
msgList.Add("\n#h\n", "\n<h2>h</h2>") l.Add("\n#h\n", "\n<h2>h</h2>")
msgList.Add("\n#hi\n", "\n<h2>hi</h2>") l.Add("\n#hi\n", "\n<h2>hi</h2>")
msgList.Add("*hi**", "<i>hi</i>*") l.Add("*hi**", "<i>hi</i>*")
msgList.Add("**hi***", "<b>hi</b>*") l.Add("**hi***", "<b>hi</b>*")
//msgList.Add("**hi*", "*<i>hi</i>") //l.Add("**hi*", "*<i>hi</i>")
msgList.Add("***hi***", "<b><i>hi</i></b>") l.Add("***hi***", "<b><i>hi</i></b>")
msgList.Add("***h***", "<b><i>h</i></b>") l.Add("***h***", "<b><i>h</i></b>")
msgList.Add("\\***h**\\*", "*<b>h</b>*") l.Add("\\***h**\\*", "*<b>h</b>*")
msgList.Add("\\*\\**h*\\*\\*", "**<i>h</i>**") l.Add("\\*\\**h*\\*\\*", "**<i>h</i>**")
msgList.Add("\\*hi\\*", "*hi*") l.Add("\\*hi\\*", "*hi*")
msgList.Add("d\\*hi\\*", "d*hi*") l.Add("d\\*hi\\*", "d*hi*")
msgList.Add("\\*hi\\*d", "*hi*d") l.Add("\\*hi\\*d", "*hi*d")
msgList.Add("d\\*hi\\*d", "d*hi*d") l.Add("d\\*hi\\*d", "d*hi*d")
msgList.Add("\\", "\\") l.Add("\\", "\\")
msgList.Add("\\\\", "\\\\") l.Add("\\\\", "\\\\")
msgList.Add("\\d", "\\d") l.Add("\\d", "\\d")
msgList.Add("\\\\d", "\\\\d") l.Add("\\\\d", "\\\\d")
msgList.Add("\\\\\\d", "\\\\\\d") l.Add("\\\\\\d", "\\\\\\d")
msgList.Add("d\\", "d\\") l.Add("d\\", "d\\")
msgList.Add("\\d\\", "\\d\\") l.Add("\\d\\", "\\d\\")
msgList.Add("*_hi_*", "<i><u>hi</u></i>") l.Add("*_hi_*", "<i><u>hi</u></i>")
msgList.Add("*~hi~*", "<i><s>hi</s></i>") l.Add("*~hi~*", "<i><s>hi</s></i>")
//msgList.Add("~*hi*~", "<s><i>hi</i></s>") //l.Add("~*hi*~", "<s><i>hi</i></s>")
//msgList.Add("~ *hi* ~", "<s> <i>hi</i> </s>") //l.Add("~ *hi* ~", "<s> <i>hi</i> </s>")
msgList.Add("_~hi~_", "<u><s>hi</s></u>") l.Add("_~hi~_", "<u><s>hi</s></u>")
msgList.Add("***~hi~***", "<b><i><s>hi</s></i></b>") l.Add("***~hi~***", "<b><i><s>hi</s></i></b>")
msgList.Add("**", "**") l.Add("**", "**")
msgList.Add("***", "***") l.Add("***", "***")
msgList.Add("****", "****") l.Add("****", "****")
msgList.Add("*****", "*****") l.Add("*****", "*****")
msgList.Add("******", "******") l.Add("******", "******")
msgList.Add("*******", "*******") l.Add("*******", "*******")
msgList.Add("~~", "~~") l.Add("~~", "~~")
msgList.Add("~~~", "~~~") l.Add("~~~", "~~~")
msgList.Add("~~~~", "~~~~") l.Add("~~~~", "~~~~")
msgList.Add("~~~~~", "~~~~~") l.Add("~~~~~", "~~~~~")
msgList.Add("__", "__") l.Add("__", "__")
msgList.Add("___", "___") l.Add("___", "___")
msgList.Add("_ _", "<u> </u>") l.Add("_ _", "<u> </u>")
msgList.Add("* *", "<i> </i>") l.Add("* *", "<i> </i>")
msgList.Add("** **", "<b> </b>") l.Add("** **", "<b> </b>")
msgList.Add("*** ***", "<b><i> </i></b>") l.Add("*** ***", "<b><i> </i></b>")
msgList.Add("-你好-", "-你好-") l.Add("-你好-", "-你好-")
msgList.Add("*-你好-*", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.? l.Add("*-你好-*", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.?
for _, item := range msgList.Items { for _, item := range l.Items {
res = markdownParse(item.Msg) if res := markdownParse(item.Msg); res != item.Expects {
if res != item.Expects {
t.Error("Testing string '" + item.Msg + "'") t.Error("Testing string '" + item.Msg + "'")
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
//t.Error("Ouput in bytes:", []byte(res)) //t.Error("Ouput in bytes:", []byte(res))
@ -312,9 +259,8 @@ func TestMarkdownRender(t *testing.T) {
} }
} }
for _, item := range msgList2.Items { for _, item := range l2.Items {
res = markdownParse(item.Msg) if res := markdownParse(item.Msg); res != item.Expects {
if res != item.Expects {
t.Error("Testing string '" + item.Msg + "'") t.Error("Testing string '" + item.Msg + "'")
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
//t.Error("Ouput in bytes:", []byte(res)) //t.Error("Ouput in bytes:", []byte(res))
@ -322,9 +268,8 @@ func TestMarkdownRender(t *testing.T) {
} }
} }
/*for _, item := range msgList.Items { /*for _, item := range l.Items {
res = markdownParse("\n" + item.Msg) if res := markdownParse("\n" + item.Msg); res != "\n"+item.Expects {
if res != "\n"+item.Expects {
t.Error("Testing string '\n" + item.Msg + "'") t.Error("Testing string '\n" + item.Msg + "'")
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
//t.Error("Ouput in bytes:", []byte(res)) //t.Error("Ouput in bytes:", []byte(res))
@ -332,9 +277,8 @@ func TestMarkdownRender(t *testing.T) {
} }
} }
for _, item := range msgList.Items { for _, item := range l.Items {
res = markdownParse("\t" + item.Msg) if res := markdownParse("\t" + item.Msg); res != "\t"+item.Expects {
if res != "\t"+item.Expects {
t.Error("Testing string '\t" + item.Msg + "'") t.Error("Testing string '\t" + item.Msg + "'")
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
//t.Error("Ouput in bytes:", []byte(res)) //t.Error("Ouput in bytes:", []byte(res))
@ -342,9 +286,8 @@ func TestMarkdownRender(t *testing.T) {
} }
}*/ }*/
for _, item := range msgList.Items { for _, item := range l.Items {
res = markdownParse("d" + item.Msg) if res := markdownParse("d" + item.Msg); res != "d"+item.Expects {
if res != "d"+item.Expects {
t.Error("Testing string 'd" + item.Msg + "'") t.Error("Testing string 'd" + item.Msg + "'")
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
//t.Error("Ouput in bytes:", []byte(res)) //t.Error("Ouput in bytes:", []byte(res))

View File

@ -13,19 +13,19 @@ import (
"strings" "strings"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
// 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, header *c.Header) c.RouteError { func AccountLogin(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
if user.Loggedin { if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
header.Title = phrases.GetTitlePhrase("login") h.Title = p.GetTitlePhrase("login")
return renderTemplate("login", w, r, header, c.Page{header, tList, nil}) return renderTemplate("login", w, r, h, c.Page{h, tList, nil})
} }
// TODO: Log failed attempted logins? // TODO: Log failed attempted logins?
@ -141,11 +141,11 @@ func mfaVerifySession(provSession string, signedSession string, uid int) bool {
return subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1 return subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1
} }
func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
if user.Loggedin { if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
header.Title = phrases.GetTitlePhrase("login_mfa_verify") h.Title = p.GetTitlePhrase("login_mfa_verify")
uid, provSession, signedSession, err := mfaGetCookies(r) uid, provSession, signedSession, err := mfaGetCookies(r)
if err != nil { if err != nil {
@ -155,7 +155,7 @@ func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user c.User,
return c.LocalError("Invalid session", w, r, user) return c.LocalError("Invalid session", w, r, user)
} }
return renderTemplate("login_mfa_verify", w, r, header, c.Page{header, tList, nil}) return renderTemplate("login_mfa_verify", w, r, h, c.Page{h, tList, nil})
} }
func AccountLoginMFAVerifySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func AccountLoginMFAVerifySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
@ -182,13 +182,13 @@ func AccountLogout(w http.ResponseWriter, r *http.Request, user c.User) c.RouteE
return nil return nil
} }
func AccountRegister(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountRegister(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
if user.Loggedin { if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
header.Title = phrases.GetTitlePhrase("register") h.Title = p.GetTitlePhrase("register")
header.AddScriptAsync("register.js") h.AddScriptAsync("register.js")
return renderTemplate("register", w, r, header, c.Page{header, tList, nil}) return renderTemplate("register", w, r, h, c.Page{h, tList, nil})
} }
func isNumeric(data string) (numeric bool) { func isNumeric(data string) (numeric bool) {
@ -204,10 +204,10 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
headerLite, _ := c.SimpleUserCheck(w, r, &user) headerLite, _ := c.SimpleUserCheck(w, r, &user)
// TODO: Should we push multiple validation errors to the user instead of just one? // TODO: Should we push multiple validation errors to the user instead of just one?
var regSuccess = true regSuccess := true
var regErrMsg = "" regErrMsg := ""
var regErrReason = "" regErrReason := ""
var regError = func(userMsg string, reason string) { regError := func(userMsg string, reason string) {
regSuccess = false regSuccess = false
if regErrMsg == "" { if regErrMsg == "" {
regErrMsg = userMsg regErrMsg = userMsg
@ -216,14 +216,14 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
} }
if r.PostFormValue("tos") != "0" { if r.PostFormValue("tos") != "0" {
regError(phrases.GetErrorPhrase("register_might_be_machine"), "trap-question") regError(p.GetErrorPhrase("register_might_be_machine"), "trap-question")
} }
if !c.Config.DisableJSAntispam { if !c.Config.DisableJSAntispam {
h := sha256.New() h := sha256.New()
h.Write([]byte(c.JSTokenBox.Load().(string))) h.Write([]byte(c.JSTokenBox.Load().(string)))
h.Write([]byte(user.LastIP)) h.Write([]byte(user.LastIP))
if r.PostFormValue("golden-watch") != hex.EncodeToString(h.Sum(nil)) { if r.PostFormValue("golden-watch") != hex.EncodeToString(h.Sum(nil)) {
regError(phrases.GetErrorPhrase("register_might_be_machine"), "js-antispam") regError(p.GetErrorPhrase("register_might_be_machine"), "js-antispam")
} }
} }
@ -231,21 +231,20 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
// TODO: Add a dedicated function for validating emails // TODO: Add a dedicated function for validating emails
email := c.SanitiseSingleLine(r.PostFormValue("email")) email := c.SanitiseSingleLine(r.PostFormValue("email"))
if username == "" { if username == "" {
regError(phrases.GetErrorPhrase("register_need_username"), "no-username") regError(p.GetErrorPhrase("register_need_username"), "no-username")
} }
if email == "" { if email == "" {
regError(phrases.GetErrorPhrase("register_need_email"), "no-email") regError(p.GetErrorPhrase("register_need_email"), "no-email")
} }
// This is so a numeric name won't interfere with mentioning a user by ID, there might be a better way of doing this like perhaps !@ to mean IDs and @ to mean usernames in the pre-parser // This is so a numeric name won't interfere with mentioning a user by ID, there might be a better way of doing this like perhaps !@ to mean IDs and @ to mean usernames in the pre-parser
usernameBits := strings.Split(username, " ") usernameBits := strings.Split(username, " ")
if isNumeric(usernameBits[0]) { if isNumeric(usernameBits[0]) {
regError(phrases.GetErrorPhrase("register_first_word_numeric"), "numeric-name") regError(p.GetErrorPhrase("register_first_word_numeric"), "numeric-name")
} }
ok := c.HasSuspiciousEmail(email) if c.HasSuspiciousEmail(email) {
if ok { regError(p.GetErrorPhrase("register_suspicious_email"), "suspicious-email")
regError(phrases.GetErrorPhrase("register_suspicious_email"), "suspicious-email")
} }
password := r.PostFormValue("password") password := r.PostFormValue("password")
@ -257,7 +256,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
// Do the two inputted passwords match..? // Do the two inputted passwords match..?
confirmPassword := r.PostFormValue("confirm_password") confirmPassword := r.PostFormValue("confirm_password")
if password != confirmPassword { if password != confirmPassword {
regError(phrases.GetErrorPhrase("register_password_mismatch"), "password-mismatch") regError(p.GetErrorPhrase("register_password_mismatch"), "password-mismatch")
} }
} }
@ -290,14 +289,14 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return c.LocalError(phrases.GetErrorPhrase("register_username_unavailable"), w, r, user) return c.LocalError(p.GetErrorPhrase("register_username_unavailable"), w, r, user)
} else if err == c.ErrLongUsername { } else if err == c.ErrLongUsername {
regLog.FailureReason += "username-too-long" regLog.FailureReason += "username-too-long"
err = regLog.Commit() err = regLog.Commit()
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return c.LocalError(phrases.GetErrorPhrase("register_username_too_long_prefix")+strconv.Itoa(c.Config.MaxUsernameLength), w, r, user) return c.LocalError(p.GetErrorPhrase("register_username_too_long_prefix")+strconv.Itoa(c.Config.MaxUsernameLength), w, r, user)
} }
regLog.FailureReason += "internal-error" regLog.FailureReason += "internal-error"
err2 := regLog.Commit() err2 := regLog.Commit()
@ -328,7 +327,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
err = c.SendValidationEmail(username, email, token) err = c.SendValidationEmail(username, email, token)
if err != nil { if err != nil {
return c.LocalError(phrases.GetErrorPhrase("register_email_fail"), w, r, user) return c.LocalError(p.GetErrorPhrase("register_email_fail"), w, r, user)
} }
} }
@ -337,11 +336,11 @@ 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, header *c.Header) { func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) {
header.Title = phrases.GetTitlePhrase(titlePhrase) h.Title = p.GetTitlePhrase(titlePhrase)
header.Path = "/user/edit/" h.Path = "/user/edit/"
header.AddSheet(header.Theme.Name + "/account.css") h.AddSheet(h.Theme.Name + "/account.css")
header.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, user c.User, header *c.Header) c.RouteError {
@ -356,7 +355,7 @@ func AccountEdit(w http.ResponseWriter, r *http.Request, user c.User, header *c.
} }
// TODO: Find a more efficient way of doing this // TODO: Find a more efficient way of doing this
var mfaSetup = false mfaSetup := false
_, err := c.MFAstore.Get(user.ID) _, err := c.MFAstore.Get(user.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)
@ -375,9 +374,9 @@ func AccountEdit(w http.ResponseWriter, r *http.Request, user c.User, header *c.
} }
//edit_password //edit_password
func AccountEditPassword(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountEditPassword(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("account_password", w, r, &user, header) accountEditHead("account_password", w, r, &user, h)
return renderTemplate("account_own_edit_password", w, r, header, c.Page{header, tList, nil}) return renderTemplate("account_own_edit_password", w, r, h, c.Page{h, tList, nil})
} }
// TODO: Require re-authentication if the user hasn't logged in in a while // TODO: Require re-authentication if the user hasn't logged in in a while
@ -479,8 +478,8 @@ func AccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user c.Us
return nil return nil
} }
func AccountEditMFA(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountEditMFA(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("account_mfa", w, r, &user, header) accountEditHead("account_mfa", w, r, &user, h)
mfaItem, err := c.MFAstore.Get(user.ID) mfaItem, err := c.MFAstore.Get(user.ID)
if err != sql.ErrNoRows && err != nil { if err != sql.ErrNoRows && err != nil {
@ -489,13 +488,13 @@ func AccountEditMFA(w http.ResponseWriter, r *http.Request, user c.User, header
return c.LocalError("Two-factor authentication hasn't been setup on your account", w, r, user) return c.LocalError("Two-factor authentication hasn't been setup on your account", w, r, user)
} }
pi := c.Page{header, tList, mfaItem.Scratch} pi := c.Page{h, tList, mfaItem.Scratch}
return renderTemplate("account_own_edit_mfa", w, r, header, pi) return renderTemplate("account_own_edit_mfa", w, r, h, pi)
} }
// If not setup, generate a string, otherwise give an option to disable mfa given the right code // If not setup, generate a string, otherwise give an option to disable mfa given the right code
func AccountEditMFASetup(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountEditMFASetup(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("account_mfa_setup", w, r, &user, header) accountEditHead("account_mfa_setup", w, r, &user, h)
// Flash an error if mfa is already setup // Flash an error if mfa is already setup
_, err := c.MFAstore.Get(user.ID) _, err := c.MFAstore.Get(user.ID)
@ -511,8 +510,8 @@ func AccountEditMFASetup(w http.ResponseWriter, r *http.Request, user c.User, he
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
pi := c.Page{header, tList, c.FriendlyGAuthSecret(code)} pi := c.Page{h, tList, c.FriendlyGAuthSecret(code)}
return renderTemplate("account_own_edit_mfa_setup", w, r, header, pi) return renderTemplate("account_own_edit_mfa_setup", w, r, h, pi)
} }
// Form should bounce the random mfa secret back and the otp to be verified server-side to reduce the chances of a bug arising on the JS side which makes every code mismatch // Form should bounce the random mfa secret back and the otp to be verified server-side to reduce the chances of a bug arising on the JS side which makes every code mismatch
@ -530,8 +529,8 @@ func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user c.Us
return c.LocalError("You have already setup two-factor authentication", w, r, user) return c.LocalError("You have already setup two-factor authentication", w, r, user)
} }
var code = r.PostFormValue("code") code := r.PostFormValue("code")
var otp = r.PostFormValue("otp") otp := r.PostFormValue("otp")
ok, err := c.VerifyGAuthToken(code, otp) ok, err := c.VerifyGAuthToken(code, otp)
if err != nil { if err != nil {
//fmt.Println("err: ", err) //fmt.Println("err: ", err)
@ -576,8 +575,8 @@ func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user c.
return nil return nil
} }
func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("account_email", w, r, &user, header) accountEditHead("account_email", w, r, &user, h)
emails, err := c.Emails.GetEmailsByUser(&user) emails, err := c.Emails.GetEmailsByUser(&user)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
@ -586,22 +585,18 @@ func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, heade
// 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 { if len(emails) == 0 {
email := c.Email{UserID: user.ID} emails = append(emails, c.Email{UserID: user.ID, Email: user.Email, Validated: false, Primary: true})
email.Email = user.Email
email.Validated = false
email.Primary = true
emails = append(emails, email)
} }
if !c.Site.EnableEmails { if !c.Site.EnableEmails {
header.AddNotice("account_mail_disabled") h.AddNotice("account_mail_disabled")
} }
if r.FormValue("verified") == "1" { if r.FormValue("verified") == "1" {
header.AddNotice("account_mail_verify_success") h.AddNotice("account_mail_verify_success")
} }
pi := c.Account{header, "edit_emails", "account_own_edit_email", c.EmailListPage{header, emails}} pi := c.Account{h, "edit_emails", "account_own_edit_email", c.EmailListPage{h, emails}}
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, h, pi)
} }
// TODO: Should we make this an AnonAction so someone can do this without being logged in? // TODO: Should we make this an AnonAction so someone can do this without being logged in?
@ -649,9 +644,8 @@ func AccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user c.
return nil return nil
} }
func AccountLogins(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountLogins(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("account_logins", w, r, &user, header) accountEditHead("account_logins", w, r, &user, h)
logCount := c.LoginLogs.CountUser(user.ID) logCount := c.LoginLogs.CountUser(user.ID)
page, _ := strconv.Atoi(r.FormValue("page")) page, _ := strconv.Atoi(r.FormValue("page"))
perPage := 12 perPage := 12
@ -663,15 +657,15 @@ func AccountLogins(w http.ResponseWriter, r *http.Request, user c.User, header *
} }
pageList := c.Paginate(page, lastPage, 5) pageList := c.Paginate(page, lastPage, 5)
pi := c.Account{header, "logins", "account_logins", c.AccountLoginsPage{header, logs, c.Paginator{pageList, page, lastPage}}} pi := c.Account{h, "logins", "account_logins", c.AccountLoginsPage{h, logs, c.Paginator{pageList, page, lastPage}}}
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, h, pi)
} }
func LevelList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func LevelList(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
header.Title = phrases.GetTitlePhrase("account_level_list") h.Title = p.GetTitlePhrase("account_level_list")
var fScores = c.GetLevels(20) fScores := c.GetLevels(20)
var levels = make([]c.LevelListItem, len(fScores)) levels := make([]c.LevelListItem, len(fScores))
for i, fScore := range fScores { for i, fScore := range fScores {
var status string var status string
if user.Level > i { if user.Level > i {
@ -686,25 +680,25 @@ func LevelList(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
levels[i] = c.LevelListItem{i, iScore, status, perc * 2} levels[i] = c.LevelListItem{i, iScore, status, perc * 2}
} }
return renderTemplate("level_list", w, r, header, c.LevelListPage{header, levels[1:]}) return renderTemplate("level_list", w, r, h, c.LevelListPage{h, levels[1:]})
} }
func Alerts(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func Alerts(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
return nil return nil
} }
func AccountPasswordReset(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func AccountPasswordReset(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
if user.Loggedin { if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
if !c.Site.EnableEmails { if !c.Site.EnableEmails {
return c.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) return c.LocalError(p.GetNoticePhrase("account_mail_disabled"), w, r, user)
} }
if r.FormValue("email_sent") == "1" { if r.FormValue("email_sent") == "1" {
header.AddNotice("password_reset_email_sent") h.AddNotice("password_reset_email_sent")
} }
header.Title = phrases.GetTitlePhrase("password_reset") h.Title = p.GetTitlePhrase("password_reset")
return renderTemplate("password_reset", w, r, header, c.Page{header, tList, nil}) return renderTemplate("password_reset", w, r, h, c.Page{h, tList, nil})
} }
// TODO: Ratelimit this // TODO: Ratelimit this
@ -713,7 +707,7 @@ func AccountPasswordResetSubmit(w http.ResponseWriter, r *http.Request, user c.U
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
if !c.Site.EnableEmails { if !c.Site.EnableEmails {
return c.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) return c.LocalError(p.GetNoticePhrase("account_mail_disabled"), w, r, user)
} }
username := r.PostFormValue("username") username := r.PostFormValue("username")
@ -767,9 +761,9 @@ func AccountPasswordResetSubmit(w http.ResponseWriter, r *http.Request, user c.U
schema = "s" schema = "s"
} }
err = c.SendEmail(tuser.Email, phrases.GetTmplPhrase("password_reset_subject"), phrases.GetTmplPhrasef("password_reset_body", tuser.Name, "http"+schema+"://"+c.Site.URL+"/accounts/password-reset/token/?uid="+strconv.Itoa(tuser.ID)+"&token="+token)) err = c.SendEmail(tuser.Email, p.GetTmplPhrase("password_reset_subject"), p.GetTmplPhrasef("password_reset_body", tuser.Name, "http"+schema+"://"+c.Site.URL+"/accounts/password-reset/token/?uid="+strconv.Itoa(tuser.ID)+"&token="+token))
if err != nil { if err != nil {
return c.LocalError(phrases.GetErrorPhrase("password_reset_email_fail"), w, r, user) return c.LocalError(p.GetErrorPhrase("password_reset_email_fail"), w, r, user)
} }
http.Redirect(w, r, "/accounts/password-reset/?email_sent=1", http.StatusSeeOther) http.Redirect(w, r, "/accounts/password-reset/?email_sent=1", http.StatusSeeOther)
@ -804,7 +798,7 @@ func AccountPasswordResetToken(w http.ResponseWriter, r *http.Request, user c.Us
} }
mfa := err != sql.ErrNoRows mfa := err != sql.ErrNoRows
header.Title = phrases.GetTitlePhrase("password_reset_token") header.Title = p.GetTitlePhrase("password_reset_token")
return renderTemplate("password_reset_token", w, r, header, c.ResetPage{header, uid, html.EscapeString(token), mfa}) return renderTemplate("password_reset_token", w, r, header, c.ResetPage{header, uid, html.EscapeString(token), mfa})
} }
@ -812,8 +806,6 @@ func AccountPasswordResetTokenSubmit(w http.ResponseWriter, r *http.Request, use
if user.Loggedin { if user.Loggedin {
return c.LocalError("You're already logged in.", w, r, user) return c.LocalError("You're already logged in.", w, r, user)
} }
token := r.FormValue("token")
uid, err := strconv.Atoi(r.FormValue("uid")) uid, err := strconv.Atoi(r.FormValue("uid"))
if err != nil { if err != nil {
return c.LocalError("Invalid uid", w, r, user) return c.LocalError("Invalid uid", w, r, user)
@ -822,6 +814,7 @@ func AccountPasswordResetTokenSubmit(w http.ResponseWriter, r *http.Request, use
return c.LocalError("This reset token has expired.", w, r, user) return c.LocalError("This reset token has expired.", w, r, user)
} }
token := r.FormValue("token")
err = c.PasswordResetter.ValidateToken(uid, token) err = c.PasswordResetter.ValidateToken(uid, token)
if err == sql.ErrNoRows || err == c.ErrBadResetToken { if err == sql.ErrNoRows || err == c.ErrBadResetToken {
return c.LocalError("This reset token has expired.", w, r, user) return c.LocalError("This reset token has expired.", w, r, user)

View File

@ -6,17 +6,18 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
//"log" //"log"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
p "github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
) )
func Convos(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func Convos(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("convos", w, r, &user, header) accountEditHead("convos", w, r, &user, h)
header.AddScript("convo.js") h.AddScript("convo.js")
header.AddSheet(header.Theme.Name + "/convo.css") h.AddSheet(h.Theme.Name + "/convo.css")
header.AddNotice("convo_dev") h.AddNotice("convo_dev")
ccount := c.Convos.GetUserCount(user.ID) ccount := c.Convos.GetUserCount(user.ID)
page, _ := strconv.Atoi(r.FormValue("page")) page, _ := strconv.Atoi(r.FormValue("page"))
offset, page, lastPage := c.PageOffset(ccount, page, c.Config.ItemsPerPage) offset, page, lastPage := c.PageOffset(ccount, page, c.Config.ItemsPerPage)
@ -25,13 +26,13 @@ func Convos(w http.ResponseWriter, r *http.Request, user c.User, header *c.Heade
convos, err := c.Convos.GetUserExtra(user.ID, offset) convos, err := c.Convos.GetUserExtra(user.ID, offset)
//log.Printf("convos: %+v\n", convos) //log.Printf("convos: %+v\n", convos)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return c.NotFound(w, r, header) return c.NotFound(w, r, h)
} else if err != nil { } else if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
pi := c.Account{header, "dashboard", "convos", c.ConvoListPage{header, convos, c.Paginator{pageList, page, lastPage}}} pi := c.Account{h, "dashboard", "convos", c.ConvoListPage{h, convos, c.Paginator{pageList, page, lastPage}}}
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, h, pi)
} }
func Convo(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, scid string) c.RouteError { func Convo(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, scid string) c.RouteError {
@ -99,12 +100,12 @@ func Convo(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, header, pi)
} }
func ConvosCreate(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func ConvosCreate(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
accountEditHead("create_convo", w, r, &user, header) accountEditHead("create_convo", w, r, &user, h)
header.AddNotice("convo_dev") h.AddNotice("convo_dev")
recpName := "" recpName := ""
pi := c.Account{header, "dashboard", "create_convo", c.ConvoCreatePage{header, recpName}} pi := c.Account{h, "dashboard", "create_convo", c.ConvoCreatePage{h, recpName}}
return renderTemplate("account", w, r, header, pi) return renderTemplate("account", w, r, h, pi)
} }
func ConvosCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func ConvosCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
@ -112,7 +113,7 @@ func ConvosCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if user.IsBanned { if !user.Perms.UseConvos {
return c.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
@ -131,6 +132,10 @@ func ConvosCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.R
} else if err != nil { } else if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// TODO: Should we kick them out of existing conversations if they're moved into a group without permission or the permission is revoked from their group? We might want to give them a chance to delete their messages though to avoid privacy headaches here and it may only be temporarily to tackle a specific incident.
if !u.Perms.UseConvos {
return c.LocalError("One of the recipients doesn't have permission to use the conversations system", w, r, user)
}
rlist = append(rlist, u.ID) rlist = append(rlist, u.ID)
} }
@ -168,7 +173,7 @@ func ConvosCreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if user.IsBanned { if !user.Perms.UseConvos {
return c.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
cid, err := strconv.Atoi(scid) cid, err := strconv.Atoi(scid)
@ -263,6 +268,9 @@ func ConvosEditReplySubmit(w http.ResponseWriter, r *http.Request, user c.User,
if err != nil { if err != nil {
return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user) return c.LocalError(p.GetErrorPhrase("id_must_be_integer"), w, r, user)
} }
if !user.Perms.UseConvos {
return c.NoPermissions(w, r, user)
}
js := (r.PostFormValue("js") == "1") js := (r.PostFormValue("js") == "1")
post := &c.ConversationPost{ID: cpid} post := &c.ConversationPost{ID: cpid}

View File

@ -38,15 +38,15 @@ func ForumList(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
var forumList []c.Forum var forumList []c.Forum
for _, fid := range canSee { for _, fid := range canSee {
// Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else // Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else
var forum = c.Forums.DirtyGet(fid).Copy() f := c.Forums.DirtyGet(fid).Copy()
if forum.ParentID == 0 && forum.Name != "" && forum.Active { if f.ParentID == 0 && f.Name != "" && f.Active {
if forum.LastTopicID != 0 { if f.LastTopicID != 0 {
if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 0 { if f.LastTopic.ID != 0 && f.LastReplyer.ID != 0 {
forum.LastTopicTime = c.RelativeTime(forum.LastTopic.LastReplyAt) f.LastTopicTime = c.RelativeTime(f.LastTopic.LastReplyAt)
} }
} }
header.Hooks.Hook("forums_frow_assign", &forum) header.Hooks.Hook("forums_frow_assign", &f)
forumList = append(forumList, forum) forumList = append(forumList, f)
} }
} }

View File

@ -52,28 +52,28 @@ func StaticFile(w http.ResponseWriter, r *http.Request) {
// Other options instead of io.Copy: io.CopyN(), w.Write(), http.ServeContent() // Other options instead of io.Copy: io.CopyN(), w.Write(), http.ServeContent()
} }
func Overview(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func Overview(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
header.Title = phrases.GetTitlePhrase("overview") h.Title = phrases.GetTitlePhrase("overview")
header.Zone = "overview" h.Zone = "overview"
return renderTemplate("overview", w, r, header, c.Page{header, tList, nil}) return renderTemplate("overview", w, r, h, c.Page{h, tList, nil})
} }
func CustomPage(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, name string) c.RouteError { func CustomPage(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header, name string) c.RouteError {
header.Zone = "custom_page" h.Zone = "custom_page"
name = c.SanitiseSingleLine(name) name = c.SanitiseSingleLine(name)
page, err := c.Pages.GetByName(name) page, err := c.Pages.GetByName(name)
if err == nil { if err == nil {
header.Title = page.Title h.Title = page.Title
return renderTemplate("custom_page", w, r, header, c.CustomPagePage{header, page}) return renderTemplate("custom_page", w, r, h, c.CustomPagePage{h, page})
} else if err != sql.ErrNoRows { } else if err != sql.ErrNoRows {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
header.Title = phrases.GetTitlePhrase("page") h.Title = phrases.GetTitlePhrase("page")
// TODO: Pass the page name to the pre-render hook? // TODO: Pass the page name to the pre-render hook?
err = renderTemplate3("page_"+name, "tmpl_page", w, r, header, c.Page{header, tList, nil}) err = renderTemplate3("page_"+name, "tmpl_page", w, r, h, c.Page{h, tList, nil})
if err == c.ErrBadDefaultTemplate { if err == c.ErrBadDefaultTemplate {
return c.NotFound(w, r, header) return c.NotFound(w, r, h)
} else if err != nil { } else if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
@ -84,7 +84,7 @@ func CustomPage(w http.ResponseWriter, r *http.Request, user c.User, header *c.H
func ChangeTheme(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func ChangeTheme(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
//headerLite, _ := SimpleUserCheck(w, r, &user) //headerLite, _ := SimpleUserCheck(w, r, &user)
// TODO: Rename js to something else, just in case we rewrite the JS side in WebAssembly? // TODO: Rename js to something else, just in case we rewrite the JS side in WebAssembly?
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
newTheme := c.SanitiseSingleLine(r.PostFormValue("newTheme")) newTheme := c.SanitiseSingleLine(r.PostFormValue("newTheme"))
theme, ok := c.Themes[newTheme] theme, ok := c.Themes[newTheme]

View File

@ -80,7 +80,7 @@ func GroupsEdit(w http.ResponseWriter, r *http.Request, user c.User, sgid string
//log.Print("aaaaa monsters") //log.Print("aaaaa monsters")
return c.NotFound(w, r, basePage.Header) return c.NotFound(w, r, basePage.Header)
} }
ferr = groupCheck(w,r,user,g,err) ferr = groupCheck(w, r, user, g, err)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
@ -122,7 +122,7 @@ func GroupsEditPromotions(w http.ResponseWriter, r *http.Request, user c.User, s
//log.Print("aaaaa monsters") //log.Print("aaaaa monsters")
return c.NotFound(w, r, basePage.Header) return c.NotFound(w, r, basePage.Header)
} }
ferr = groupCheck(w,r,user,g,err) ferr = groupCheck(w, r, user, g, err)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
@ -343,6 +343,7 @@ func GroupsEditPerms(w http.ResponseWriter, r *http.Request, user c.User, sgid s
addGlobalPerm("ViewIPs", g.Perms.ViewIPs) addGlobalPerm("ViewIPs", g.Perms.ViewIPs)
addGlobalPerm("UploadFiles", g.Perms.UploadFiles) addGlobalPerm("UploadFiles", g.Perms.UploadFiles)
addGlobalPerm("UploadAvatars", g.Perms.UploadAvatars) addGlobalPerm("UploadAvatars", g.Perms.UploadAvatars)
addGlobalPerm("UseConvos", g.Perms.UseConvos)
pi := c.PanelEditGroupPermsPage{basePage, g.ID, g.Name, localPerms, globalPerms} pi := c.PanelEditGroupPermsPage{basePage, g.ID, g.Name, localPerms, globalPerms}
return renderTemplate("panel_group_edit_perms", w, r, basePage.Header, pi) return renderTemplate("panel_group_edit_perms", w, r, basePage.Header, pi)

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
) )
func Settings(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func Settings(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
@ -24,33 +24,34 @@ func Settings(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
settingPhrases := phrases.GetAllSettingPhrases() settingPhrases := p.GetAllSettingPhrases()
var settingList []*c.PanelSetting var settingList []*c.PanelSetting
for _, settingPtr := range settings { for _, settingPtr := range settings {
setting := settingPtr.Copy() s := settingPtr.Copy()
if setting.Type == "list" { if s.Type == "list" {
llist := settingPhrases[setting.Name+"_label"] llist := settingPhrases[s.Name+"_label"]
labels := strings.Split(llist, ",") labels := strings.Split(llist, ",")
conv, err := strconv.Atoi(setting.Content) conv, err := strconv.Atoi(s.Content)
if err != nil { if err != nil {
return c.LocalError("The setting '"+setting.Name+"' can't be converted to an integer", w, r, user) return c.LocalError("The setting '"+s.Name+"' can't be converted to an integer", w, r, user)
} }
setting.Content = labels[conv-1] s.Content = labels[conv-1]
} else if setting.Type == "bool" { // TODO: Localise this
if setting.Content == "1" { } else if s.Type == "bool" {
setting.Content = "Yes" if s.Content == "1" {
s.Content = "Yes"
} else { } else {
setting.Content = "No" s.Content = "No"
} }
} else if setting.Type == "html-attribute" { } else if s.Type == "html-attribute" {
setting.Type = "textarea" s.Type = "textarea"
} }
settingList = append(settingList, &c.PanelSetting{setting, phrases.GetSettingPhrase(setting.Name)}) settingList = append(settingList, &c.PanelSetting{s, p.GetSettingPhrase(s.Name)})
} }
pi := c.PanelPage{basePage, tList, settingList} pi := c.PanelPage{basePage, tList, settingList}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_settings",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_settings", &pi})
} }
func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname string) c.RouteError { func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname string) c.RouteError {
@ -71,7 +72,7 @@ func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname stri
var itemList []c.OptionLabel var itemList []c.OptionLabel
if setting.Type == "list" { if setting.Type == "list" {
llist := phrases.GetSettingPhrase(setting.Name + "_label") llist := p.GetSettingPhrase(setting.Name + "_label")
conv, err := strconv.Atoi(setting.Content) conv, err := strconv.Atoi(setting.Content)
if err != nil { if err != nil {
return c.LocalError("The value of this setting couldn't be converted to an integer", w, r, user) return c.LocalError("The value of this setting couldn't be converted to an integer", w, r, user)
@ -88,9 +89,9 @@ func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname stri
setting.Type = "textarea" setting.Type = "textarea"
} }
pSetting := &c.PanelSetting{setting, phrases.GetSettingPhrase(setting.Name)} pSetting := &c.PanelSetting{setting, p.GetSettingPhrase(setting.Name)}
pi := c.PanelSettingPage{basePage, itemList, pSetting} pi := c.PanelSettingPage{basePage, itemList, pSetting}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_setting",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_setting", &pi})
} }
func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sname string) c.RouteError { func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sname string) c.RouteError {

View File

@ -34,7 +34,7 @@ func Themes(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
} }
pi := c.PanelThemesPage{basePage, pThemeList, vThemeList} pi := c.PanelThemesPage{basePage, pThemeList, vThemeList}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"panel_themes","","panel_themes",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_themes", "", "panel_themes", &pi})
} }
func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user c.User, uname string) c.RouteError { func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user c.User, uname string) c.RouteError {
@ -74,7 +74,7 @@ func ThemesMenus(w http.ResponseWriter, r *http.Request, user c.User) c.RouteErr
var menuList []c.PanelMenuListItem var menuList []c.PanelMenuListItem
for mid, list := range c.Menus.GetAllMap() { for mid, list := range c.Menus.GetAllMap() {
var name = "" name := ""
if mid == 1 { if mid == 1 {
name = p.GetTmplPhrase("panel_themes_menus_main") name = p.GetTmplPhrase("panel_themes_menus_main")
} }
@ -85,7 +85,7 @@ func ThemesMenus(w http.ResponseWriter, r *http.Request, user c.User) c.RouteErr
}) })
} }
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_themes_menus", &c.PanelMenuListPage{basePage, menuList}}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus", &c.PanelMenuListPage{basePage, menuList}})
} }
func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user c.User, smid string) c.RouteError { func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user c.User, smid string) c.RouteError {
@ -132,7 +132,7 @@ func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user c.User, smid s
menuList = append(menuList, item) menuList = append(menuList, item)
} }
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_themes_menus_items", &c.PanelMenuPage{basePage, mid, menuList}}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus_items", &c.PanelMenuPage{basePage, mid, menuList}})
} }
func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError {
@ -157,53 +157,53 @@ func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user c.User, sit
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_themes_menus_item_edit", &c.PanelMenuItemPage{basePage, menuItem}}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus_item_edit", &c.PanelMenuItemPage{basePage, menuItem}})
} }
func themesMenuItemSetters(r *http.Request, mItem c.MenuItem) c.MenuItem { func themesMenuItemSetters(r *http.Request, i c.MenuItem) c.MenuItem {
getItem := func(name string) string { getItem := func(name string) string {
return c.SanitiseSingleLine(r.PostFormValue("item-" + name)) return c.SanitiseSingleLine(r.PostFormValue("item-" + name))
} }
mItem.Name = getItem("name") i.Name = getItem("name")
mItem.HTMLID = getItem("htmlid") i.HTMLID = getItem("htmlid")
mItem.CSSClass = getItem("cssclass") i.CSSClass = getItem("cssclass")
mItem.Position = getItem("position") i.Position = getItem("position")
if mItem.Position != "left" && mItem.Position != "right" { if i.Position != "left" && i.Position != "right" {
mItem.Position = "left" i.Position = "left"
} }
mItem.Path = getItem("path") i.Path = getItem("path")
mItem.Aria = getItem("aria") i.Aria = getItem("aria")
mItem.Tooltip = getItem("tooltip") i.Tooltip = getItem("tooltip")
mItem.TmplName = getItem("tmplname") i.TmplName = getItem("tmplname")
switch getItem("permissions") { switch getItem("permissions") {
case "everyone": case "everyone":
mItem.GuestOnly = false i.GuestOnly = false
mItem.MemberOnly = false i.MemberOnly = false
mItem.SuperModOnly = false i.SuperModOnly = false
mItem.AdminOnly = false i.AdminOnly = false
case "guest-only": case "guest-only":
mItem.GuestOnly = true i.GuestOnly = true
mItem.MemberOnly = false i.MemberOnly = false
mItem.SuperModOnly = false i.SuperModOnly = false
mItem.AdminOnly = false i.AdminOnly = false
case "member-only": case "member-only":
mItem.GuestOnly = false i.GuestOnly = false
mItem.MemberOnly = true i.MemberOnly = true
mItem.SuperModOnly = false i.SuperModOnly = false
mItem.AdminOnly = false i.AdminOnly = false
case "supermod-only": case "supermod-only":
mItem.GuestOnly = false i.GuestOnly = false
mItem.MemberOnly = true i.MemberOnly = true
mItem.SuperModOnly = true i.SuperModOnly = true
mItem.AdminOnly = false i.AdminOnly = false
case "admin-only": case "admin-only":
mItem.GuestOnly = false i.GuestOnly = false
mItem.MemberOnly = true i.MemberOnly = true
mItem.SuperModOnly = true i.SuperModOnly = true
mItem.AdminOnly = true i.AdminOnly = true
} }
return mItem return i
} }
func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError {
@ -211,7 +211,7 @@ func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.Use
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }
@ -243,7 +243,7 @@ func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user c.U
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }
@ -270,7 +270,7 @@ func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.U
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }
@ -299,7 +299,7 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user c.Us
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }
@ -341,14 +341,14 @@ func ThemesWidgets(w http.ResponseWriter, r *http.Request, user c.User) c.RouteE
} }
basePage.Header.AddScript("widgets.js") basePage.Header.AddScript("widgets.js")
var docks = make(map[string][]c.WidgetEdit) docks := make(map[string][]c.WidgetEdit)
for _, name := range c.GetDockList() { for _, name := range c.GetDockList() {
if name == "leftOfNav" || name == "rightOfNav" { if name == "leftOfNav" || name == "rightOfNav" {
continue continue
} }
var widgets []c.WidgetEdit var widgets []c.WidgetEdit
for _, widget := range c.GetDock(name) { for _, widget := range c.GetDock(name) {
var data = make(map[string]string) data := make(map[string]string)
err := json.Unmarshal([]byte(widget.RawBody), &data) err := json.Unmarshal([]byte(widget.RawBody), &data)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
@ -359,12 +359,12 @@ func ThemesWidgets(w http.ResponseWriter, r *http.Request, user c.User) c.RouteE
} }
pi := c.PanelWidgetListPage{basePage, docks, c.WidgetEdit{&c.Widget{ID: 0, Type: "simple"}, make(map[string]string)}} pi := c.PanelWidgetListPage{basePage, docks, c.WidgetEdit{&c.Widget{ID: 0, Type: "simple"}, make(map[string]string)}}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_themes_widgets", pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_widgets", pi})
} }
func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error) { func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error) {
var data = make(map[string]string) data := make(map[string]string)
widget.Enabled = (r.FormValue("wenabled") == "1") widget.Enabled = r.FormValue("wenabled") == "1"
widget.Location = r.FormValue("wlocation") widget.Location = r.FormValue("wlocation")
if widget.Location == "" { if widget.Location == "" {
return nil, errors.New("You need to specify a location for this widget.") return nil, errors.New("You need to specify a location for this widget.")
@ -374,7 +374,7 @@ func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error
return nil, errors.New("The widget dock you specified doesn't exist.") return nil, errors.New("The widget dock you specified doesn't exist.")
} }
var wtype = r.FormValue("wtype") wtype := r.FormValue("wtype")
switch wtype { switch wtype {
case "simple", "about": case "simple", "about":
data["Name"] = r.FormValue("wname") data["Name"] = r.FormValue("wname")
@ -402,7 +402,7 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }
@ -435,7 +435,7 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget // ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
//fmt.Println("in ThemesWidgetsCreateSubmit") //fmt.Println("in ThemesWidgetsCreateSubmit")
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
_, ferr := c.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -462,7 +462,7 @@ func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.Us
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return c.NoPermissionsJSQ(w, r, user, js) return c.NoPermissionsJSQ(w, r, user, js)
} }

View File

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
func PollVote(w http.ResponseWriter, r *http.Request, user c.User, sPollID string) c.RouteError { func PollVote(w http.ResponseWriter, r *http.Request, user c.User, sPollID string) c.RouteError {
@ -57,7 +57,6 @@ func PollVote(w http.ResponseWriter, r *http.Request, user c.User, sPollID strin
if err != nil { if err != nil {
return c.LocalError("Malformed input", w, r, user) return c.LocalError("Malformed input", w, r, user)
} }
err = poll.CastVote(optionIndex, user.ID, user.LastIP) err = poll.CastVote(optionIndex, user.ID, user.LastIP)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
@ -88,7 +87,7 @@ func PollResults(w http.ResponseWriter, r *http.Request, user c.User, sPollID st
} }
defer rows.Close() defer rows.Close()
var optionList = "" optionList := ""
for rows.Next() { for rows.Next() {
var votes int var votes int
err := rows.Scan(&votes) err := rows.Scan(&votes)

View File

@ -19,16 +19,16 @@ func wsTopicList(topicList []*c.TopicsRow, lastPage int) *c.WsTopicList {
return &c.WsTopicList{wsTopicList, lastPage, 0} return &c.WsTopicList{wsTopicList, lastPage, 0}
} }
func TopicList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func TopicList(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
skip, rerr := header.Hooks.VhookSkippable("route_topic_list_start", w, r, &user, header) skip, rerr := h.Hooks.VhookSkippable("route_topic_list_start", w, r, &user, h)
if skip || rerr != nil { if skip || rerr != nil {
return rerr return rerr
} }
return TopicListCommon(w, r, user, header, "lastupdated", "") return TopicListCommon(w, r, user, h, "lastupdated", "")
} }
func TopicListMostViewed(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { func TopicListMostViewed(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
return TopicListCommon(w, r, user, header, "mostviewed", "most-viewed") return TopicListCommon(w, r, user, h, "mostviewed", "most-viewed")
} }
// TODO: Implement search // TODO: Implement search
@ -85,7 +85,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user c.User, header
var cfids []int var cfids []int
if len(fids) > 0 { if len(fids) > 0 {
var inSlice = func(haystack []int, needle int) bool { inSlice := func(haystack []int, needle int) bool {
for _, item := range haystack { for _, item := range haystack {
if needle == item { if needle == item {
return true return true
@ -117,7 +117,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user c.User, header
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var reqUserList = make(map[int]bool) reqUserList := make(map[int]bool)
for _, topic := range tMap { for _, topic := range tMap {
reqUserList[topic.CreatedBy] = true reqUserList[topic.CreatedBy] = true
reqUserList[topic.LastReplyBy] = true reqUserList[topic.LastReplyBy] = true
@ -126,7 +126,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user c.User, header
//fmt.Printf("reqUserList %+v\n", reqUserList) //fmt.Printf("reqUserList %+v\n", reqUserList)
// Convert the user ID map to a slice, then bulk load the users // Convert the user ID map to a slice, then bulk load the users
var idSlice = make([]int, len(reqUserList)) idSlice := make([]int, len(reqUserList))
var i int var i int
for userID := range reqUserList { for userID := range reqUserList {
idSlice[i] = userID idSlice[i] = userID

View File

@ -7,9 +7,9 @@ INSERT INTO [settings] ([name],[content],[type]) VALUES ('rapid_loading','1','bo
INSERT INTO [settings] ([name],[content],[type]) VALUES ('google_site_verify','','html-attribute'); INSERT INTO [settings] ([name],[content],[type]) VALUES ('google_site_verify','','html-attribute');
INSERT INTO [themes] ([uname],[default]) VALUES ('cosora',1); INSERT INTO [themes] ([uname],[default]) VALUES ('cosora',1);
INSERT INTO [emails] ([email],[uid],[validated]) VALUES ('admin@localhost',1,1); INSERT INTO [emails] ([email],[uid],[validated]) VALUES ('admin@localhost',1,1);
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[is_admin],[tag]) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin'); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[is_admin],[tag]) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[tag]) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod'); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[tag]) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_banned]) VALUES ('Banned','{"ViewTopic":true}','{}',1); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_banned]) VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}'); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[tag]) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest'); INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[tag]) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest');
@ -36,6 +36,6 @@ INSERT INTO [menu_items] ([mid],[htmlID],[cssClass],[position],[tmplName],[order
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3);
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4);
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[staffOnly],[order]) VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[staffOnly],[order]) VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5);
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?session={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[memberOnly],[order]) VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?s={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6);
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[guestOnly],[order]) VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[guestOnly],[order]) VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7);
INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[guestOnly],[order]) VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8); INSERT INTO [menu_items] ([mid],[name],[cssClass],[position],[path],[aria],[tooltip],[guestOnly],[order]) VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8);

View File

@ -15,9 +15,9 @@ INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('rapid_loading','1','boo
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('google_site_verify','','html-attribute'); INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('google_site_verify','','html-attribute');
INSERT INTO `themes`(`uname`,`default`) VALUES ('cosora',1); INSERT INTO `themes`(`uname`,`default`) VALUES ('cosora',1);
INSERT INTO `emails`(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1); INSERT INTO `emails`(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1);
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin'); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod'); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}','{}',1); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}'); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest'); INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest');
@ -44,6 +44,6 @@ INSERT INTO `menu_items`(`mid`,`htmlID`,`cssClass`,`position`,`tmplName`,`order`
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3);
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4);
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`staffOnly`,`order`) VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`staffOnly`,`order`) VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5);
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?session={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`memberOnly`,`order`) VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?s={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6);
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`guestOnly`,`order`) VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`guestOnly`,`order`) VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7);
INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`guestOnly`,`order`) VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8); INSERT INTO `menu_items`(`mid`,`name`,`cssClass`,`position`,`path`,`aria`,`tooltip`,`guestOnly`,`order`) VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8);

View File

@ -7,9 +7,9 @@ INSERT INTO "settings"("name","content","type") VALUES ('rapid_loading','1','boo
INSERT INTO "settings"("name","content","type") VALUES ('google_site_verify','','html-attribute'); INSERT INTO "settings"("name","content","type") VALUES ('google_site_verify','','html-attribute');
INSERT INTO "themes"("uname","default") VALUES ('cosora',1); INSERT INTO "themes"("uname","default") VALUES ('cosora',1);
INSERT INTO "emails"("email","uid","validated") VALUES ('admin@localhost',1,1); INSERT INTO "emails"("email","uid","validated") VALUES ('admin@localhost',1,1);
INSERT INTO "users_groups"("name","permissions","plugin_perms","is_mod","is_admin","tag") VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin'); INSERT INTO "users_groups"("name","permissions","plugin_perms","is_mod","is_admin","tag") VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,1,'Admin');
INSERT INTO "users_groups"("name","permissions","plugin_perms","is_mod","tag") VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod'); INSERT INTO "users_groups"("name","permissions","plugin_perms","is_mod","tag") VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}','{}',1,'Mod');
INSERT INTO "users_groups"("name","permissions","plugin_perms") VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'); INSERT INTO "users_groups"("name","permissions","plugin_perms") VALUES ('Member','{"UploadFiles":true,"UploadAvatars":true,"UseConvos":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO "users_groups"("name","permissions","plugin_perms","is_banned") VALUES ('Banned','{"ViewTopic":true}','{}',1); INSERT INTO "users_groups"("name","permissions","plugin_perms","is_banned") VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO "users_groups"("name","permissions","plugin_perms") VALUES ('Awaiting Activation','{"ViewTopic":true}','{}'); INSERT INTO "users_groups"("name","permissions","plugin_perms") VALUES ('Awaiting Activation','{"ViewTopic":true}','{}');
INSERT INTO "users_groups"("name","permissions","plugin_perms","tag") VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest'); INSERT INTO "users_groups"("name","permissions","plugin_perms","tag") VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest');
@ -36,6 +36,6 @@ INSERT INTO "menu_items"("mid","htmlID","cssClass","position","tmplName","order"
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_account}','menu_account','left','/user/edit/','{lang.menu_account_aria}','{lang.menu_account_tooltip}',1,3);
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_profile}','menu_profile','left','{me.Link}','{lang.menu_profile_aria}','{lang.menu_profile_tooltip}',1,4);
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","staffOnly","order") VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","staffOnly","order") VALUES (1,'{lang.menu_panel}','menu_panel menu_account','left','/panel/','{lang.menu_panel_aria}','{lang.menu_panel_tooltip}',1,1,5);
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?session={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","memberOnly","order") VALUES (1,'{lang.menu_logout}','menu_logout','left','/accounts/logout/?s={me.Session}','{lang.menu_logout_aria}','{lang.menu_logout_tooltip}',1,6);
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","guestOnly","order") VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","guestOnly","order") VALUES (1,'{lang.menu_register}','menu_register','left','/accounts/create/','{lang.menu_register_aria}','{lang.menu_register_tooltip}',1,7);
INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","guestOnly","order") VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8); INSERT INTO "menu_items"("mid","name","cssClass","position","path","aria","tooltip","guestOnly","order") VALUES (1,'{lang.menu_login}','menu_login','left','/accounts/login/','{lang.menu_login_aria}','{lang.menu_login_tooltip}',1,8);

View File

@ -9,12 +9,12 @@
<div id="poweredBy"> <div id="poweredBy">
<a id="poweredByName" href="https://github.com/Azareal/Gosora">{{lang "footer_powered_by"}}</a><span id="poweredByDash"> - </span><span id="poweredByMaker">{{lang "footer_made_with_love"}}</span> <a id="poweredByName" href="https://github.com/Azareal/Gosora">{{lang "footer_powered_by"}}</a><span id="poweredByDash"> - </span><span id="poweredByMaker">{{lang "footer_made_with_love"}}</span>
</div> </div>
{{/**{{if .CurrentUser.IsAdmin}}**/}}<div title="start to before tmpl" class="elapsed">{{.Header.Elapsed1}}</div><div title="start to footer" class="elapsed">{{elapsed .Header.StartedAt}}</div>{{/**{{end}}**/}} {{if .CurrentUser.IsAdmin}}<div title="start to before tmpl" class="elapsed">{{.Header.Elapsed1}}</div><div title="start to footer" class="elapsed">{{elapsed .Header.StartedAt}}</div>{{end}}
<form action="/theme/" method="post"> <form action="/theme/" method="post">
<div id="themeSelector"> <div id="themeSelector">
<select id="themeSelectorSelect" name="themeSelector" aria-label="{{lang "footer_theme_selector_aria"}}">{{range .Header.Themes}} <select id="themeSelectorSelect" name="themeSelector" aria-label="{{lang "footer_theme_selector_aria"}}">{{range .Header.Themes}}{{if not .HideFromThemes}}
{{if not .HideFromThemes}}<option val="{{.Name}}"{{if eq $.Header.Theme.Name .Name}} selected{{end}}>{{.FriendlyName}}</option>{{end}} <option val="{{.Name}}"{{if eq $.Header.Theme.Name .Name}} selected{{end}}>{{.FriendlyName}}</option>
{{end}}</select> {{end}}{{end}}</select>
<noscript><input type="submit" /></noscript> <noscript><input type="submit" /></noscript>
</div> </div>
</form> </form>

View File

@ -1 +1 @@
<nav class="colstack_left" aria-label="{{lang "panel_menu_aria"}}">{{template "panel_inner_menu.html" . }}</nav> <nav class="colstack_left" aria-label="{{lang "panel_menu_aria"}}">{{template "panel_inner_menu.html" . }}</nav>

View File

@ -15,8 +15,7 @@ import (
// TODO: Name the tasks so we can figure out which one it was when something goes wrong? Or maybe toss it up WithStack down there? // TODO: Name the tasks so we can figure out which one it was when something goes wrong? Or maybe toss it up WithStack down there?
func runTasks(tasks []func() error) { func runTasks(tasks []func() error) {
for _, task := range tasks { for _, task := range tasks {
err := task() if err := task(); err != nil {
if err != nil {
c.LogError(err) c.LogError(err)
} }
} }
@ -24,8 +23,7 @@ func runTasks(tasks []func() error) {
func startTick() (abort bool) { func startTick() (abort bool) {
isDBDown := atomic.LoadInt32(&c.IsDBDown) isDBDown := atomic.LoadInt32(&c.IsDBDown)
err := db.Ping() if err := db.Ping(); err != nil {
if err != nil {
// TODO: There's a bit of a race here, but it doesn't matter if this error appears multiple times in the logs as it's capped at three times, we just want to cut it down 99% of the time // TODO: There's a bit of a race here, but it doesn't matter if this error appears multiple times in the logs as it's capped at three times, we just want to cut it down 99% of the time
if isDBDown == 0 { if isDBDown == 0 {
db.SetConnMaxLifetime(time.Second) // Drop all the connections and start over db.SetConnMaxLifetime(time.Second) // Drop all the connections and start over
@ -45,8 +43,7 @@ func startTick() (abort bool) {
} }
func runHook(name string) { func runHook(name string) {
err := c.RunTaskHook(name) if err := c.RunTaskHook(name); err != nil {
if err != nil {
c.LogError(err, "Failed at task '"+name+"'") c.LogError(err, "Failed at task '"+name+"'")
} }
} }
@ -88,16 +85,14 @@ func tickLoop(thumbChan chan bool) {
runTasks(c.ScheduledSecondTasks) runTasks(c.ScheduledSecondTasks)
// TODO: Stop hard-coding this // TODO: Stop hard-coding this
err := c.HandleExpiredScheduledGroups() if err := c.HandleExpiredScheduledGroups(); err != nil {
if err != nil {
c.LogError(err) c.LogError(err)
} }
// TODO: Handle delayed moderation tasks // TODO: Handle delayed moderation tasks
// Sync with the database, if there are any changes // Sync with the database, if there are any changes
err = c.HandleServerSync() if err = c.HandleServerSync(); err != nil {
if err != nil {
c.LogError(err) c.LogError(err)
} }
@ -164,35 +159,30 @@ func dailies() {
} }
if c.Config.LogPruneCutoff > -1 { if c.Config.LogPruneCutoff > -1 {
_, err := qgen.NewAcc().Delete("login_logs").DateOlderThan("doneAt",c.Config.LogPruneCutoff,"day").Run() f := func(tbl string) {
if err != nil { _, err := qgen.NewAcc().Delete(tbl).DateOlderThan("doneAt",c.Config.LogPruneCutoff,"day").Run()
c.LogError(err) if err != nil {
} c.LogError(err)
_, err = qgen.NewAcc().Delete("registration_logs").DateOlderThan("doneAt",c.Config.LogPruneCutoff,"day").Run() }
if err != nil {
c.LogError(err)
} }
f("login_logs")
f("registration_logs")
} }
if c.Config.PostIPCutoff > -1 { if c.Config.PostIPCutoff > -1 {
// TODO: Use unixtime to remove this MySQLesque logic? // TODO: Use unixtime to remove this MySQLesque logic?
_, err := qgen.NewAcc().Update("topics").Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec() f := func(tbl string) {
if err != nil { _, err := qgen.NewAcc().Update(tbl).Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec()
c.LogError(err) if err != nil {
c.LogError(err)
}
} }
f("topics")
f("replies")
f("users_replies")
_, err = qgen.NewAcc().Update("replies").Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec()
if err != nil {
c.LogError(err)
}
// TODO: Find some way of purging the ip data in polls_votes without breaking any anti-cheat measures which might be running... maybe hash it instead? // TODO: Find some way of purging the ip data in polls_votes without breaking any anti-cheat measures which might be running... maybe hash it instead?
_, err = qgen.NewAcc().Update("users_replies").Set("ipaddress = '0'").DateOlderThan("createdAt",c.Config.PostIPCutoff,"day").Where("ipaddress != '0'").Exec()
if err != nil {
c.LogError(err)
}
// TODO: lastActiveAt isn't currently set, so we can't rely on this to purge last_ips of users who haven't been on in a while // TODO: lastActiveAt isn't currently set, so we can't rely on this to purge last_ips of users who haven't been on in a while
/*_, err = qgen.NewAcc().Update("users").Set("last_ip = '0'").DateOlderThan("lastActiveAt",c.Config.PostIPCutoff,"day").Where("last_ip != '0'").Exec() /*_, err = qgen.NewAcc().Update("users").Set("last_ip = '0'").DateOlderThan("lastActiveAt",c.Config.PostIPCutoff,"day").Where("last_ip != '0'").Exec()
if err != nil { if err != nil {