From 20a6a22e7819e217bf7af712c9fbd2fcef668f4a Mon Sep 17 00:00:00 2001 From: Azareal Date: Fri, 19 Apr 2019 16:36:26 +1000 Subject: [PATCH] Shorten the common namespaces in some areas to reduce the amount of boilerplate. --- cmd/elasticsearch/setup.go | 18 +- common/counters/agents.go | 12 +- common/counters/forums.go | 10 +- common/counters/langs.go | 12 +- common/counters/posts.go | 10 +- common/counters/topics_views.go | 12 +- extend/guilds/lib/guilds.go | 172 ++++++------ patcher/main.go | 18 +- routes/account.go | 446 ++++++++++++++++---------------- routes/api.go | 86 +++--- routes/attachments.go | 70 ++--- routes/common.go | 18 +- routes/forum.go | 46 ++-- routes/forum_list.go | 22 +- routes/misc.go | 42 +-- routes/moderate.go | 22 +- routes/panel/analytics.go | 300 ++++++++++----------- routes/panel/backups.go | 18 +- routes/panel/common.go | 16 +- routes/panel/debug.go | 8 +- routes/panel/themes.go | 208 +++++++-------- routes/poll.go | 54 ++-- routes/profile.go | 42 +-- routes/reply.go | 298 ++++++++++----------- routes/reports.go | 46 ++-- routes/topic.go | 422 +++++++++++++++--------------- routes/topic_list.go | 72 +++--- 27 files changed, 1250 insertions(+), 1250 deletions(-) diff --git a/cmd/elasticsearch/setup.go b/cmd/elasticsearch/setup.go index f2a874ae..ffaa73c5 100644 --- a/cmd/elasticsearch/setup.go +++ b/cmd/elasticsearch/setup.go @@ -10,25 +10,25 @@ import ( "os" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" "gopkg.in/olivere/elastic.v6" ) func main() { log.Print("Loading the configuration data") - err := common.LoadConfig() + err := c.LoadConfig() if err != nil { log.Fatal(err) } log.Print("Processing configuration data") - err = common.ProcessConfig() + err = c.ProcessConfig() if err != nil { log.Fatal(err) } - if common.DbConfig.Adapter != "mysql" && common.DbConfig.Adapter != "" { + if c.DbConfig.Adapter != "mysql" && c.DbConfig.Adapter != "" { log.Fatal("Only MySQL is supported for upgrades right now, please wait for a newer build of the patcher") } @@ -59,11 +59,11 @@ func main() { func prepMySQL() error { return qgen.Builder.Init("mysql", map[string]string{ - "host": common.DbConfig.Host, - "port": common.DbConfig.Port, - "name": common.DbConfig.Dbname, - "username": common.DbConfig.Username, - "password": common.DbConfig.Password, + "host": c.DbConfig.Host, + "port": c.DbConfig.Port, + "name": c.DbConfig.Dbname, + "username": c.DbConfig.Username, + "password": c.DbConfig.Password, "collation": "utf8mb4_general_ci", }) } diff --git a/common/counters/agents.go b/common/counters/agents.go index fb9bacdb..c3980755 100644 --- a/common/counters/agents.go +++ b/common/counters/agents.go @@ -3,7 +3,7 @@ package counters import ( "database/sql" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) @@ -23,9 +23,9 @@ func NewDefaultAgentViewCounter(acc *qgen.Accumulator) (*DefaultAgentViewCounter agentBuckets: agentBuckets, insert: acc.Insert("viewchunks_agents").Columns("count, createdAt, browser").Fields("?,UTC_TIMESTAMP(),?").Prepare(), } - common.AddScheduledFifteenMinuteTask(counter.Tick) - //common.AddScheduledSecondTask(counter.Tick) - common.AddShutdownTask(counter.Tick) + c.AddScheduledFifteenMinuteTask(counter.Tick) + //c.AddScheduledSecondTask(counter.Tick) + c.AddShutdownTask(counter.Tick) return counter, acc.FirstError() } @@ -50,14 +50,14 @@ func (counter *DefaultAgentViewCounter) insertChunk(count int, agent int) error return nil } var agentName = reverseAgentMapEnum[agent] - common.DebugLogf("Inserting a viewchunk with a count of %d for agent %s (%d)", count, agentName, agent) + c.DebugLogf("Inserting a viewchunk with a count of %d for agent %s (%d)", count, agentName, agent) _, err := counter.insert.Exec(count, agentName) return err } func (counter *DefaultAgentViewCounter) Bump(agent int) { // TODO: Test this check - common.DebugDetail("counter.agentBuckets[", agent, "]: ", counter.agentBuckets[agent]) + c.DebugDetail("counter.agentBuckets[", agent, "]: ", counter.agentBuckets[agent]) if len(counter.agentBuckets) <= agent || agent < 0 { return } diff --git a/common/counters/forums.go b/common/counters/forums.go index a929f4b4..8390115f 100644 --- a/common/counters/forums.go +++ b/common/counters/forums.go @@ -4,7 +4,7 @@ import ( "database/sql" "sync" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) @@ -28,9 +28,9 @@ func NewDefaultForumViewCounter() (*DefaultForumViewCounter, error) { evenMap: make(map[int]*RWMutexCounterBucket), insert: acc.Insert("viewchunks_forums").Columns("count, createdAt, forum").Fields("?,UTC_TIMESTAMP(),?").Prepare(), } - common.AddScheduledFifteenMinuteTask(counter.Tick) // There could be a lot of routes, so we don't want to be running this every second - //common.AddScheduledSecondTask(counter.Tick) - common.AddShutdownTask(counter.Tick) + c.AddScheduledFifteenMinuteTask(counter.Tick) // There could be a lot of routes, so we don't want to be running this every second + //c.AddScheduledSecondTask(counter.Tick) + c.AddShutdownTask(counter.Tick) return counter, acc.FirstError() } @@ -78,7 +78,7 @@ func (counter *DefaultForumViewCounter) insertChunk(count int, forum int) error if count == 0 { return nil } - common.DebugLogf("Inserting a viewchunk with a count of %d for forum %d", count, forum) + c.DebugLogf("Inserting a viewchunk with a count of %d for forum %d", count, forum) _, err := counter.insert.Exec(count, forum) return err } diff --git a/common/counters/langs.go b/common/counters/langs.go index d2f6a384..74e96945 100644 --- a/common/counters/langs.go +++ b/common/counters/langs.go @@ -1,7 +1,7 @@ package counters import "database/sql" -import "github.com/Azareal/Gosora/common" +import c "github.com/Azareal/Gosora/common" import "github.com/Azareal/Gosora/query_gen" var LangViewCounter *DefaultLangViewCounter @@ -116,9 +116,9 @@ func NewDefaultLangViewCounter(acc *qgen.Accumulator) (*DefaultLangViewCounter, insert: acc.Insert("viewchunks_langs").Columns("count, createdAt, lang").Fields("?,UTC_TIMESTAMP(),?").Prepare(), } - common.AddScheduledFifteenMinuteTask(counter.Tick) - //common.AddScheduledSecondTask(counter.Tick) - common.AddShutdownTask(counter.Tick) + c.AddScheduledFifteenMinuteTask(counter.Tick) + //c.AddScheduledSecondTask(counter.Tick) + c.AddShutdownTask(counter.Tick) return counter, acc.FirstError() } @@ -143,7 +143,7 @@ func (counter *DefaultLangViewCounter) insertChunk(count int, id int) error { return nil } var langCode = langCodes[id] - common.DebugLogf("Inserting a viewchunk with a count of %d for lang %s (%d)", count, langCode, id) + c.DebugLogf("Inserting a viewchunk with a count of %d for lang %s (%d)", count, langCode, id) _, err := counter.insert.Exec(count, langCode) return err } @@ -158,7 +158,7 @@ func (counter *DefaultLangViewCounter) Bump(langCode string) (validCode bool) { } // TODO: Test this check - common.DebugDetail("counter.buckets[", id, "]: ", counter.buckets[id]) + c.DebugDetail("counter.buckets[", id, "]: ", counter.buckets[id]) if len(counter.buckets) <= id || id < 0 { return validCode } diff --git a/common/counters/posts.go b/common/counters/posts.go index e935eba3..fa6cedd0 100644 --- a/common/counters/posts.go +++ b/common/counters/posts.go @@ -4,7 +4,7 @@ import ( "database/sql" "sync/atomic" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) @@ -23,9 +23,9 @@ func NewPostCounter() (*DefaultPostCounter, error) { currentBucket: 0, insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), } - common.AddScheduledFifteenMinuteTask(counter.Tick) - //common.AddScheduledSecondTask(counter.Tick) - common.AddShutdownTask(counter.Tick) + c.AddScheduledFifteenMinuteTask(counter.Tick) + //c.AddScheduledSecondTask(counter.Tick) + c.AddShutdownTask(counter.Tick) return counter, acc.FirstError() } @@ -52,7 +52,7 @@ func (counter *DefaultPostCounter) insertChunk(count int64) error { if count == 0 { return nil } - common.DebugLogf("Inserting a postchunk with a count of %d", count) + c.DebugLogf("Inserting a postchunk with a count of %d", count) _, err := counter.insert.Exec(count) return err } diff --git a/common/counters/topics_views.go b/common/counters/topics_views.go index 19e114f9..3a12e367 100644 --- a/common/counters/topics_views.go +++ b/common/counters/topics_views.go @@ -5,7 +5,7 @@ import ( "sync" "sync/atomic" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) @@ -28,9 +28,9 @@ func NewDefaultTopicViewCounter() (*DefaultTopicViewCounter, error) { evenTopics: make(map[int]*RWMutexCounterBucket), update: acc.Update("topics").Set("views = views + ?").Where("tid = ?").Prepare(), } - common.AddScheduledFifteenMinuteTask(counter.Tick) // Who knows how many topics we have queued up, we probably don't want this running too frequently - //common.AddScheduledSecondTask(counter.Tick) - common.AddShutdownTask(counter.Tick) + c.AddScheduledFifteenMinuteTask(counter.Tick) // Who knows how many topics we have queued up, we probably don't want this running too frequently + //c.AddScheduledSecondTask(counter.Tick) + c.AddShutdownTask(counter.Tick) return counter, acc.FirstError() } @@ -82,14 +82,14 @@ func (counter *DefaultTopicViewCounter) insertChunk(count int, topicID int) erro return nil } - common.DebugLogf("Inserting %d views into topic %d", count, topicID) + c.DebugLogf("Inserting %d views into topic %d", count, topicID) _, err := counter.update.Exec(count, topicID) if err != nil { return err } // TODO: Add a way to disable this for extra speed ;) - tcache := common.Topics.GetCache() + tcache := c.Topics.GetCache() if tcache != nil { topic, err := tcache.Get(topicID) if err != nil { diff --git a/extend/guilds/lib/guilds.go b/extend/guilds/lib/guilds.go index bdf9bf5d..77342aba 100644 --- a/extend/guilds/lib/guilds.go +++ b/extend/guilds/lib/guilds.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) // A blank list to fill out that parameter in Page for routes which don't use it @@ -43,16 +43,16 @@ type Guild struct { LastUpdateTime string MainForumID int - MainForum *common.Forum - Forums []*common.Forum - ExtData common.ExtData + MainForum *c.Forum + Forums []*c.Forum + ExtData c.ExtData } type Page struct { Title string - Header *common.Header - ItemList []*common.TopicsRow - Forum *common.Forum + Header *c.Header + ItemList []*c.TopicsRow + Forum *c.Forum Guild *Guild Page int LastPage int @@ -61,13 +61,13 @@ type Page struct { // ListPage is a page struct for constructing a list of every guild type ListPage struct { Title string - Header *common.Header + Header *c.Header GuildList []*Guild } type MemberListPage struct { Title string - Header *common.Header + Header *c.Header ItemList []Member Guild *Guild Page int @@ -83,15 +83,15 @@ type Member struct { JoinedAt string Offline bool // TODO: Need to track the online states of members when WebSockets are enabled - User common.User + User c.User } -func PrebuildTmplList(user common.User, header *common.Header) common.CTmpl { +func PrebuildTmplList(user c.User, header *c.Header) c.CTmpl { var guildList = []*Guild{ &Guild{ ID: 1, Name: "lol", - Link: BuildGuildURL(common.NameToSlug("lol"), 1), + Link: BuildGuildURL(c.NameToSlug("lol"), 1), Desc: "A group for people who like to laugh", Active: true, MemberCount: 1, @@ -99,26 +99,26 @@ func PrebuildTmplList(user common.User, header *common.Header) common.CTmpl { CreatedAt: "date", LastUpdateTime: "date", MainForumID: 1, - MainForum: common.Forums.DirtyGet(1), - Forums: []*common.Forum{common.Forums.DirtyGet(1)}, + MainForum: c.Forums.DirtyGet(1), + Forums: []*c.Forum{c.Forums.DirtyGet(1)}, }, } listPage := ListPage{"Guild List", user, header, guildList} - return common.CTmpl{"guilds_guild_list", "guilds_guild_list.html", "templates/", "guilds.ListPage", listPage, []string{"./extend/guilds/lib"}} + return c.CTmpl{"guilds_guild_list", "guilds_guild_list.html", "templates/", "guilds.ListPage", listPage, []string{"./extend/guilds/lib"}} } // TODO: Do this properly via the widget system // TODO: REWRITE THIS -func CommonAreaWidgets(header *common.Header) { +func CommonAreaWidgets(header *c.Header) { // TODO: Hot Groups? Featured Groups? Official Groups? var b bytes.Buffer - var menu = common.WidgetMenu{"Guilds", []common.WidgetMenuItem{ - common.WidgetMenuItem{"Create Guild", "/guild/create/", false}, + var menu = c.WidgetMenu{"Guilds", []c.WidgetMenuItem{ + c.WidgetMenuItem{"Create Guild", "/guild/create/", false}, }} err := header.Theme.RunTmpl("widget_menu", pi, w) if err != nil { - common.LogError(err) + c.LogError(err) return } @@ -131,7 +131,7 @@ func CommonAreaWidgets(header *common.Header) { // TODO: Do this properly via the widget system // TODO: Make a better more customisable group widget system -func GuildWidgets(header *common.Header, guildItem *Guild) (success bool) { +func GuildWidgets(header *c.Header, guildItem *Guild) (success bool) { return false // Disabled until the next commit /*var b bytes.Buffer @@ -142,7 +142,7 @@ func GuildWidgets(header *common.Header, guildItem *Guild) (success bool) { err := templates.ExecuteTemplate(&b, "widget_menu.html", menu) if err != nil { - common.LogError(err) + c.LogError(err) return false } @@ -160,16 +160,16 @@ func GuildWidgets(header *common.Header, guildItem *Guild) (success bool) { Custom Pages */ -func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - header, ferr := common.UserCheck(w, r, &user) +func RouteGuildList(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + header, ferr := c.UserCheck(w, r, &user) if ferr != nil { return ferr } CommonAreaWidgets(header) rows, err := ListStmt.Query() - if err != nil && err != common.ErrNoRows { - return common.InternalError(err, w, r) + if err != nil && err != c.ErrNoRows { + return c.InternalError(err, w, r) } defer rows.Close() @@ -178,37 +178,37 @@ func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) co guildItem := &Guild{ID: 0} err := rows.Scan(&guildItem.ID, &guildItem.Name, &guildItem.Desc, &guildItem.Active, &guildItem.Privacy, &guildItem.Joinable, &guildItem.Owner, &guildItem.MemberCount, &guildItem.CreatedAt, &guildItem.LastUpdateTime) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - guildItem.Link = BuildGuildURL(common.NameToSlug(guildItem.Name), guildItem.ID) + guildItem.Link = BuildGuildURL(c.NameToSlug(guildItem.Name), guildItem.ID) guildList = append(guildList, guildItem) } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } pi := ListPage{"Guild List", user, header, guildList} err = header.Theme.RunTmpl("guilds_guild_list", pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } -func MiddleViewGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func MiddleViewGuild(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { _, guildID, err := routes.ParseSEOURL(r.URL.Path[len("/guild/"):]) if err != nil { - return common.PreError("Not a valid guild ID", w, r) + return c.PreError("Not a valid guild ID", w, r) } guildItem, err := Gstore.Get(guildID) if err != nil { - return common.LocalError("Bad guild", w, r, user) + return c.LocalError("Bad guild", w, r, user) } // TODO: Build and pass header if !guildItem.Active { - return common.NotFound(w, r, nil) + return c.NotFound(w, r, nil) } return nil @@ -219,36 +219,36 @@ func MiddleViewGuild(w http.ResponseWriter, r *http.Request, user common.User) c //return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID)) } -func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - header, ferr := common.UserCheck(w, r, &user) +func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + header, ferr := c.UserCheck(w, r, &user) if ferr != nil { return ferr } header.Title = "Create Guild" // TODO: Add an approval queue mode for group creation if !user.Loggedin || !user.PluginPerms["CreateGuild"] { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } CommonAreaWidgets(header) - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} err := header.Theme.RunTmpl("guilds_create_guild", pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } -func RouteCreateGuildSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func RouteCreateGuildSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { // TODO: Add an approval queue mode for group creation if !user.Loggedin || !user.PluginPerms["CreateGuild"] { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } var guildActive = true - var guildName = common.SanitiseSingleLine(r.PostFormValue("group_name")) + var guildName = c.SanitiseSingleLine(r.PostFormValue("group_name")) // TODO: Allow Markdown / BBCode / Limited HTML in the description? - var guildDesc = common.SanitiseBody(r.PostFormValue("group_desc")) + var guildDesc = c.SanitiseBody(r.PostFormValue("group_desc")) var gprivacy = r.PostFormValue("group_privacy") var guildPrivacy int @@ -264,53 +264,53 @@ func RouteCreateGuildSubmit(w http.ResponseWriter, r *http.Request, user common. } // Create the backing forum - fid, err := common.Forums.Create(guildName, "", true, "") + fid, err := c.Forums.Create(guildName, "", true, "") if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } gid, err := Gstore.Create(guildName, guildDesc, guildActive, guildPrivacy, user.ID, fid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Add the main backing forum to the forum list err = AttachForum(gid, fid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } _, err = AddMemberStmt.Exec(gid, user.ID, 2) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - http.Redirect(w, r, BuildGuildURL(common.NameToSlug(guildName), gid), http.StatusSeeOther) + http.Redirect(w, r, BuildGuildURL(c.NameToSlug(guildName), gid), http.StatusSeeOther) return nil } -func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - header, ferr := common.UserCheck(w, r, &user) +func RouteMemberList(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + header, ferr := c.UserCheck(w, r, &user) if ferr != nil { return ferr } _, guildID, err := routes.ParseSEOURL(r.URL.Path[len("/guild/members/"):]) if err != nil { - return common.PreError("Not a valid group ID", w, r) + return c.PreError("Not a valid group ID", w, r) } guildItem, err := Gstore.Get(guildID) if err != nil { - return common.LocalError("Bad group", w, r, user) + return c.LocalError("Bad group", w, r, user) } - guildItem.Link = BuildGuildURL(common.NameToSlug(guildItem.Name), guildItem.ID) + guildItem.Link = BuildGuildURL(c.NameToSlug(guildItem.Name), guildItem.ID) GuildWidgets(header, guildItem) rows, err := MemberListJoinStmt.Query(guildID) - if err != nil && err != common.ErrNoRows { - return common.InternalError(err, w, r) + if err != nil && err != c.ErrNoRows { + return c.InternalError(err, w, r) } var guildMembers []Member @@ -318,11 +318,11 @@ func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) c guildMember := Member{PostCount: 0} err := rows.Scan(&guildMember.User.ID, &guildMember.Rank, &guildMember.PostCount, &guildMember.JoinedAt, &guildMember.User.Name, &guildMember.User.RawAvatar) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - guildMember.Link = common.BuildProfileURL(common.NameToSlug(guildMember.User.Name), guildMember.User.ID) - guildMember.User.Avatar, guildMember.User.MicroAvatar = common.BuildAvatar(guildMember.User.ID, guildMember.User.RawAvatar) - guildMember.JoinedAt, _ = common.RelativeTimeFromString(guildMember.JoinedAt) + guildMember.Link = c.BuildProfileURL(c.NameToSlug(guildMember.User.Name), guildMember.User.ID) + guildMember.User.Avatar, guildMember.User.MicroAvatar = c.BuildAvatar(guildMember.User.ID, guildMember.User.RawAvatar) + guildMember.JoinedAt, _ = c.RelativeTimeFromString(guildMember.JoinedAt) if guildItem.Owner == guildMember.User.ID { guildMember.RankString = "Owner" } else { @@ -339,18 +339,18 @@ func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) c } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } rows.Close() pi := MemberListPage{"Guild Member List", user, header, guildMembers, guildItem, 0, 0} // A plugin with plugins. Pluginception! - if common.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { + if c.RunPreRenderHook("pre_render_guilds_member_list", w, r, &user, &pi) { return nil } - err = common.RunThemeTemplate(header.Theme.Name, "guilds_member_list", pi, w) + err = c.RunThemeTemplate(header.Theme.Name, "guilds_member_list", pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } @@ -366,7 +366,7 @@ func UnattachForum(fid int) error { } func BuildGuildURL(slug string, id int) string { - if slug == "" || !common.Config.BuildSlugs { + if slug == "" || !c.Config.BuildSlugs { return "/guild/" + strconv.Itoa(id) } return "/guild/" + slug + "." + strconv.Itoa(id) @@ -377,8 +377,8 @@ func BuildGuildURL(slug string, id int) string { */ // TODO: Prebuild this template -func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.User, data interface{}) (halt bool) { - pi := data.(*common.ForumPage) +func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *c.User, data interface{}) (halt bool) { + pi := data.(*c.ForumPage) if pi.Header.ExtData.Items != nil { if guildData, ok := pi.Header.ExtData.Items["guilds_current_group"]; ok { guildItem := guildData.(*Guild) @@ -386,7 +386,7 @@ func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.Use guildpi := Page{pi.Title, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage} err := header.Theme.RunTmpl("guilds_view_guild", guildpi, w) if err != nil { - common.LogError(err) + c.LogError(err) return false } return true @@ -396,10 +396,10 @@ func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.Use } func TrowAssign(args ...interface{}) interface{} { - var forum = args[1].(*common.Forum) + var forum = args[1].(*c.Forum) if forum.ParentType == "guild" { - var topicItem = args[0].(*common.TopicsRow) - topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, common.GetForumURLPrefix()) + var topicItem = args[0].(*c.TopicsRow) + topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, c.GetForumURLPrefix()) } return nil } @@ -407,7 +407,7 @@ func TrowAssign(args ...interface{}) interface{} { // TODO: It would be nice, if you could select one of the boards in the group from that drop-down rather than just the one you got linked from func TopicCreatePreLoop(args ...interface{}) interface{} { var fid = args[2].(int) - if common.Forums.DirtyGet(fid).ParentType == "guild" { + if c.Forums.DirtyGet(fid).ParentType == "guild" { var strictmode = args[5].(*bool) *strictmode = true } @@ -417,10 +417,10 @@ func TopicCreatePreLoop(args ...interface{}) interface{} { // TODO: Add privacy options // TODO: Add support for multiple boards and add per-board simplified permissions // TODO: Take isJs into account for routes which expect JSON responses -func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { +func ForumCheck(args ...interface{}) (skip bool, rerr c.RouteError) { var r = args[1].(*http.Request) var fid = args[3].(*int) - var forum = common.Forums.DirtyGet(*fid) + var forum = c.Forums.DirtyGet(*fid) if forum.ParentType == "guild" { var err error @@ -429,15 +429,15 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { if !ok { guildItem, err = Gstore.Get(forum.ParentID) if err != nil { - return true, common.InternalError(errors.New("Unable to find the parent group for a forum"), w, r) + return true, c.InternalError(errors.New("Unable to find the parent group for a forum"), w, r) } if !guildItem.Active { - return true, common.NotFound(w, r, nil) // TODO: Can we pull header out of args? + return true, c.NotFound(w, r, nil) // TODO: Can we pull header out of args? } r = r.WithContext(context.WithValue(r.Context(), "guilds_current_group", guildItem)) } - var user = args[2].(*common.User) + var user = args[2].(*c.User) var rank int var posts int var joinedAt string @@ -446,32 +446,32 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { // Clear the default group permissions // TODO: Do this more efficiently, doing it quick and dirty for now to get this out quickly - common.OverrideForumPerms(&user.Perms, false) + c.OverrideForumPerms(&user.Perms, false) user.Perms.ViewTopic = true err = GetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) - if err != nil && err != common.ErrNoRows { - return true, common.InternalError(err, w, r) + if err != nil && err != c.ErrNoRows { + return true, c.InternalError(err, w, r) } else if err != nil { // TODO: Should we let admins / guests into public groups? - return true, common.LocalError("You're not part of this group!", w, r, *user) + return true, c.LocalError("You're not part of this group!", w, r, *user) } // TODO: Implement bans properly by adding the Local Ban API in the next commit // TODO: How does this even work? Refactor it along with the rest of this plugin! if rank < 0 { - return true, common.LocalError("You've been banned from this group!", w, r, *user) + return true, c.LocalError("You've been banned from this group!", w, r, *user) } // Basic permissions for members, more complicated permissions coming in the next commit! if guildItem.Owner == user.ID { - common.OverrideForumPerms(&user.Perms, true) + c.OverrideForumPerms(&user.Perms, true) } else if rank == 0 { user.Perms.LikeItem = true user.Perms.CreateTopic = true user.Perms.CreateReply = true } else { - common.OverrideForumPerms(&user.Perms, true) + c.OverrideForumPerms(&user.Perms, true) } return true, nil } @@ -483,19 +483,19 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) { func Widgets(args ...interface{}) interface{} { var zone = args[0].(string) - var header = args[2].(*common.Header) + var header = args[2].(*c.Header) var request = args[3].(*http.Request) if zone != "view_forum" { return false } - var forum = args[1].(*common.Forum) + var forum = args[1].(*c.Forum) if forum.ParentType == "guild" { // This is why I hate using contexts, all the daisy chains and interface casts x.x guildItem, ok := request.Context().Value("guilds_current_group").(*Guild) if !ok { - common.LogError(errors.New("Unable to find a parent group in the context data")) + c.LogError(errors.New("Unable to find a parent group in the context data")) return false } diff --git a/patcher/main.go b/patcher/main.go index 08ff1279..0f631578 100644 --- a/patcher/main.go +++ b/patcher/main.go @@ -11,7 +11,7 @@ import ( "runtime/debug" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" _ "github.com/go-sql-driver/mysql" ) @@ -38,18 +38,18 @@ func main() { }() log.Print("Loading the configuration data") - err := common.LoadConfig() + err := c.LoadConfig() if err != nil { log.Fatal(err) } log.Print("Processing configuration data") - err = common.ProcessConfig() + err = c.ProcessConfig() if err != nil { log.Fatal(err) } - if common.DbConfig.Adapter != "mysql" && common.DbConfig.Adapter != "" { + if c.DbConfig.Adapter != "mysql" && c.DbConfig.Adapter != "" { log.Fatal("Only MySQL is supported for upgrades right now, please wait for a newer build of the patcher") } @@ -74,11 +74,11 @@ func pressAnyKey(scanner *bufio.Scanner) { func prepMySQL() error { return qgen.Builder.Init("mysql", map[string]string{ - "host": common.DbConfig.Host, - "port": common.DbConfig.Port, - "name": common.DbConfig.Dbname, - "username": common.DbConfig.Username, - "password": common.DbConfig.Password, + "host": c.DbConfig.Host, + "port": c.DbConfig.Port, + "name": c.DbConfig.Dbname, + "username": c.DbConfig.Username, + "password": c.DbConfig.Password, "collation": "utf8mb4_general_ci", }) } diff --git a/routes/account.go b/routes/account.go index c491b566..c34d7ace 100644 --- a/routes/account.go +++ b/routes/account.go @@ -15,7 +15,7 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" ) @@ -23,52 +23,52 @@ import ( // A blank list to fill out that parameter in Page for routes which don't use it var tList []interface{} -func AccountLogin(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountLogin(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { if user.Loggedin { - return common.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") - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} return renderTemplate("login", w, r, header, pi) } // TODO: Log failed attempted logins? // TODO: Lock IPS out if they have too many failed attempts? // TODO: Log unusual countries in comparison to the country a user usually logs in from? Alert the user about this? -func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { if user.Loggedin { - return common.LocalError("You're already logged in.", w, r, user) + return c.LocalError("You're already logged in.", w, r, user) } - username := common.SanitiseSingleLine(r.PostFormValue("username")) - uid, err, requiresExtraAuth := common.Auth.Authenticate(username, r.PostFormValue("password")) + username := c.SanitiseSingleLine(r.PostFormValue("username")) + uid, err, requiresExtraAuth := c.Auth.Authenticate(username, r.PostFormValue("password")) if err != nil { { // TODO: uid is currently set to 0 as authenticate fetches the user by username and password. Get the actual uid, so we can alert the user of attempted logins? What if someone takes advantage of the response times to deduce if an account exists? - logItem := &common.LoginLogItem{UID: uid, Success: false, IPAddress: user.LastIP} + logItem := &c.LoginLogItem{UID: uid, Success: false, IPAddress: user.LastIP} _, err := logItem.Create() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } // TODO: Take 2FA into account - logItem := &common.LoginLogItem{UID: uid, Success: true, IPAddress: user.LastIP} + logItem := &c.LoginLogItem{UID: uid, Success: true, IPAddress: user.LastIP} _, err = logItem.Create() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Do we want to slacken this by only doing it when the IP changes? if requiresExtraAuth { - provSession, signedSession, err := common.Auth.CreateProvisionalSession(uid) + provSession, signedSession, err := c.Auth.CreateProvisionalSession(uid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Use the login log ID in the provisional cookie? - common.Auth.SetProvisionalCookies(w, uid, provSession, signedSession) + c.Auth.SetProvisionalCookies(w, uid, provSession, signedSession) http.Redirect(w, r, "/accounts/mfa_verify/", http.StatusSeeOther) return nil } @@ -76,24 +76,24 @@ func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user common.User return loginSuccess(uid, w, r, &user) } -func loginSuccess(uid int, w http.ResponseWriter, r *http.Request, user *common.User) common.RouteError { - userPtr, err := common.Users.Get(uid) +func loginSuccess(uid int, w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { + userPtr, err := c.Users.Get(uid) if err != nil { - return common.LocalError("Bad account", w, r, *user) + return c.LocalError("Bad account", w, r, *user) } *user = *userPtr var session string if user.Session == "" { - session, err = common.Auth.CreateSession(uid) + session, err = c.Auth.CreateSession(uid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } else { session = user.Session } - common.Auth.SetCookies(w, uid, session) + c.Auth.SetCookies(w, uid, session) if user.IsAdmin { // Is this error check redundant? We already check for the error in PreRoute for the same IP // TODO: Should we be logging this? @@ -131,7 +131,7 @@ func mfaGetCookies(r *http.Request) (uid int, provSession string, signedSession func mfaVerifySession(provSession string, signedSession string, uid int) bool { h := sha256.New() - h.Write([]byte(common.SessionSigningKeyBox.Load().(string))) + h.Write([]byte(c.SessionSigningKeyBox.Load().(string))) h.Write([]byte(provSession)) h.Write([]byte(strconv.Itoa(uid))) expected := hex.EncodeToString(h.Sum(nil)) @@ -140,69 +140,69 @@ func mfaVerifySession(provSession string, signedSession string, uid int) bool { } h = sha256.New() - h.Write([]byte(common.OldSessionSigningKeyBox.Load().(string))) + h.Write([]byte(c.OldSessionSigningKeyBox.Load().(string))) h.Write([]byte(provSession)) h.Write([]byte(strconv.Itoa(uid))) expected = hex.EncodeToString(h.Sum(nil)) return subtle.ConstantTimeCompare([]byte(signedSession), []byte(expected)) == 1 } -func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { if user.Loggedin { - return common.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") uid, provSession, signedSession, err := mfaGetCookies(r) if err != nil { - return common.LocalError("Invalid cookie", w, r, user) + return c.LocalError("Invalid cookie", w, r, user) } if !mfaVerifySession(provSession, signedSession, uid) { - return common.LocalError("Invalid session", w, r, user) + return c.LocalError("Invalid session", w, r, user) } - pi := common.Page{header, tList, nil} - if common.RunPreRenderHook("pre_render_login_mfa_verify", w, r, &user, &pi) { + pi := c.Page{header, tList, nil} + if c.RunPreRenderHook("pre_render_login_mfa_verify", w, r, &user, &pi) { return nil } err = header.Theme.RunTmpl("login_mfa_verify", pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } -func AccountLoginMFAVerifySubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AccountLoginMFAVerifySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { uid, provSession, signedSession, err := mfaGetCookies(r) if err != nil { - return common.LocalError("Invalid cookie", w, r, user) + return c.LocalError("Invalid cookie", w, r, user) } if !mfaVerifySession(provSession, signedSession, uid) { - return common.LocalError("Invalid session", w, r, user) + return c.LocalError("Invalid session", w, r, user) } var token = r.PostFormValue("mfa_token") - err = common.Auth.ValidateMFAToken(token, uid) + err = c.Auth.ValidateMFAToken(token, uid) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } return loginSuccess(uid, w, r, &user) } -func AccountLogout(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - common.Auth.Logout(w, user.ID) +func AccountLogout(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + c.Auth.Logout(w, user.ID) http.Redirect(w, r, "/", http.StatusSeeOther) return nil } -func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountRegister(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { if user.Loggedin { - return common.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") header.LooseCSP = true - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} return renderTemplate("register", w, r, header, pi) } @@ -215,8 +215,8 @@ func isNumeric(data string) (numeric bool) { return true } -func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - headerLite, _ := common.SimpleUserCheck(w, r, &user) +func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + headerLite, _ := c.SimpleUserCheck(w, r, &user) // TODO: Should we push multiple validation errors to the user instead of just one? var regSuccess = true @@ -233,18 +233,18 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U if r.PostFormValue("tos") != "0" { regError(phrases.GetErrorPhrase("register_might_be_machine"), "trap-question") } - if !common.Config.DisableJSAntispam { + if !c.Config.DisableJSAntispam { h := sha256.New() - h.Write([]byte(common.JSTokenBox.Load().(string))) + h.Write([]byte(c.JSTokenBox.Load().(string))) h.Write([]byte(user.LastIP)) if r.PostFormValue("golden-watch") != hex.EncodeToString(h.Sum(nil)) { regError(phrases.GetErrorPhrase("register_might_be_machine"), "js-antispam") } } - username := common.SanitiseSingleLine(r.PostFormValue("username")) + username := c.SanitiseSingleLine(r.PostFormValue("username")) // TODO: Add a dedicated function for validating emails - email := common.SanitiseSingleLine(r.PostFormValue("email")) + email := c.SanitiseSingleLine(r.PostFormValue("email")) if username == "" { regError(phrases.GetErrorPhrase("register_need_username"), "no-username") } @@ -258,14 +258,14 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U regError(phrases.GetErrorPhrase("register_first_word_numeric"), "numeric-name") } - ok := common.HasSuspiciousEmail(email) + ok := c.HasSuspiciousEmail(email) if ok { regError(phrases.GetErrorPhrase("register_suspicious_email"), "suspicious-email") } password := r.PostFormValue("password") // ? Move this into Create()? What if we want to programatically set weak passwords for tests? - err := common.WeakPassword(password, username, email) + err := c.WeakPassword(password, username, email) if err != nil { regError(err.Error(), "weak-password") } else { @@ -276,13 +276,13 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U } } - regLog := common.RegLogItem{Username: username, Email: email, FailureReason: regErrReason, Success: regSuccess, IPAddress: user.LastIP} + regLog := c.RegLogItem{Username: username, Email: email, FailureReason: regErrReason, Success: regSuccess, IPAddress: user.LastIP} _, err = regLog.Create() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if !regSuccess { - return common.LocalError(regErrMsg, w, r, user) + return c.LocalError(regErrMsg, w, r, user) } var active bool @@ -290,60 +290,60 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U switch headerLite.Settings["activation_type"] { case 1: // Activate All active = true - group = common.Config.DefaultGroup + group = c.Config.DefaultGroup default: // Anything else. E.g. Admin Activation or Email Activation. - group = common.Config.ActivationGroup + group = c.Config.ActivationGroup } // TODO: Do the registration attempt logging a little less messily (without having to amend the result after the insert) - uid, err := common.Users.Create(username, password, email, group, active) + uid, err := c.Users.Create(username, password, email, group, active) if err != nil { regLog.Success = false - if err == common.ErrAccountExists { + if err == c.ErrAccountExists { regLog.FailureReason += "username-exists" err = regLog.Commit() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - return common.LocalError(phrases.GetErrorPhrase("register_username_unavailable"), w, r, user) - } else if err == common.ErrLongUsername { + return c.LocalError(phrases.GetErrorPhrase("register_username_unavailable"), w, r, user) + } else if err == c.ErrLongUsername { regLog.FailureReason += "username-too-long" err = regLog.Commit() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - return common.LocalError(phrases.GetErrorPhrase("register_username_too_long_prefix")+strconv.Itoa(common.Config.MaxUsernameLength), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("register_username_too_long_prefix")+strconv.Itoa(c.Config.MaxUsernameLength), w, r, user) } regLog.FailureReason += "internal-error" err2 := regLog.Commit() if err2 != nil { - return common.InternalError(err2, w, r) + return c.InternalError(err2, w, r) } - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - session, err := common.Auth.CreateSession(uid) + session, err := c.Auth.CreateSession(uid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - common.Auth.SetCookies(w, uid, session) + c.Auth.SetCookies(w, uid, session) // Check if this user actually owns this email, if email activation is on, automatically flip their account to active when the email is validated. Validation is also useful for determining whether this user should receive any alerts, etc. via email - if common.Site.EnableEmails { - token, err := common.GenerateSafeString(80) + if c.Site.EnableEmails { + token, err := c.GenerateSafeString(80) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Add an EmailStore and move this there _, err = qgen.NewAcc().Insert("emails").Columns("email, uid, validated, token").Fields("?,?,?,?").Exec(email, uid, 0, token) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - err = common.SendValidationEmail(username, email, token) + err = c.SendValidationEmail(username, email, token) if err != nil { - return common.LocalError(phrases.GetErrorPhrase("register_email_fail"), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("register_email_fail"), w, r, user) } } @@ -352,14 +352,14 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user common.U } // TODO: Figure a way of making this into middleware? -func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, user *common.User, header *common.Header) { +func accountEditHead(titlePhrase string, w http.ResponseWriter, r *http.Request, user *c.User, header *c.Header) { header.Title = phrases.GetTitlePhrase(titlePhrase) header.Path = "/user/edit/" header.AddSheet(header.Theme.Name + "/account.css") header.AddScriptAsync("account.js") } -func AccountEdit(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountEdit(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account", w, r, &user, header) if r.FormValue("avatar_updated") == "1" { @@ -372,33 +372,33 @@ func AccountEdit(w http.ResponseWriter, r *http.Request, user common.User, heade // TODO: Find a more efficient way of doing this var mfaSetup = false - _, err := common.MFAstore.Get(user.ID) + _, err := c.MFAstore.Get(user.ID) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else if err != sql.ErrNoRows { mfaSetup = true } // Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score - prevScore := common.GetLevelScore(user.Level) + prevScore := c.GetLevelScore(user.Level) currentScore := user.Score - prevScore - nextScore := common.GetLevelScore(user.Level+1) - prevScore + nextScore := c.GetLevelScore(user.Level+1) - prevScore perc := int(math.Ceil((float64(nextScore) / float64(currentScore)) * 100)) - pi := common.Account{header, "dashboard", "account_own_edit", common.AccountDashPage{header, mfaSetup, currentScore, nextScore, user.Level + 1, perc * 2}} + pi := c.Account{header, "dashboard", "account_own_edit", c.AccountDashPage{header, mfaSetup, currentScore, nextScore, user.Level + 1, perc * 2}} return renderTemplate("account", w, r, header, pi) } //edit_password -func AccountEditPassword(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountEditPassword(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account_password", w, r, &user, header) - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} return renderTemplate("account_own_edit_password", w, r, header, pi) } // TODO: Require re-authentication if the user hasn't logged in in a while -func AccountEditPasswordSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) +func AccountEditPasswordSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } @@ -411,30 +411,30 @@ func AccountEditPasswordSubmit(w http.ResponseWriter, r *http.Request, user comm // TODO: Use a reusable statement err := qgen.NewAcc().Select("users").Columns("password, salt").Where("uid = ?").QueryRow(user.ID).Scan(&realPassword, &salt) if err == sql.ErrNoRows { - return common.LocalError("Your account no longer exists.", w, r, user) + return c.LocalError("Your account no longer exists.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - err = common.CheckPassword(realPassword, currentPassword, salt) - if err == common.ErrMismatchedHashAndPassword { - return common.LocalError("That's not the correct password.", w, r, user) + err = c.CheckPassword(realPassword, currentPassword, salt) + if err == c.ErrMismatchedHashAndPassword { + return c.LocalError("That's not the correct password.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if newPassword != confirmPassword { - return common.LocalError("The two passwords don't match.", w, r, user) + return c.LocalError("The two passwords don't match.", w, r, user) } - common.SetPassword(user.ID, newPassword) // TODO: Limited version of WeakPassword() + c.SetPassword(user.ID, newPassword) // TODO: Limited version of WeakPassword() // Log the user out as a safety precaution - common.Auth.ForceLogout(user.ID) + c.Auth.ForceLogout(user.ID) http.Redirect(w, r, "/", http.StatusSeeOther) return nil } -func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) +func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } @@ -451,7 +451,7 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common } } if len(filenameMap) > 1 { - return common.LocalError("You may only upload one avatar", w, r, user) + return c.LocalError("You may only upload one avatar", w, r, user) } var ext string @@ -462,50 +462,50 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common } infile, err := hdr.Open() if err != nil { - return common.LocalError("Upload failed", w, r, user) + return c.LocalError("Upload failed", w, r, user) } defer infile.Close() if ext == "" { extarr := strings.Split(hdr.Filename, ".") if len(extarr) < 2 { - return common.LocalError("Bad file", w, r, user) + return c.LocalError("Bad file", w, r, user) } ext = extarr[len(extarr)-1] // TODO: Can we do this without a regex? reg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { - return common.LocalError("Bad file extension", w, r, user) + return c.LocalError("Bad file extension", w, r, user) } ext = reg.ReplaceAllString(ext, "") ext = strings.ToLower(ext) - if !common.ImageFileExts.Contains(ext) { - return common.LocalError("You can only use an image for your avatar", w, r, user) + if !c.ImageFileExts.Contains(ext) { + return c.LocalError("You can only use an image for your avatar", w, r, user) } } // TODO: Centralise this string, so we don't have to change it in two different places when it changes outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext) if err != nil { - return common.LocalError("Upload failed [File Creation Failed]", w, r, user) + return c.LocalError("Upload failed [File Creation Failed]", w, r, user) } defer outfile.Close() _, err = io.Copy(outfile, infile) if err != nil { - return common.LocalError("Upload failed [Copy Failed]", w, r, user) + return c.LocalError("Upload failed [Copy Failed]", w, r, user) } } } if ext == "" { - return common.LocalError("No file", w, r, user) + return c.LocalError("No file", w, r, user) } err := user.ChangeAvatar("." + ext) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Clean up the old avatar data, so we don't end up with too many dead files in /uploads/ @@ -513,13 +513,13 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common if user.RawAvatar[0] == '.' && user.RawAvatar[1] == '.' { err := os.Remove("./uploads/avatar_" + strconv.Itoa(user.ID) + "_tmp" + user.RawAvatar[1:]) if err != nil && !os.IsNotExist(err) { - common.LogWarning(err) - return common.LocalError("Something went wrong", w, r, user) + c.LogWarning(err) + return c.LocalError("Something went wrong", w, r, user) } err = os.Remove("./uploads/avatar_" + strconv.Itoa(user.ID) + "_w48" + user.RawAvatar[1:]) if err != nil && !os.IsNotExist(err) { - common.LogWarning(err) - return common.LocalError("Something went wrong", w, r, user) + c.LogWarning(err) + return c.LocalError("Something went wrong", w, r, user) } } } @@ -527,98 +527,98 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common // TODO: Only schedule a resize if the avatar isn't tiny err = user.ScheduleAvatarResize() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } http.Redirect(w, r, "/user/edit/?avatar_updated=1", http.StatusSeeOther) return nil } -func AccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) +func AccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } - newUsername := common.SanitiseSingleLine(r.PostFormValue("account-new-username")) + newUsername := c.SanitiseSingleLine(r.PostFormValue("account-new-username")) if newUsername == "" { - return common.LocalError("You can't leave your username blank", w, r, user) + return c.LocalError("You can't leave your username blank", w, r, user) } err := user.ChangeName(newUsername) if err != nil { - return common.LocalError("Unable to change the username. Does someone else already have this name?", w, r, user) + return c.LocalError("Unable to change the username. Does someone else already have this name?", w, r, user) } http.Redirect(w, r, "/user/edit/?username_updated=1", http.StatusSeeOther) return nil } -func AccountEditMFA(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountEditMFA(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account_mfa", w, r, &user, header) - mfaItem, err := common.MFAstore.Get(user.ID) + mfaItem, err := c.MFAstore.Get(user.ID) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else if err == sql.ErrNoRows { - return common.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 := common.Page{header, tList, mfaItem.Scratch} + pi := c.Page{header, tList, mfaItem.Scratch} return renderTemplate("account_own_edit_mfa", w, r, header, pi) } // 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 common.User, header *common.Header) common.RouteError { +func AccountEditMFASetup(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account_mfa_setup", w, r, &user, header) // Flash an error if mfa is already setup - _, err := common.MFAstore.Get(user.ID) + _, err := c.MFAstore.Get(user.ID) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else if err != sql.ErrNoRows { - return common.LocalError("You have already setup two-factor authentication", w, r, user) + return c.LocalError("You have already setup two-factor authentication", w, r, user) } // TODO: Entitise this? - code, err := common.GenerateGAuthSecret() + code, err := c.GenerateGAuthSecret() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - pi := common.Page{header, tList, common.FriendlyGAuthSecret(code)} + pi := c.Page{header, tList, c.FriendlyGAuthSecret(code)} return renderTemplate("account_own_edit_mfa_setup", w, r, header, 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 -func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) +func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } // Flash an error if mfa is already setup - _, err := common.MFAstore.Get(user.ID) + _, err := c.MFAstore.Get(user.ID) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else if err != sql.ErrNoRows { - return common.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") var otp = r.PostFormValue("otp") - ok, err := common.VerifyGAuthToken(code, otp) + ok, err := c.VerifyGAuthToken(code, otp) if err != nil { //fmt.Println("err: ", err) - return common.LocalError("Something weird happened", w, r, user) // TODO: Log this error? + return c.LocalError("Something weird happened", w, r, user) // TODO: Log this error? } // TODO: Use AJAX for this if !ok { - return common.LocalError("The token isn't right", w, r, user) + return c.LocalError("The token isn't right", w, r, user) } // TODO: How should we handle races where a mfa key is already setup? Right now, it's a fairly generic error, maybe try parsing the error message? - err = common.MFAstore.Create(code, user.ID) + err = c.MFAstore.Create(code, user.ID) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } http.Redirect(w, r, "/user/edit/?mfa_setup_success=1", http.StatusSeeOther) @@ -626,72 +626,72 @@ func AccountEditMFASetupSubmit(w http.ResponseWriter, r *http.Request, user comm } // TODO: Implement this -func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) +func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } // Flash an error if mfa is already setup - mfaItem, err := common.MFAstore.Get(user.ID) + mfaItem, err := c.MFAstore.Get(user.ID) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else if err == sql.ErrNoRows { - return common.LocalError("You don't have two-factor enabled on your account", w, r, user) + return c.LocalError("You don't have two-factor enabled on your account", w, r, user) } err = mfaItem.Delete() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } http.Redirect(w, r, "/user/edit/?mfa_disabled=1", http.StatusSeeOther) return nil } -func AccountEditEmail(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account_email", w, r, &user, header) - emails, err := common.Emails.GetEmailsByUser(&user) + emails, err := c.Emails.GetEmailsByUser(&user) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Was this site migrated from another forum software? Most of them don't have multiple emails for a single user. // This also applies when the admin switches site.EnableEmails on after having it off for a while. if len(emails) == 0 { - email := common.Email{UserID: user.ID} + email := c.Email{UserID: user.ID} email.Email = user.Email email.Validated = false email.Primary = true emails = append(emails, email) } - if !common.Site.EnableEmails { + if !c.Site.EnableEmails { header.AddNotice("account_mail_disabled") } if r.FormValue("verified") == "1" { header.AddNotice("account_mail_verify_success") } - pi := common.Account{header, "edit_emails", "account_own_edit_email", common.EmailListPage{header, emails}} + pi := c.Account{header, "edit_emails", "account_own_edit_email", c.EmailListPage{header, emails}} return renderTemplate("account", w, r, header, pi) } // TODO: Should we make this an AnonAction so someone can do this without being logged in? -func AccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user common.User, token string) common.RouteError { - header, ferr := common.UserCheck(w, r, &user) +func AccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user c.User, token string) c.RouteError { + header, ferr := c.UserCheck(w, r, &user) if ferr != nil { return ferr } - if !common.Site.EnableEmails { + if !c.Site.EnableEmails { http.Redirect(w, r, "/user/edit/email/", http.StatusSeeOther) return nil } - targetEmail := common.Email{UserID: user.ID} - emails, err := common.Emails.GetEmailsByUser(&user) + targetEmail := c.Email{UserID: user.ID} + emails, err := c.Emails.GetEmailsByUser(&user) if err != nil { - return common.LocalError("You are not logged in", w, r, user) + return c.LocalError("You are not logged in", w, r, user) } for _, email := range emails { if subtle.ConstantTimeCompare([]byte(email.Token), []byte(token)) == 1 { @@ -700,51 +700,51 @@ func AccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, user co } if len(emails) == 0 { - return common.LocalError("A verification email was never sent for you!", w, r, user) + return c.LocalError("A verification email was never sent for you!", w, r, user) } if targetEmail.Token == "" { - return common.LocalError("That's not a valid token!", w, r, user) + return c.LocalError("That's not a valid token!", w, r, user) } - err = common.Emails.VerifyEmail(user.Email) + err = c.Emails.VerifyEmail(user.Email) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // If Email Activation is on, then activate the account while we're here if header.Settings["activation_type"] == 2 { err = user.Activate() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } http.Redirect(w, r, "/user/edit/email/?verified=1", http.StatusSeeOther) return nil } -func AccountLogins(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountLogins(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("account_logins", w, r, &user, header) - logCount := common.LoginLogs.Count(user.ID) + logCount := c.LoginLogs.Count(user.ID) page, _ := strconv.Atoi(r.FormValue("page")) perPage := 12 - offset, page, lastPage := common.PageOffset(logCount, page, perPage) + offset, page, lastPage := c.PageOffset(logCount, page, perPage) - logs, err := common.LoginLogs.GetOffset(user.ID, offset, perPage) + logs, err := c.LoginLogs.GetOffset(user.ID, offset, perPage) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - pageList := common.Paginate(logCount, perPage, 5) - pi := common.Account{header, "logins", "account_logins", common.AccountLoginsPage{header, logs, common.Paginator{pageList, page, lastPage}}} + pageList := c.Paginate(logCount, perPage, 5) + pi := c.Account{header, "logins", "account_logins", c.AccountLoginsPage{header, logs, c.Paginator{pageList, page, lastPage}}} return renderTemplate("account", w, r, header, pi) } -func LevelList(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func LevelList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { header.Title = phrases.GetTitlePhrase("account_level_list") - var fScores = common.GetLevels(20) - var levels = make([]common.LevelListItem, len(fScores)) + var fScores = c.GetLevels(20) + var levels = make([]c.LevelListItem, len(fScores)) for i, fScore := range fScores { var status string if user.Level > i { @@ -756,103 +756,103 @@ func LevelList(w http.ResponseWriter, r *http.Request, user common.User, header } iScore := int(math.Ceil(fScore)) perc := int(math.Ceil((fScore / float64(user.Score)) * 100)) - levels[i] = common.LevelListItem{i, iScore, status, perc * 2} + levels[i] = c.LevelListItem{i, iScore, status, perc * 2} } - pi := common.LevelListPage{header, levels[1:]} + pi := c.LevelListPage{header, levels[1:]} return renderTemplate("level_list", w, r, header, pi) } -func Alerts(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func Alerts(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { return nil } -func AccountPasswordReset(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountPasswordReset(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { if user.Loggedin { - return common.LocalError("You're already logged in.", w, r, user) + return c.LocalError("You're already logged in.", w, r, user) } - if !common.Site.EnableEmails { - return common.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) + if !c.Site.EnableEmails { + return c.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) } if r.FormValue("email_sent") == "1" { header.AddNotice("password_reset_email_sent") } header.Title = phrases.GetTitlePhrase("password_reset") - return renderTemplate("password_reset", w, r, header, common.Page{header, tList, nil}) + return renderTemplate("password_reset", w, r, header, c.Page{header, tList, nil}) } // TODO: Ratelimit this -func AccountPasswordResetSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AccountPasswordResetSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { if user.Loggedin { - return common.LocalError("You're already logged in.", w, r, user) + return c.LocalError("You're already logged in.", w, r, user) } - if !common.Site.EnableEmails { - return common.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) + if !c.Site.EnableEmails { + return c.LocalError(phrases.GetNoticePhrase("account_mail_disabled"), w, r, user) } username := r.PostFormValue("username") - tuser, err := common.Users.GetByName(username) + tuser, err := c.Users.GetByName(username) if err == sql.ErrNoRows { // Someone trying to stir up trouble? http.Redirect(w, r, "/accounts/password-reset/?email_sent=1", http.StatusSeeOther) return nil } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - token, err := common.GenerateSafeString(80) + token, err := c.GenerateSafeString(80) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Move these queries somewhere else var disc string err = qgen.NewAcc().Select("password_resets").Columns("createdAt").DateCutoff("createdAt", 1, "hour").QueryRow().Scan(&disc) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if err == nil { - return common.LocalError("You can only send a password reset email for a user once an hour", w, r, user) + return c.LocalError("You can only send a password reset email for a user once an hour", w, r, user) } count, err := qgen.NewAcc().Count("password_resets").DateCutoff("createdAt", 6, "hour").Total() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if count >= 3 { - return common.LocalError("You can only send a password reset email for a user three times every six hours", w, r, user) + return c.LocalError("You can only send a password reset email for a user three times every six hours", w, r, user) } count, err = qgen.NewAcc().Count("password_resets").DateCutoff("createdAt", 12, "hour").Total() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if count >= 4 { - return common.LocalError("You can only send a password reset email for a user four times every twelve hours", w, r, user) + return c.LocalError("You can only send a password reset email for a user four times every twelve hours", w, r, user) } - err = common.PasswordResetter.Create(tuser.Email, tuser.ID, token) + err = c.PasswordResetter.Create(tuser.Email, tuser.ID, token) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var schema string - if common.Site.EnableSsl { + if c.Site.EnableSsl { schema = "s" } - err = common.SendEmail(tuser.Email, phrases.GetTmplPhrase("password_reset_subject"), phrases.GetTmplPhrasef("password_reset_body", tuser.Name, "http"+schema+"://"+common.Site.URL+"/accounts/password-reset/token/?uid="+strconv.Itoa(tuser.ID)+"&token="+token)) + 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)) if err != nil { - return common.LocalError(phrases.GetErrorPhrase("password_reset_email_fail"), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("password_reset_email_fail"), w, r, user) } http.Redirect(w, r, "/accounts/password-reset/?email_sent=1", http.StatusSeeOther) return nil } -func AccountPasswordResetToken(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func AccountPasswordResetToken(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { if user.Loggedin { - return common.LocalError("You're already logged in.", w, r, user) + return c.LocalError("You're already logged in.", w, r, user) } // TODO: Find a way to flash this notice /*if r.FormValue("token_verified") == "1" { @@ -862,67 +862,67 @@ func AccountPasswordResetToken(w http.ResponseWriter, r *http.Request, user comm token := r.FormValue("token") uid, err := strconv.Atoi(r.FormValue("uid")) if err != nil { - return common.LocalError("Invalid uid", w, r, user) + return c.LocalError("Invalid uid", w, r, user) } - err = common.PasswordResetter.ValidateToken(uid, token) - if err == sql.ErrNoRows || err == common.ErrBadResetToken { - return common.LocalError("This reset token has expired.", w, r, user) + err = c.PasswordResetter.ValidateToken(uid, token) + if err == sql.ErrNoRows || err == c.ErrBadResetToken { + return c.LocalError("This reset token has expired.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - _, err = common.MFAstore.Get(uid) + _, err = c.MFAstore.Get(uid) if err != sql.ErrNoRows && err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } mfa := err != sql.ErrNoRows header.Title = phrases.GetTitlePhrase("password_reset_token") - return renderTemplate("password_reset_token", w, r, header, common.ResetPage{header, uid, html.EscapeString(token), mfa}) + return renderTemplate("password_reset_token", w, r, header, c.ResetPage{header, uid, html.EscapeString(token), mfa}) } -func AccountPasswordResetTokenSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AccountPasswordResetTokenSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { if user.Loggedin { - return common.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")) if err != nil { - return common.LocalError("Invalid uid", w, r, user) + return c.LocalError("Invalid uid", w, r, user) } - if !common.Users.Exists(uid) { - return common.LocalError("This reset token has expired.", w, r, user) + if !c.Users.Exists(uid) { + return c.LocalError("This reset token has expired.", w, r, user) } - err = common.PasswordResetter.ValidateToken(uid, token) - if err == sql.ErrNoRows || err == common.ErrBadResetToken { - return common.LocalError("This reset token has expired.", w, r, user) + err = c.PasswordResetter.ValidateToken(uid, token) + if err == sql.ErrNoRows || err == c.ErrBadResetToken { + return c.LocalError("This reset token has expired.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } mfaToken := r.PostFormValue("mfa_token") - err = common.Auth.ValidateMFAToken(mfaToken, uid) - if err != nil && err != common.ErrNoMFAToken { - return common.LocalError(err.Error(), w, r, user) + err = c.Auth.ValidateMFAToken(mfaToken, uid) + if err != nil && err != c.ErrNoMFAToken { + return c.LocalError(err.Error(), w, r, user) } newPassword := r.PostFormValue("password") confirmPassword := r.PostFormValue("confirm_password") if newPassword != confirmPassword { - return common.LocalError("The two passwords don't match.", w, r, user) + return c.LocalError("The two passwords don't match.", w, r, user) } - common.SetPassword(uid, newPassword) // TODO: Limited version of WeakPassword() + c.SetPassword(uid, newPassword) // TODO: Limited version of WeakPassword() - err = common.PasswordResetter.FlushTokens(uid) + err = c.PasswordResetter.FlushTokens(uid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Log the user out as a safety precaution - common.Auth.ForceLogout(uid) + c.Auth.ForceLogout(uid) //http.Redirect(w, r, "/accounts/password-reset/token/?token_verified=1", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther) diff --git a/routes/api.go b/routes/api.go index 3ac88fb7..7b0d9e93 100644 --- a/routes/api.go +++ b/routes/api.go @@ -7,12 +7,12 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) // TODO: Make this a static file somehow? Is it possible for us to put this file somewhere else? // TODO: Add an API so that plugins can register disallowed areas. E.g. /guilds/join for plugin_guilds -func RobotsTxt(w http.ResponseWriter, r *http.Request) common.RouteError { +func RobotsTxt(w http.ResponseWriter, r *http.Request) c.RouteError { // TODO: Do we have to put * or something at the end of the paths? _, _ = w.Write([]byte(`User-agent: * Disallow: /panel/* @@ -32,14 +32,14 @@ func writeXMLHeader(w http.ResponseWriter, r *http.Request) { } // TODO: Keep track of when a sitemap was last modifed and add a lastmod element for it -func SitemapXml(w http.ResponseWriter, r *http.Request) common.RouteError { +func SitemapXml(w http.ResponseWriter, r *http.Request) c.RouteError { var sslBit string - if common.Site.EnableSsl { + if c.Site.EnableSsl { sslBit = "s" } var sitemapItem = func(path string) { w.Write([]byte(` - http` + sslBit + `://` + common.Site.URL + "/" + path + ` + http` + sslBit + `://` + c.Site.URL + "/" + path + ` `)) } @@ -55,13 +55,13 @@ func SitemapXml(w http.ResponseWriter, r *http.Request) common.RouteError { type FuzzyRoute struct { Path string - Handle func(http.ResponseWriter, *http.Request, int) common.RouteError + Handle func(http.ResponseWriter, *http.Request, int) c.RouteError } // TODO: Add a sitemap API and clean things up // TODO: ^-- Make sure that the API is concurrent // TODO: Add a social group sitemap -var sitemapRoutes = map[string]func(http.ResponseWriter, *http.Request) common.RouteError{ +var sitemapRoutes = map[string]func(http.ResponseWriter, *http.Request) c.RouteError{ "forums.xml": SitemapForums, "topics.xml": SitemapTopics, } @@ -71,7 +71,7 @@ var fuzzySitemapRoutes = map[string]FuzzyRoute{ "topics_page_": FuzzyRoute{"topics_page_(%d).xml", SitemapTopic}, } -func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError { +func sitemapSwitch(w http.ResponseWriter, r *http.Request) c.RouteError { var path = r.URL.Path[len("/sitemaps/"):] for name, fuzzy := range fuzzySitemapRoutes { if strings.HasPrefix(path, name) && strings.HasSuffix(path, ".xml") { @@ -80,8 +80,8 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError { page, err := strconv.Atoi(spath) if err != nil { // ? What's this? Do we need it? Was it just a quick trace? - common.DebugLogf("Unable to convert string '%s' to integer in fuzzy route", spath) - return common.NotFound(w, r, nil) + c.DebugLogf("Unable to convert string '%s' to integer in fuzzy route", spath) + return c.NotFound(w, r, nil) } return fuzzy.Handle(w, r, page) } @@ -89,26 +89,26 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError { route, ok := sitemapRoutes[path] if !ok { - return common.NotFound(w, r, nil) + return c.NotFound(w, r, nil) } return route(w, r) } -func SitemapForums(w http.ResponseWriter, r *http.Request) common.RouteError { +func SitemapForums(w http.ResponseWriter, r *http.Request) c.RouteError { var sslBit string - if common.Site.EnableSsl { + if c.Site.EnableSsl { sslBit = "s" } var sitemapItem = func(path string) { w.Write([]byte(` - http` + sslBit + `://` + common.Site.URL + path + ` + http` + sslBit + `://` + c.Site.URL + path + ` `)) } - group, err := common.Groups.Get(common.GuestUser.Group) + group, err := c.Groups.Get(c.GuestUser.Group) if err != nil { - return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) + return c.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } writeXMLHeader(w, r) @@ -116,9 +116,9 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) common.RouteError { for _, fid := range group.CanSee { // Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else - var forum = common.Forums.DirtyGet(fid).Copy() + var forum = c.Forums.DirtyGet(fid).Copy() if forum.ParentID == 0 && forum.Name != "" && forum.Active { - sitemapItem(common.BuildForumURL(common.NameToSlug(forum.Name), forum.ID)) + sitemapItem(c.BuildForumURL(c.NameToSlug(forum.Name), forum.ID)) } } @@ -128,34 +128,34 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) common.RouteError { // TODO: Add a global ratelimit. 10 50MB files (smaller if compressed better) per minute? // ? We might have problems with banned users, if they have fewer ViewTopic permissions than guests as they'll be able to see this list. Then again, a banned user could just logout to see it -func SitemapTopics(w http.ResponseWriter, r *http.Request) common.RouteError { +func SitemapTopics(w http.ResponseWriter, r *http.Request) c.RouteError { var sslBit string - if common.Site.EnableSsl { + if c.Site.EnableSsl { sslBit = "s" } var sitemapItem = func(path string) { w.Write([]byte(` - http` + sslBit + `://` + common.Site.URL + "/" + path + ` + http` + sslBit + `://` + c.Site.URL + "/" + path + ` `)) } - group, err := common.Groups.Get(common.GuestUser.Group) + group, err := c.Groups.Get(c.GuestUser.Group) if err != nil { - return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) + return c.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } - var visibleForums []common.Forum + var visibleForums []c.Forum for _, fid := range group.CanSee { - forum := common.Forums.DirtyGet(fid) + forum := c.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active { visibleForums = append(visibleForums, forum.Copy()) } } - topicCount, err := common.TopicCountInForums(visibleForums) + topicCount, err := c.TopicCountInForums(visibleForums) if err != nil { - return common.InternalErrorXML(err, w, r) + return c.InternalErrorXML(err, w, r) } var pageCount = topicCount / sitemapPageCap @@ -170,35 +170,35 @@ func SitemapTopics(w http.ResponseWriter, r *http.Request) common.RouteError { return nil } -func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) common.RouteError { +func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) c.RouteError { /*var sslBit string - if common.Site.EnableSsl { + if c.Site.EnableSsl { sslBit = "s" } var sitemapItem = func(path string) { w.Write([]byte(` - http` + sslBit + `://` + common.Site.URL + "/" + path + ` + http` + sslBit + `://` + c.Site.URL + "/" + path + ` `)) }*/ - group, err := common.Groups.Get(common.GuestUser.Group) + group, err := c.Groups.Get(c.GuestUser.Group) if err != nil { - return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) + return c.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } - var visibleForums []common.Forum + var visibleForums []c.Forum for _, fid := range group.CanSee { - forum := common.Forums.DirtyGet(fid) + forum := c.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active { visibleForums = append(visibleForums, forum.Copy()) } } - argList, qlist := common.ForumListToArgQ(visibleForums) - topicCount, err := common.ArgQToTopicCount(argList, qlist) + argList, qlist := c.ForumListToArgQ(visibleForums) + topicCount, err := c.ArgQToTopicCount(argList, qlist) if err != nil { - return common.InternalErrorXML(err, w, r) + return c.InternalErrorXML(err, w, r) } var pageCount = topicCount / sitemapPageCap @@ -216,18 +216,18 @@ func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) common.Route return nil } -func SitemapUsers(w http.ResponseWriter, r *http.Request) common.RouteError { +func SitemapUsers(w http.ResponseWriter, r *http.Request) c.RouteError { writeXMLHeader(w, r) w.Write([]byte("\n")) return nil } type JsonMe struct { - User *common.MeUser + User *c.MeUser Site MeSite } -// We don't want to expose too much information about the site, so we'll make this a small subset of common.site +// We don't want to expose too much information about the site, so we'll make this a small subset of c.site type MeSite struct { MaxRequestSize int } @@ -235,18 +235,18 @@ type MeSite struct { // APIMe returns information about the current logged-in user // TODO: Find some way to stop intermediaries from doing compression to avoid the BREACH attack // TODO: Decouple site settings into a different API? I'd like to avoid having too many requests, if possible, maybe we can use a different name for this? -func APIMe(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func APIMe(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { // TODO: Don't make this too JSON dependent so that we can swap in newer more efficient formats w.Header().Set("Content-Type", "application/json") // We don't want an intermediary accidentally caching this // TODO: Use this header anywhere with a user check? w.Header().Set("Cache-Control", "private") - me := JsonMe{(&user).Me(), MeSite{common.Site.MaxRequestSize}} + me := JsonMe{(&user).Me(), MeSite{c.Site.MaxRequestSize}} jsonBytes, err := json.Marshal(me) if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } w.Write(jsonBytes) diff --git a/routes/attachments.go b/routes/attachments.go index 1a583834..e9fdb983 100644 --- a/routes/attachments.go +++ b/routes/attachments.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) @@ -20,7 +20,7 @@ var attachmentStmts AttachmentStmts // TODO: Abstract this with an attachment store func init() { - common.DbInits.Add(func(acc *qgen.Accumulator) error { + c.DbInits.Add(func(acc *qgen.Accumulator) error { attachmentStmts = AttachmentStmts{ get: acc.Select("attachments").Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path").Where("path = ? AND sectionID = ? AND sectionTable = ?").Prepare(), } @@ -28,16 +28,16 @@ func init() { }) } -func ShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, filename string) common.RouteError { - filename = common.Stripslashes(filename) +func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filename string) c.RouteError { + filename = c.Stripslashes(filename) var ext = filepath.Ext("./attachs/" + filename) - if !common.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { - return common.LocalError("Bad extension", w, r, user) + if !c.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { + return c.LocalError("Bad extension", w, r, user) } sectionID, err := strconv.Atoi(r.FormValue("sectionID")) if err != nil { - return common.LocalError("The sectionID is not an integer", w, r, user) + return c.LocalError("The sectionID is not an integer", w, r, user) } var sectionTable = r.FormValue("sectionType") @@ -45,37 +45,37 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, fi var originID, uploadedBy int err = attachmentStmts.get.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename) if err == sql.ErrNoRows { - return common.NotFound(w, r, nil) + return c.NotFound(w, r, nil) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if sectionTable == "forums" { - _, ferr := common.SimpleForumUserCheck(w, r, &user, sectionID) + _, ferr := c.SimpleForumUserCheck(w, r, &user, sectionID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } } else { - return common.LocalError("Unknown section", w, r, user) + return c.LocalError("Unknown section", w, r, user) } if originTable != "topics" && originTable != "replies" { - return common.LocalError("Unknown origin", w, r, user) + return c.LocalError("Unknown origin", w, r, user) } if !user.Loggedin { - w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(common.Year))) + w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year))) } else { - guest := common.GuestUser - _, ferr := common.SimpleForumUserCheck(w, r, &guest, sectionID) + guest := c.GuestUser + _, ferr := c.SimpleForumUserCheck(w, r, &guest, sectionID) if ferr != nil { return ferr } if guest.Perms.ViewTopic { - w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(common.Year))) + w.Header().Set("Cache-Control", "max-age="+strconv.Itoa(int(c.Year))) } else { w.Header().Set("Cache-Control", "private") } @@ -87,27 +87,27 @@ func ShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, fi } // TODO: Add a table for the files and lock the file row when performing tasks related to the file -func deleteAttachment(w http.ResponseWriter, r *http.Request, user common.User, aid int, js bool) common.RouteError { - attach, err := common.Attachments.Get(aid) +func deleteAttachment(w http.ResponseWriter, r *http.Request, user c.User, aid int, js bool) c.RouteError { + attach, err := c.Attachments.Get(aid) if err == sql.ErrNoRows { - return common.NotFoundJSQ(w, r, nil, js) + return c.NotFoundJSQ(w, r, nil, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - err = common.Attachments.Delete(aid) + err = c.Attachments.Delete(aid) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - count := common.Attachments.CountInPath(attach.Path) + count := c.Attachments.CountInPath(attach.Path) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } if count == 0 { err := os.Remove("./attachs/" + attach.Path) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } } @@ -117,7 +117,7 @@ func deleteAttachment(w http.ResponseWriter, r *http.Request, user common.User, // TODO: Stop duplicating this code // TODO: Use a transaction here // TODO: Move this function to neutral ground -func uploadAttachment(w http.ResponseWriter, r *http.Request, user common.User, sid int, sectionTable string, oid int, originTable string, extra string) (pathMap map[string]string, rerr common.RouteError) { +func uploadAttachment(w http.ResponseWriter, r *http.Request, user c.User, sid int, sectionTable string, oid int, originTable string, extra string) (pathMap map[string]string, rerr c.RouteError) { pathMap = make(map[string]string) files, rerr := uploadFilesWithHash(w, r, user, "./attachs/") if rerr != nil { @@ -125,9 +125,9 @@ func uploadAttachment(w http.ResponseWriter, r *http.Request, user common.User, } for _, filename := range files { - aid, err := common.Attachments.Add(sid, sectionTable, oid, originTable, user.ID, filename, extra) + aid, err := c.Attachments.Add(sid, sectionTable, oid, originTable, user.ID, filename, extra) if err != nil { - return nil, common.InternalError(err, w, r) + return nil, c.InternalError(err, w, r) } _, ok := pathMap[filename] @@ -139,18 +139,18 @@ func uploadAttachment(w http.ResponseWriter, r *http.Request, user common.User, switch originTable { case "topics": - _, err = topicStmts.updateAttachs.Exec(common.Attachments.CountIn(originTable, oid), oid) + _, err = topicStmts.updateAttachs.Exec(c.Attachments.CountIn(originTable, oid), oid) if err != nil { - return nil, common.InternalError(err, w, r) + return nil, c.InternalError(err, w, r) } - err = common.Topics.Reload(oid) + err = c.Topics.Reload(oid) if err != nil { - return nil, common.InternalError(err, w, r) + return nil, c.InternalError(err, w, r) } case "replies": - _, err = replyStmts.updateAttachs.Exec(common.Attachments.CountIn(originTable, oid), oid) + _, err = replyStmts.updateAttachs.Exec(c.Attachments.CountIn(originTable, oid), oid) if err != nil { - return nil, common.InternalError(err, w, r) + return nil, c.InternalError(err, w, r) } } } diff --git a/routes/common.go b/routes/common.go index e9812729..02206004 100644 --- a/routes/common.go +++ b/routes/common.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) var successJSONBytes = []byte(`{"success":"1"}`) @@ -21,9 +21,9 @@ func ParseSEOURL(urlBit string) (slug string, id int, err error) { return halves[0], tid, err } -func doPush(w http.ResponseWriter, header *common.Header) { +func doPush(w http.ResponseWriter, header *c.Header) { //fmt.Println("in doPush") - if common.Config.EnableCDNPush { + if c.Config.EnableCDNPush { // TODO: Faster string building... var sbuf string var push = func(in []string) { @@ -46,9 +46,9 @@ func doPush(w http.ResponseWriter, header *common.Header) { sbuf = sbuf[:len(sbuf)-1] w.Header().Set("Link", sbuf) } - } else if !common.Config.DisableServerPush { + } else if !c.Config.DisableServerPush { //fmt.Println("push enabled") - gzw, ok := w.(common.GzipResponseWriter) + gzw, ok := w.(c.GzipResponseWriter) if ok { w = gzw.ResponseWriter } @@ -75,7 +75,7 @@ func doPush(w http.ResponseWriter, header *common.Header) { } } -func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *common.Header, pi interface{}) common.RouteError { +func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError { if header.CurrentUser.Loggedin { header.MetaDesc = "" header.OGDesc = "" @@ -83,7 +83,7 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea header.OGDesc = header.MetaDesc } // TODO: Expand this to non-HTTPS requests too - if !header.LooseCSP && common.Site.EnableSsl { + if !header.LooseCSP && c.Site.EnableSsl { w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests") } header.AddScript("global.js") @@ -98,12 +98,12 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea if header.CurrentUser.IsAdmin { header.Elapsed1 = time.Since(header.StartedAt).String() } - if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &header.CurrentUser, pi) { + if c.RunPreRenderHook("pre_render_"+tmplName, w, r, &header.CurrentUser, pi) { return nil } err := header.Theme.RunTmpl(tmplName, pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } diff --git a/routes/forum.go b/routes/forum.go index 52b1ef1e..162b4749 100644 --- a/routes/forum.go +++ b/routes/forum.go @@ -5,7 +5,7 @@ import ( "net/http" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" @@ -19,7 +19,7 @@ var forumStmts ForumStmts // TODO: Move these DbInits into *Forum as Topics() func init() { - common.DbInits.Add(func(acc *qgen.Accumulator) error { + c.DbInits.Add(func(acc *qgen.Accumulator) error { forumStmts = ForumStmts{ getTopics: acc.Select("topics").Columns("tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, lastReplyID, parentID, views, postCount, likeCount").Where("parentID = ?").Orderby("sticky DESC, lastReplyAt DESC, createdBy DESC").Limit("?,?").Prepare(), } @@ -28,55 +28,55 @@ func init() { } // TODO: Retire this in favour of an alias for /topics/? -func ViewForum(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header, sfid string) common.RouteError { +func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, sfid string) c.RouteError { page, _ := strconv.Atoi(r.FormValue("page")) _, fid, err := ParseSEOURL(sfid) if err != nil { - return common.PreError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r) + return c.PreError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r) } - ferr := common.ForumUserCheck(header, w, r, &user, fid) + ferr := c.ForumUserCheck(header, w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } header.Path = "/forums/" // TODO: Fix this double-check - forum, err := common.Forums.Get(fid) + forum, err := c.Forums.Get(fid) if err == sql.ErrNoRows { - return common.NotFound(w, r, header) + return c.NotFound(w, r, header) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } header.Title = forum.Name header.OGDesc = forum.Desc // TODO: Does forum.TopicCount take the deleted items into consideration for guests? We don't have soft-delete yet, only hard-delete - offset, page, lastPage := common.PageOffset(forum.TopicCount, page, common.Config.ItemsPerPage) + offset, page, lastPage := c.PageOffset(forum.TopicCount, page, c.Config.ItemsPerPage) // TODO: Move this to *Forum - rows, err := forumStmts.getTopics.Query(fid, offset, common.Config.ItemsPerPage) + rows, err := forumStmts.getTopics.Query(fid, offset, c.Config.ItemsPerPage) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } defer rows.Close() // TODO: Use something other than TopicsRow as we don't need to store the forum name and link on each and every topic item? - var topicList []*common.TopicsRow + var topicList []*c.TopicsRow var reqUserList = make(map[int]bool) for rows.Next() { - var topicItem = common.TopicsRow{ID: 0} + var topicItem = c.TopicsRow{ID: 0} err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.IsClosed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.LastReplyBy, &topicItem.LastReplyID, &topicItem.ParentID, &topicItem.ViewCount, &topicItem.PostCount, &topicItem.LikeCount) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - topicItem.Link = common.BuildTopicURL(common.NameToSlug(topicItem.Title), topicItem.ID) + topicItem.Link = c.BuildTopicURL(c.NameToSlug(topicItem.Title), topicItem.ID) // TODO: Create a specialised function with a bit less overhead for getting the last page for a post count - _, _, lastPage := common.PageOffset(topicItem.PostCount, 1, common.Config.ItemsPerPage) + _, _, lastPage := c.PageOffset(topicItem.PostCount, 1, c.Config.ItemsPerPage) topicItem.LastPage = lastPage header.Hooks.VhookNoRet("forum_trow_assign", &topicItem, &forum) @@ -86,7 +86,7 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user common.User, header } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Convert the user ID map to a slice, then bulk load the users @@ -98,9 +98,9 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user common.User, header } // TODO: What if a user is deleted via the Control Panel? - userList, err := common.Users.BulkGetMap(idSlice) + userList, err := c.Users.BulkGetMap(idSlice) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Second pass to the add the user data @@ -116,14 +116,14 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user common.User, header if r.FormValue("js") == "1" { outBytes, err := wsTopicList(topicList, lastPage).MarshalJSON() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } w.Write(outBytes) return nil } - pageList := common.Paginate(forum.TopicCount, common.Config.ItemsPerPage, 5) - pi := common.ForumPage{header, topicList, forum, common.Paginator{pageList, page, lastPage}} + pageList := c.Paginate(forum.TopicCount, c.Config.ItemsPerPage, 5) + pi := c.ForumPage{header, topicList, forum, c.Paginator{pageList, page, lastPage}} ferr = renderTemplate("forum", w, r, header, pi) counters.ForumViewCounter.Bump(forum.ID) return ferr diff --git a/routes/forum_list.go b/routes/forum_list.go index 777f05d0..292bbb76 100644 --- a/routes/forum_list.go +++ b/routes/forum_list.go @@ -4,40 +4,40 @@ import ( "log" "net/http" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) -func ForumList(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func ForumList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { header.Title = phrases.GetTitlePhrase("forums") header.Zone = "forums" header.Path = "/forums/" header.MetaDesc = header.Settings["meta_desc"].(string) var err error - var forumList []common.Forum + var forumList []c.Forum var canSee []int if user.IsSuperAdmin { - canSee, err = common.Forums.GetAllVisibleIDs() + canSee, err = c.Forums.GetAllVisibleIDs() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } else { - group, err := common.Groups.Get(user.Group) + group, err := c.Groups.Get(user.Group) if err != nil { - log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) - return common.LocalError("Something weird happened", w, r, user) + log.Printf("Group #%d doesn't exist despite being used by c.User #%d", user.Group, user.ID) + return c.LocalError("Something weird happened", w, r, user) } canSee = group.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 - var forum = common.Forums.DirtyGet(fid).Copy() + var forum = c.Forums.DirtyGet(fid).Copy() if forum.ParentID == 0 && forum.Name != "" && forum.Active { if forum.LastTopicID != 0 { if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 0 { - forum.LastTopicTime = common.RelativeTime(forum.LastTopic.LastReplyAt) + forum.LastTopicTime = c.RelativeTime(forum.LastTopic.LastReplyAt) } else { forum.LastTopicTime = "" } @@ -49,6 +49,6 @@ func ForumList(w http.ResponseWriter, r *http.Request, user common.User, header } } - pi := common.ForumsPage{header, forumList} + pi := c.ForumsPage{header, forumList} return renderTemplate("forums", w, r, header, pi) } diff --git a/routes/misc.go b/routes/misc.go index 01964b6f..22702440 100644 --- a/routes/misc.go +++ b/routes/misc.go @@ -9,17 +9,17 @@ import ( "strings" "time" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) -var cacheControlMaxAge = "max-age=" + strconv.Itoa(int(common.Day)) // TODO: Make this a common.Config value +var cacheControlMaxAge = "max-age=" + strconv.Itoa(int(c.Day)) // TODO: Make this a c.Config value // GET functions func StaticFile(w http.ResponseWriter, r *http.Request) { - file, ok := common.StaticFiles.Get(r.URL.Path) + file, ok := c.StaticFiles.Get(r.URL.Path) if !ok { - common.DebugLogf("Failed to find '%s'", r.URL.Path) // TODO: Use MicroNotFound? Might be better than the unneccessary overhead of sprintf + c.DebugLogf("Failed to find '%s'", r.URL.Path) // TODO: Use MicroNotFound? Might be better than the unneccessary overhead of sprintf w.WriteHeader(http.StatusNotFound) return } @@ -47,56 +47,56 @@ func StaticFile(w http.ResponseWriter, r *http.Request) { // Other options instead of io.Copy: io.CopyN(), w.Write(), http.ServeContent() } -func Overview(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func Overview(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { header.Title = phrases.GetTitlePhrase("overview") header.Zone = "overview" - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} return renderTemplate("overview", w, r, header, pi) } -func CustomPage(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header, name string) common.RouteError { +func CustomPage(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, name string) c.RouteError { header.Zone = "custom_page" - name = common.SanitiseSingleLine(name) - page, err := common.Pages.GetByName(name) + name = c.SanitiseSingleLine(name) + page, err := c.Pages.GetByName(name) if err == nil { header.Title = page.Title - pi := common.CustomPagePage{header, page} + pi := c.CustomPagePage{header, page} return renderTemplate("custom_page", w, r, header, pi) } else if err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // ! Is this safe? - if common.DefaultTemplates.Lookup("page_"+name+".html") == nil { - return common.NotFound(w, r, header) + if c.DefaultTemplates.Lookup("page_"+name+".html") == nil { + return c.NotFound(w, r, header) } header.Title = phrases.GetTitlePhrase("page") - pi := common.Page{header, tList, nil} + pi := c.Page{header, tList, nil} // TODO: Pass the page name to the pre-render hook? - if common.RunPreRenderHook("pre_render_tmpl_page", w, r, &user, &pi) { + if c.RunPreRenderHook("pre_render_tmpl_page", w, r, &user, &pi) { return nil } err = header.Theme.RunTmpl("page_"+name, pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } // TODO: Set the cookie domain -func ChangeTheme(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func ChangeTheme(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { //headerLite, _ := SimpleUserCheck(w, r, &user) // TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly? isJs := (r.PostFormValue("isJs") == "1") - newTheme := common.SanitiseSingleLine(r.PostFormValue("newTheme")) + newTheme := c.SanitiseSingleLine(r.PostFormValue("newTheme")) - theme, ok := common.Themes[newTheme] + theme, ok := c.Themes[newTheme] if !ok || theme.HideFromThemes { - return common.LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) + return c.LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) } - cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: int(common.Year)} + cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: int(c.Year)} http.SetCookie(w, &cookie) if !isJs { diff --git a/routes/moderate.go b/routes/moderate.go index dba652f8..785b7dde 100644 --- a/routes/moderate.go +++ b/routes/moderate.go @@ -3,37 +3,37 @@ package routes import ( "net/http" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) -func IPSearch(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func IPSearch(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { header.Title = phrases.GetTitlePhrase("ip_search") // TODO: How should we handle the permissions if we extend this into an alt detector of sorts? if !user.Perms.ViewIPs { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } // TODO: Reject IP Addresses with illegal characters - var ip = common.SanitiseSingleLine(r.FormValue("ip")) - uids, err := common.IPSearch.Lookup(ip) + var ip = c.SanitiseSingleLine(r.FormValue("ip")) + uids, err := c.IPSearch.Lookup(ip) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: What if a user is deleted via the Control Panel? We'll cross that bridge when we come to it, although we might lean towards blanking the account and removing the related data rather than purging it - userList, err := common.Users.BulkGetMap(uids) + userList, err := c.Users.BulkGetMap(uids) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - pi := common.IPSearchPage{header, userList, ip} - if common.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) { + pi := c.IPSearchPage{header, userList, ip} + if c.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) { return nil } err = header.Theme.RunTmpl("ip_search", pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } diff --git a/routes/panel/analytics.go b/routes/panel/analytics.go index 83d9299c..59a3deec 100644 --- a/routes/panel/analytics.go +++ b/routes/panel/analytics.go @@ -8,7 +8,7 @@ import ( "strconv" "time" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" ) @@ -103,7 +103,7 @@ func analyticsRowsToViewMap(rows *sql.Rows, labelList []int64, viewMap map[int64 } var unixCreatedAt = createdAt.Unix() // TODO: Bulk log this - if common.Dev.SuperDebug { + if c.Dev.SuperDebug { log.Print("count: ", count) log.Print("createdAt: ", createdAt) log.Print("unixCreatedAt: ", unixCreatedAt) @@ -118,7 +118,7 @@ func analyticsRowsToViewMap(rows *sql.Rows, labelList []int64, viewMap map[int64 return viewMap, rows.Err() } -func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *common.User) (*common.BasePanelPage, common.RouteError) { +func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *c.User) (*c.BasePanelPage, c.RouteError) { basePage, ferr := buildBasePage(w, r, user, "analytics", "analytics") if ferr != nil { return nil, ferr @@ -129,336 +129,336 @@ func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *common.Use return basePage, nil } -func AnalyticsViews(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsViews(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - common.DebugLog("in panel.AnalyticsViews") + c.DebugLog("in panel.AnalyticsViews") // TODO: Add some sort of analytics store / iterator? rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 - var viewItems []common.PanelAnalyticsItem + var viewItems []c.PanelAnalyticsItem for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) - viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) + viewItems = append(viewItems, c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) var ttime string if timeRange.Range == "six-hours" || timeRange.Range == "twelve-hours" || timeRange.Range == "one-day" { ttime = "time" } - pi := common.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, ttime} + pi := c.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, ttime} return renderTemplate("panel_analytics_views", w, r, basePage.Header, &pi) } -func AnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user common.User, route string) common.RouteError { +func AnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user c.User, route string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - common.DebugLog("in panel.AnalyticsRouteViews") + c.DebugLog("in panel.AnalyticsRouteViews") // TODO: Validate the route is valid rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, createdAt").Where("route = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(route) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 - var viewItems []common.PanelAnalyticsItem + var viewItems []c.PanelAnalyticsItem for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) - viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) + viewItems = append(viewItems, c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) - pi := common.PanelAnalyticsRoutePage{basePage, common.SanitiseSingleLine(route), graph, viewItems, timeRange.Range} + pi := c.PanelAnalyticsRoutePage{basePage, c.SanitiseSingleLine(route), graph, viewItems, timeRange.Range} return renderTemplate("panel_analytics_route_views", w, r, basePage.Header, &pi) } -func AnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user common.User, agent string) common.RouteError { +func AnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user c.User, agent string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) // ? Only allow valid agents? The problem with this is that agents wind up getting renamed and it would take a migration to get them all up to snuff - agent = common.SanitiseSingleLine(agent) + agent = c.SanitiseSingleLine(agent) - common.DebugLog("in panel.AnalyticsAgentViews") + c.DebugLog("in panel.AnalyticsAgentViews") // TODO: Verify the agent is valid rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, createdAt").Where("browser = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(agent) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) friendlyAgent, ok := phrases.GetUserAgentPhrase(agent) if !ok { friendlyAgent = agent } - pi := common.PanelAnalyticsAgentPage{basePage, agent, friendlyAgent, graph, timeRange.Range} + pi := c.PanelAnalyticsAgentPage{basePage, agent, friendlyAgent, graph, timeRange.Range} return renderTemplate("panel_analytics_agent_views", w, r, basePage.Header, &pi) } -func AnalyticsForumViews(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { +func AnalyticsForumViews(w http.ResponseWriter, r *http.Request, user c.User, sfid string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) fid, err := strconv.Atoi(sfid) if err != nil { - return common.LocalError("Invalid integer", w, r, user) + return c.LocalError("Invalid integer", w, r, user) } - common.DebugLog("in panel.AnalyticsForumViews") + c.DebugLog("in panel.AnalyticsForumViews") // TODO: Verify the agent is valid rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count, createdAt").Where("forum = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(fid) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) - forum, err := common.Forums.Get(fid) + forum, err := c.Forums.Get(fid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - pi := common.PanelAnalyticsAgentPage{basePage, sfid, forum.Name, graph, timeRange.Range} + pi := c.PanelAnalyticsAgentPage{basePage, sfid, forum.Name, graph, timeRange.Range} return renderTemplate("panel_analytics_forum_views", w, r, basePage.Header, &pi) } -func AnalyticsSystemViews(w http.ResponseWriter, r *http.Request, user common.User, system string) common.RouteError { +func AnalyticsSystemViews(w http.ResponseWriter, r *http.Request, user c.User, system string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - system = common.SanitiseSingleLine(system) + system = c.SanitiseSingleLine(system) - common.DebugLog("in panel.AnalyticsSystemViews") + c.DebugLog("in panel.AnalyticsSystemViews") // TODO: Verify the OS name is valid rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, createdAt").Where("system = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(system) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) friendlySystem, ok := phrases.GetOSPhrase(system) if !ok { friendlySystem = system } - pi := common.PanelAnalyticsAgentPage{basePage, system, friendlySystem, graph, timeRange.Range} + pi := c.PanelAnalyticsAgentPage{basePage, system, friendlySystem, graph, timeRange.Range} return renderTemplate("panel_analytics_system_views", w, r, basePage.Header, &pi) } -func AnalyticsLanguageViews(w http.ResponseWriter, r *http.Request, user common.User, lang string) common.RouteError { +func AnalyticsLanguageViews(w http.ResponseWriter, r *http.Request, user c.User, lang string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - lang = common.SanitiseSingleLine(lang) + lang = c.SanitiseSingleLine(lang) - common.DebugLog("in panel.AnalyticsLanguageViews") + c.DebugLog("in panel.AnalyticsLanguageViews") // TODO: Verify the language code is valid rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, createdAt").Where("lang = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(lang) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) friendlyLang, ok := phrases.GetHumanLangPhrase(lang) if !ok { friendlyLang = lang } - pi := common.PanelAnalyticsAgentPage{basePage, lang, friendlyLang, graph, timeRange.Range} + pi := c.PanelAnalyticsAgentPage{basePage, lang, friendlyLang, graph, timeRange.Range} return renderTemplate("panel_analytics_lang_views", w, r, basePage.Header, &pi) } -func AnalyticsReferrerViews(w http.ResponseWriter, r *http.Request, user common.User, domain string) common.RouteError { +func AnalyticsReferrerViews(w http.ResponseWriter, r *http.Request, user c.User, domain string) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - common.DebugLog("in panel.AnalyticsReferrerViews") + c.DebugLog("in panel.AnalyticsReferrerViews") // TODO: Verify the agent is valid rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count, createdAt").Where("domain = ?").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query(domain) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) - pi := common.PanelAnalyticsAgentPage{basePage, common.SanitiseSingleLine(domain), "", graph, timeRange.Range} + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) + pi := c.PanelAnalyticsAgentPage{basePage, c.SanitiseSingleLine(domain), "", graph, timeRange.Range} return renderTemplate("panel_analytics_referrer_views", w, r, basePage.Header, &pi) } -func AnalyticsTopics(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsTopics(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - common.DebugLog("in panel.AnalyticsTopics") + c.DebugLog("in panel.AnalyticsTopics") rows, err := qgen.NewAcc().Select("topicchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 - var viewItems []common.PanelAnalyticsItem + var viewItems []c.PanelAnalyticsItem for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) - viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) + viewItems = append(viewItems, c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) - pi := common.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) + pi := c.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} return renderTemplate("panel_analytics_topics", w, r, basePage.Header, &pi) } -func AnalyticsPosts(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsPosts(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) - common.DebugLog("in panel.AnalyticsPosts") + c.DebugLog("in panel.AnalyticsPosts") rows, err := qgen.NewAcc().Select("postchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var viewList []int64 - var viewItems []common.PanelAnalyticsItem + var viewItems []c.PanelAnalyticsItem for _, value := range revLabelList { viewList = append(viewList, viewMap[value]) - viewItems = append(viewItems, common.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) + viewItems = append(viewItems, c.PanelAnalyticsItem{Time: value, Count: viewMap[value]}) } - graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} - common.DebugLogf("graph: %+v\n", graph) - pi := common.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} + graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} + c.DebugLogf("graph: %+v\n", graph) + pi := c.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} return renderTemplate("panel_analytics_posts", w, r, basePage.Header, &pi) } @@ -473,7 +473,7 @@ func analyticsRowsToNameMap(rows *sql.Rows) (map[string]int, error) { return nameMap, err } // TODO: Bulk log this - if common.Dev.SuperDebug { + if c.Dev.SuperDebug { log.Print("count: ", count) log.Print("name: ", name) } @@ -497,7 +497,7 @@ func analyticsRowsToDuoMap(rows *sql.Rows, labelList []int64, viewMap map[int64] // TODO: Bulk log this var unixCreatedAt = createdAt.Unix() - if common.Dev.SuperDebug { + if c.Dev.SuperDebug { log.Print("count: ", count) log.Print("name: ", name) log.Print("createdAt: ", createdAt) @@ -557,7 +557,7 @@ func analyticsVMapToOVList(vMap map[string]map[int64]int64) (ovList []OVItem) { return tOVList } -func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsForums(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr @@ -567,17 +567,17 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) rows, err := qgen.NewAcc().Select("viewchunks_forums").Columns("count, forum, createdAt").Where("forum != ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } vMap, forumMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } ovList := analyticsVMapToOVList(vMap) @@ -592,15 +592,15 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c vList = append(vList, viewList) fid, err := strconv.Atoi(ovitem.name) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var lName string - forum, err := common.Forums.Get(fid) + forum, err := c.Forums.Get(fid) if err == sql.ErrNoRows { // TODO: Localise this lName = "Deleted Forum" } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else { lName = forum.Name } @@ -610,38 +610,38 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c } i++ } - graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} + c.DebugLogf("graph: %+v\n", graph) // TODO: Sort this slice - var forumItems []common.PanelAnalyticsAgentsItem + var forumItems []c.PanelAnalyticsAgentsItem for sfid, count := range forumMap { fid, err := strconv.Atoi(sfid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var lName string - forum, err := common.Forums.Get(fid) + forum, err := c.Forums.Get(fid) if err == sql.ErrNoRows { // TODO: Localise this lName = "Deleted Forum" } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } else { lName = forum.Name } - forumItems = append(forumItems, common.PanelAnalyticsAgentsItem{ + forumItems = append(forumItems, c.PanelAnalyticsAgentsItem{ Agent: sfid, FriendlyAgent: lName, Count: count, }) } - pi := common.PanelAnalyticsDuoPage{basePage, forumItems, graph, timeRange.Range} + pi := c.PanelAnalyticsDuoPage{basePage, forumItems, graph, timeRange.Range} return renderTemplate("panel_analytics_forums", w, r, basePage.Header, &pi) } -func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr @@ -651,17 +651,17 @@ func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) c timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, route, createdAt").Where("route != ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } vMap, routeMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } ovList := analyticsVMapToOVList(vMap) @@ -680,24 +680,24 @@ func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) c } i++ } - graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} + c.DebugLogf("graph: %+v\n", graph) // TODO: Sort this slice - var routeItems []common.PanelAnalyticsRoutesItem + var routeItems []c.PanelAnalyticsRoutesItem for route, count := range routeMap { - routeItems = append(routeItems, common.PanelAnalyticsRoutesItem{ + routeItems = append(routeItems, c.PanelAnalyticsRoutesItem{ Route: route, Count: count, }) } - pi := common.PanelAnalyticsRoutesPage{basePage, routeItems, graph, timeRange.Range} + pi := c.PanelAnalyticsRoutesPage{basePage, routeItems, graph, timeRange.Range} return renderTemplate("panel_analytics_routes", w, r, basePage.Header, &pi) } // Trialling multi-series charts -func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr @@ -707,17 +707,17 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) c timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, browser, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } vMap, agentMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } ovList := analyticsVMapToOVList(vMap) @@ -740,28 +740,28 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) c } i++ } - graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} + c.DebugLogf("graph: %+v\n", graph) // TODO: Sort this slice - var agentItems []common.PanelAnalyticsAgentsItem + var agentItems []c.PanelAnalyticsAgentsItem for agent, count := range agentMap { aAgent, ok := phrases.GetUserAgentPhrase(agent) if !ok { aAgent = agent } - agentItems = append(agentItems, common.PanelAnalyticsAgentsItem{ + agentItems = append(agentItems, c.PanelAnalyticsAgentsItem{ Agent: agent, FriendlyAgent: aAgent, Count: count, }) } - pi := common.PanelAnalyticsDuoPage{basePage, agentItems, graph, timeRange.Range} + pi := c.PanelAnalyticsDuoPage{basePage, agentItems, graph, timeRange.Range} return renderTemplate("panel_analytics_agents", w, r, basePage.Header, &pi) } -func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr @@ -771,17 +771,17 @@ func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user common.User) timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, system, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } vMap, osMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } ovList := analyticsVMapToOVList(vMap) @@ -804,28 +804,28 @@ func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user common.User) } i++ } - graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} + c.DebugLogf("graph: %+v\n", graph) // TODO: Sort this slice - var systemItems []common.PanelAnalyticsAgentsItem + var systemItems []c.PanelAnalyticsAgentsItem for system, count := range osMap { sSystem, ok := phrases.GetOSPhrase(system) if !ok { sSystem = system } - systemItems = append(systemItems, common.PanelAnalyticsAgentsItem{ + systemItems = append(systemItems, c.PanelAnalyticsAgentsItem{ Agent: system, FriendlyAgent: sSystem, Count: count, }) } - pi := common.PanelAnalyticsDuoPage{basePage, systemItems, graph, timeRange.Range} + pi := c.PanelAnalyticsDuoPage{basePage, systemItems, graph, timeRange.Range} return renderTemplate("panel_analytics_systems", w, r, basePage.Header, &pi) } -func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := PreAnalyticsDetail(w, r, &user) if ferr != nil { return ferr @@ -835,17 +835,17 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user common.User timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, lang, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } vMap, langMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } ovList := analyticsVMapToOVList(vMap) @@ -868,56 +868,56 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user common.User } i++ } - graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} - common.DebugLogf("graph: %+v\n", graph) + graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} + c.DebugLogf("graph: %+v\n", graph) // TODO: Can we de-duplicate these analytics functions further? // TODO: Sort this slice - var langItems []common.PanelAnalyticsAgentsItem + var langItems []c.PanelAnalyticsAgentsItem for lang, count := range langMap { lLang, ok := phrases.GetHumanLangPhrase(lang) if !ok { lLang = lang } - langItems = append(langItems, common.PanelAnalyticsAgentsItem{ + langItems = append(langItems, c.PanelAnalyticsAgentsItem{ Agent: lang, FriendlyAgent: lLang, Count: count, }) } - pi := common.PanelAnalyticsDuoPage{basePage, langItems, graph, timeRange.Range} + pi := c.PanelAnalyticsDuoPage{basePage, langItems, graph, timeRange.Range} return renderTemplate("panel_analytics_langs", w, r, basePage.Header, &pi) } -func AnalyticsReferrers(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func AnalyticsReferrers(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "analytics", "analytics") if ferr != nil { return ferr } timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) if err != nil { - return common.LocalError(err.Error(), w, r, user) + return c.LocalError(err.Error(), w, r, user) } rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count, domain").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } refMap, err := analyticsRowsToNameMap(rows) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Sort this slice - var refItems []common.PanelAnalyticsAgentsItem + var refItems []c.PanelAnalyticsAgentsItem for domain, count := range refMap { - refItems = append(refItems, common.PanelAnalyticsAgentsItem{ - Agent: common.SanitiseSingleLine(domain), + refItems = append(refItems, c.PanelAnalyticsAgentsItem{ + Agent: c.SanitiseSingleLine(domain), Count: count, }) } - pi := common.PanelAnalyticsAgentsPage{basePage, refItems, timeRange.Range} + pi := c.PanelAnalyticsAgentsPage{basePage, refItems, timeRange.Range} return renderTemplate("panel_analytics_referrers", w, r, basePage.Header, &pi) } diff --git a/routes/panel/backups.go b/routes/panel/backups.go index f84ebe0d..07ecf3af 100644 --- a/routes/panel/backups.go +++ b/routes/panel/backups.go @@ -7,10 +7,10 @@ import ( "path/filepath" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" ) -func Backups(w http.ResponseWriter, r *http.Request, user common.User, backupURL string) common.RouteError { +func Backups(w http.ResponseWriter, r *http.Request, user c.User, backupURL string) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "backups", "backups") if ferr != nil { return ferr @@ -18,15 +18,15 @@ func Backups(w http.ResponseWriter, r *http.Request, user common.User, backupURL if backupURL != "" { // We don't want them trying to break out of this directory, it shouldn't hurt since it's a super admin, but it's always good to practice good security hygiene, especially if this is one of many instances on a managed server not controlled by the superadmin/s - backupURL = common.Stripslashes(backupURL) + backupURL = c.Stripslashes(backupURL) var ext = filepath.Ext("./backups/" + backupURL) if ext != ".sql" && ext != ".zip" { - return common.NotFound(w, r, basePage.Header) + return c.NotFound(w, r, basePage.Header) } info, err := os.Stat("./backups/" + backupURL) if err != nil { - return common.NotFound(w, r, basePage.Header) + return c.NotFound(w, r, basePage.Header) } w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10)) @@ -44,19 +44,19 @@ func Backups(w http.ResponseWriter, r *http.Request, user common.User, backupURL return nil } - var backupList []common.BackupItem + var backupList []c.BackupItem backupFiles, err := ioutil.ReadDir("./backups") if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } for _, backupFile := range backupFiles { var ext = filepath.Ext(backupFile.Name()) if ext != ".sql" { continue } - backupList = append(backupList, common.BackupItem{backupFile.Name(), backupFile.ModTime()}) + backupList = append(backupList, c.BackupItem{backupFile.Name(), backupFile.ModTime()}) } - pi := common.PanelBackupPage{basePage, backupList} + pi := c.PanelBackupPage{basePage, backupList} return renderTemplate("panel_backups", w, r, basePage.Header, &pi) } diff --git a/routes/panel/common.go b/routes/panel/common.go index e57b77ef..4f7e8e02 100644 --- a/routes/panel/common.go +++ b/routes/panel/common.go @@ -3,7 +3,7 @@ package panel import ( "net/http" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) @@ -12,7 +12,7 @@ var tList []interface{} var successJSONBytes = []byte(`{"success":"1"}`) // We're trying to reduce the amount of boilerplate in here, so I added these two functions, they might wind up circulating outside this file in the future -func successRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs bool) common.RouteError { +func successRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs bool) c.RouteError { if !isJs { http.Redirect(w, r, dest, http.StatusSeeOther) } else { @@ -21,25 +21,25 @@ func successRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs b return nil } -func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *common.Header, pi interface{}) common.RouteError { +func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *c.Header, pi interface{}) c.RouteError { header.AddScript("global.js") - if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &header.CurrentUser, pi) { + if c.RunPreRenderHook("pre_render_"+tmplName, w, r, &header.CurrentUser, pi) { return nil } // TODO: Prepend this with panel_? err := header.Theme.RunTmpl(tmplName, pi, w) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return nil } -func buildBasePage(w http.ResponseWriter, r *http.Request, user *common.User, titlePhrase string, zone string) (*common.BasePanelPage, common.RouteError) { - header, stats, ferr := common.PanelUserCheck(w, r, user) +func buildBasePage(w http.ResponseWriter, r *http.Request, user *c.User, titlePhrase string, zone string) (*c.BasePanelPage, c.RouteError) { + header, stats, ferr := c.PanelUserCheck(w, r, user) if ferr != nil { return nil, ferr } header.Title = phrases.GetTitlePhrase("panel_" + titlePhrase) - return &common.BasePanelPage{header, stats, zone, common.ReportForumID}, nil + return &c.BasePanelPage{header, stats, zone, c.ReportForumID}, nil } diff --git a/routes/panel/debug.go b/routes/panel/debug.go index 71eafda9..fb411174 100644 --- a/routes/panel/debug.go +++ b/routes/panel/debug.go @@ -6,11 +6,11 @@ import ( "strconv" "time" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) -func Debug(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "debug", "debug") if ferr != nil { return ferr @@ -19,7 +19,7 @@ func Debug(w http.ResponseWriter, r *http.Request, user common.User) common.Rout goVersion := runtime.Version() dbVersion := qgen.Builder.DbVersion() var uptime string - upDuration := time.Since(common.StartTime) + upDuration := time.Since(c.StartTime) hours := int(upDuration.Hours()) minutes := int(upDuration.Minutes()) if hours > 24 { @@ -41,6 +41,6 @@ func Debug(w http.ResponseWriter, r *http.Request, user common.User) common.Rout var memStats runtime.MemStats runtime.ReadMemStats(&memStats) - pi := common.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, memStats} + pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, memStats} return renderTemplate("panel_debug", w, r, basePage.Header, &pi) } diff --git a/routes/panel/themes.go b/routes/panel/themes.go index 136ac29a..42821752 100644 --- a/routes/panel/themes.go +++ b/routes/panel/themes.go @@ -8,21 +8,21 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) -func Themes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func Themes(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "themes", "themes") if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } - var pThemeList, vThemeList []*common.Theme - for _, theme := range common.Themes { + var pThemeList, vThemeList []*c.Theme + for _, theme := range c.Themes { if theme.HideFromThemes { continue } @@ -33,88 +33,88 @@ func Themes(w http.ResponseWriter, r *http.Request, user common.User) common.Rou } } - pi := common.PanelThemesPage{basePage, pThemeList, vThemeList} + pi := c.PanelThemesPage{basePage, pThemeList, vThemeList} return renderTemplate("panel_themes", w, r, basePage.Header, &pi) } -func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user c.User, uname string) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } - theme, ok := common.Themes[uname] + theme, ok := c.Themes[uname] if !ok { - return common.LocalError("The theme isn't registered in the system", w, r, user) + return c.LocalError("The theme isn't registered in the system", w, r, user) } if theme.Disabled { - return common.LocalError("You must not enable this theme", w, r, user) + return c.LocalError("You must not enable this theme", w, r, user) } - err := common.UpdateDefaultTheme(theme) + err := c.UpdateDefaultTheme(theme) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther) return nil } -func ThemesMenus(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func ThemesMenus(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "themes_menus", "themes") if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } - var menuList []common.PanelMenuListItem - for mid, list := range common.Menus.GetAllMap() { + var menuList []c.PanelMenuListItem + for mid, list := range c.Menus.GetAllMap() { var name = "" if mid == 1 { name = phrases.GetTmplPhrase("panel_themes_menus_main") } - menuList = append(menuList, common.PanelMenuListItem{ + menuList = append(menuList, c.PanelMenuListItem{ Name: name, ID: mid, ItemCount: len(list.List), }) } - pi := common.PanelMenuListPage{basePage, menuList} + pi := c.PanelMenuListPage{basePage, menuList} return renderTemplate("panel_themes_menus", w, r, basePage.Header, &pi) } -func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError { +func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user c.User, smid string) c.RouteError { // TODO: Something like Menu #1 for the title? basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes") if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js") mid, err := strconv.Atoi(smid) if err != nil { - return common.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) } - menuHold, err := common.Menus.Get(mid) + menuHold, err := c.Menus.Get(mid) if err == sql.ErrNoRows { - return common.NotFound(w, r, basePage.Header) + return c.NotFound(w, r, basePage.Header) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - var menuList []common.MenuItem + var menuList []c.MenuItem for _, item := range menuHold.List { - var menuTmpls = map[string]common.MenuTmpl{ + var menuTmpls = map[string]c.MenuTmpl{ item.TmplName: menuHold.Parse(item.Name, []byte("{{.Name}}")), } var renderBuffer [][]byte @@ -132,39 +132,39 @@ func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user common.User, s menuList = append(menuList, item) } - pi := common.PanelMenuPage{basePage, mid, menuList} + pi := c.PanelMenuPage{basePage, mid, menuList} return renderTemplate("panel_themes_menus_items", w, r, basePage.Header, &pi) } -func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { +func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { // TODO: Something like Menu #1 for the title? basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes") if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } itemID, err := strconv.Atoi(sitemID) if err != nil { - return common.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) } - menuItem, err := common.Menus.ItemStore().Get(itemID) + menuItem, err := c.Menus.ItemStore().Get(itemID) if err == sql.ErrNoRows { - return common.NotFound(w, r, basePage.Header) + return c.NotFound(w, r, basePage.Header) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - pi := common.PanelMenuItemPage{basePage, menuItem} + pi := c.PanelMenuItemPage{basePage, menuItem} return renderTemplate("panel_themes_menus_item_edit", w, r, basePage.Header, &pi) } -func themesMenuItemSetters(r *http.Request, menuItem common.MenuItem) common.MenuItem { +func themesMenuItemSetters(r *http.Request, menuItem c.MenuItem) c.MenuItem { var getItem = func(name string) string { - return common.SanitiseSingleLine(r.PostFormValue("item-" + name)) + return c.SanitiseSingleLine(r.PostFormValue("item-" + name)) } menuItem.Name = getItem("name") menuItem.HTMLID = getItem("htmlid") @@ -208,113 +208,113 @@ func themesMenuItemSetters(r *http.Request, menuItem common.MenuItem) common.Men return menuItem } -func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } itemID, err := strconv.Atoi(sitemID) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - menuItem, err := common.Menus.ItemStore().Get(itemID) + menuItem, err := c.Menus.ItemStore().Get(itemID) if err == sql.ErrNoRows { - return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs) + return c.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } //menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad menuItem = themesMenuItemSetters(r, menuItem) err = menuItem.Commit() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs) } -func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } smenuID := r.PostFormValue("mid") if smenuID == "" { - return common.LocalErrorJSQ("No menuID provided", w, r, user, isJs) + return c.LocalErrorJSQ("No menuID provided", w, r, user, isJs) } menuID, err := strconv.Atoi(smenuID) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - menuItem := common.MenuItem{MenuID: menuID} + menuItem := c.MenuItem{MenuID: menuID} menuItem = themesMenuItemSetters(r, menuItem) itemID, err := menuItem.Create() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs) } -func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } itemID, err := strconv.Atoi(sitemID) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - menuItem, err := common.Menus.ItemStore().Get(itemID) + menuItem, err := c.Menus.ItemStore().Get(itemID) if err == sql.ErrNoRows { - return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs) + return c.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } //menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad err = menuItem.Delete() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return successRedirect("/panel/themes/menus/", w, r, isJs) } -func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user c.User, smid string) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } mid, err := strconv.Atoi(smid) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - menuHold, err := common.Menus.Get(mid) + menuHold, err := c.Menus.Get(mid) if err == sql.ErrNoRows { - return common.LocalErrorJSQ("Can't find menu", w, r, user, isJs) + return c.LocalErrorJSQ("Can't find menu", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}") @@ -324,7 +324,7 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user comm for index, smiid := range strings.Split(sitems, ",") { miid, err := strconv.Atoi(smiid) if err != nil { - return common.LocalErrorJSQ("Invalid integer in menu item list", w, r, user, isJs) + return c.LocalErrorJSQ("Invalid integer in menu item list", w, r, user, isJs) } updateMap[miid] = index } @@ -333,38 +333,38 @@ func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user comm return successRedirect("/panel/themes/menus/edit/"+strconv.Itoa(mid), w, r, isJs) } -func ThemesWidgets(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func ThemesWidgets(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { basePage, ferr := buildBasePage(w, r, &user, "themes_widgets", "themes") if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } basePage.Header.AddScript("widgets.js") - var docks = make(map[string][]common.WidgetEdit) - for _, name := range common.GetDockList() { + var docks = make(map[string][]c.WidgetEdit) + for _, name := range c.GetDockList() { if name == "leftOfNav" || name == "rightOfNav" { continue } - var widgets []common.WidgetEdit - for _, widget := range common.GetDock(name) { + var widgets []c.WidgetEdit + for _, widget := range c.GetDock(name) { var data = make(map[string]string) err := json.Unmarshal([]byte(widget.RawBody), &data) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - widgets = append(widgets, common.WidgetEdit{widget, data}) + widgets = append(widgets, c.WidgetEdit{widget, data}) } docks[name] = widgets } - pi := common.PanelWidgetListPage{basePage, docks, common.WidgetEdit{&common.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_themes_widgets", w, r, basePage.Header, &pi) } -func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetEdit, error) { +func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error) { var data = make(map[string]string) widget.Enabled = (r.FormValue("wenabled") == "1") widget.Location = r.FormValue("wlocation") @@ -372,7 +372,7 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE return nil, errors.New("You need to specify a location for this widget.") } widget.Side = r.FormValue("wside") - if !common.HasDock(widget.Side) { + if !c.HasDock(widget.Side) { return nil, errors.New("The widget dock you specified doesn't exist.") } @@ -394,95 +394,95 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE return nil, errors.New("Unknown widget type") } - return &common.WidgetEdit{widget, data}, nil + return &c.WidgetEdit{widget, data}, nil } // ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget -func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError { +func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, swid string) c.RouteError { //fmt.Println("in ThemesWidgetsEditSubmit") - _, ferr := common.SimplePanelUserCheck(w, r, &user) + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } wid, err := strconv.Atoi(swid) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - widget, err := common.Widgets.Get(wid) + widget, err := c.Widgets.Get(wid) if err == sql.ErrNoRows { - return common.NotFoundJSQ(w, r, nil, isJs) + return c.NotFoundJSQ(w, r, nil, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } ewidget, err := widgetsParseInputs(r, widget.Copy()) if err != nil { - return common.LocalErrorJSQ(err.Error(), w, r, user, isJs) + return c.LocalErrorJSQ(err.Error(), w, r, user, isJs) } err = ewidget.Commit() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return successRedirect("/panel/themes/widgets/", w, r, isJs) } // 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 common.User) common.RouteError { +func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { //fmt.Println("in ThemesWidgetsCreateSubmit") isJs := (r.PostFormValue("js") == "1") - _, ferr := common.SimplePanelUserCheck(w, r, &user) + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } - ewidget, err := widgetsParseInputs(r, &common.Widget{}) + ewidget, err := widgetsParseInputs(r, &c.Widget{}) if err != nil { - return common.LocalErrorJSQ(err.Error(), w, r, user, isJs) + return c.LocalErrorJSQ(err.Error(), w, r, user, isJs) } err = ewidget.Create() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return successRedirect("/panel/themes/widgets/", w, r, isJs) } -func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError { - _, ferr := common.SimplePanelUserCheck(w, r, &user) +func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, swid string) c.RouteError { + _, ferr := c.SimplePanelUserCheck(w, r, &user) if ferr != nil { return ferr } isJs := (r.PostFormValue("js") == "1") if !user.Perms.ManageThemes { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } wid, err := strconv.Atoi(swid) if err != nil { - return common.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) + return c.LocalErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs) } - widget, err := common.Widgets.Get(wid) + widget, err := c.Widgets.Get(wid) if err == sql.ErrNoRows { - return common.NotFound(w, r, nil) + return c.NotFound(w, r, nil) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } err = widget.Delete() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } return successRedirect("/panel/themes/widgets/", w, r, isJs) diff --git a/routes/poll.go b/routes/poll.go index 0537ef08..ab6abcc0 100644 --- a/routes/poll.go +++ b/routes/poll.go @@ -6,85 +6,85 @@ import ( "net/http" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/query_gen" ) -func PollVote(w http.ResponseWriter, r *http.Request, user common.User, sPollID string) common.RouteError { +func PollVote(w http.ResponseWriter, r *http.Request, user c.User, sPollID string) c.RouteError { pollID, err := strconv.Atoi(sPollID) if err != nil { - return common.PreError("The provided PollID is not a valid number.", w, r) + return c.PreError("The provided PollID is not a valid number.", w, r) } - poll, err := common.Polls.Get(pollID) + poll, err := c.Polls.Get(pollID) if err == sql.ErrNoRows { - return common.PreError("The poll you tried to vote for doesn't exist.", w, r) + return c.PreError("The poll you tried to vote for doesn't exist.", w, r) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - var topic *common.Topic + var topic *c.Topic if poll.ParentTable == "replies" { - reply, err := common.Rstore.Get(poll.ParentID) + reply, err := c.Rstore.Get(poll.ParentID) if err == sql.ErrNoRows { - return common.PreError("The parent post doesn't exist.", w, r) + return c.PreError("The parent post doesn't exist.", w, r) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - topic, err = common.Topics.Get(reply.ParentID) + topic, err = c.Topics.Get(reply.ParentID) } else if poll.ParentTable == "topics" { - topic, err = common.Topics.Get(poll.ParentID) + topic, err = c.Topics.Get(poll.ParentID) } else { - return common.InternalError(errors.New("Unknown parentTable for poll"), w, r) + return c.InternalError(errors.New("Unknown parentTable for poll"), w, r) } if err == sql.ErrNoRows { - return common.PreError("The parent topic doesn't exist.", w, r) + return c.PreError("The parent topic doesn't exist.", w, r) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } optionIndex, err := strconv.Atoi(r.PostFormValue("poll_option_input")) if err != nil { - return common.LocalError("Malformed input", w, r, user) + return c.LocalError("Malformed input", w, r, user) } err = poll.CastVote(optionIndex, user.ID, user.LastIP) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID), http.StatusSeeOther) return nil } -func PollResults(w http.ResponseWriter, r *http.Request, user common.User, sPollID string) common.RouteError { +func PollResults(w http.ResponseWriter, r *http.Request, user c.User, sPollID string) c.RouteError { //log.Print("in PollResults") pollID, err := strconv.Atoi(sPollID) if err != nil { - return common.PreError("The provided PollID is not a valid number.", w, r) + return c.PreError("The provided PollID is not a valid number.", w, r) } - poll, err := common.Polls.Get(pollID) + poll, err := c.Polls.Get(pollID) if err == sql.ErrNoRows { - return common.PreError("The poll you tried to vote for doesn't exist.", w, r) + return c.PreError("The poll you tried to vote for doesn't exist.", w, r) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Abstract this rows, err := qgen.NewAcc().Select("polls_options").Columns("votes").Where("pollID = ?").Orderby("option ASC").Query(poll.ID) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } defer rows.Close() @@ -93,13 +93,13 @@ func PollResults(w http.ResponseWriter, r *http.Request, user common.User, sPoll var votes int err := rows.Scan(&votes) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } optionList += strconv.Itoa(votes) + "," } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Implement a version of this which doesn't rely so much on sequential order diff --git a/routes/profile.go b/routes/profile.go index f360daef..f5c478bb 100644 --- a/routes/profile.go +++ b/routes/profile.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" ) @@ -19,7 +19,7 @@ var profileStmts ProfileStmts // TODO: Move these DbInits into some sort of abstraction func init() { - common.DbInits.Add(func(acc *qgen.Accumulator) error { + c.DbInits.Add(func(acc *qgen.Accumulator) error { profileStmts = ProfileStmts{ getReplies: acc.SimpleLeftJoin("users_replies", "users", "users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group", "users_replies.createdBy = users.uid", "users_replies.uid = ?", "", ""), } @@ -28,7 +28,7 @@ func init() { } // TODO: Remove the View part of the name? -func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { // TODO: Preload this? header.AddSheet(header.Theme.Name + "/profile.css") if user.Loggedin { @@ -39,57 +39,57 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, heade var replyCreatedAt time.Time var replyContent, replyCreatedByName, replyAvatar, replyMicroAvatar, replyTag, replyClassName string var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyLines, replyGroup int - var replyList []common.ReplyUser + var replyList []c.ReplyUser // TODO: Do a 301 if it's the wrong username? Do a canonical too? _, pid, err := ParseSEOURL(r.URL.Path[len("/user/"):]) if err != nil { - return common.LocalError("The provided UserID is not a valid number.", w, r, user) + return c.LocalError("The provided UserID is not a valid number.", w, r, user) } - var puser *common.User + var puser *c.User if pid == user.ID { user.IsMod = true puser = &user } else { // Fetch the user data // TODO: Add a shared function for checking for ErrNoRows and internal erroring if it's not that case? - puser, err = common.Users.Get(pid) + puser, err = c.Users.Get(pid) if err == sql.ErrNoRows { - return common.NotFound(w, r, header) + return c.NotFound(w, r, header) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } puser.Init() } header.Title = phrases.GetTitlePhrasef("profile", puser.Name) - header.Path = common.BuildProfileURL(common.NameToSlug(puser.Name), puser.ID) + header.Path = c.BuildProfileURL(c.NameToSlug(puser.Name), puser.ID) // Get the replies.. rows, err := profileStmts.getReplies.Query(puser.ID) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } defer rows.Close() for rows.Next() { err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - group, err := common.Groups.Get(replyGroup) + group, err := c.Groups.Get(replyGroup) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } replyLines = strings.Count(replyContent, "\n") if group.IsMod { - replyClassName = common.Config.StaffCSS + replyClassName = c.Config.StaffCSS } else { replyClassName = "" } - replyAvatar, replyMicroAvatar = common.BuildAvatar(replyCreatedBy, replyAvatar) + replyAvatar, replyMicroAvatar = c.BuildAvatar(replyCreatedBy, replyAvatar) if group.Tag != "" { replyTag = group.Tag @@ -103,18 +103,18 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, heade replyLikeCount := 0 // TODO: Add a hook here - replyList = append(replyList, common.ReplyUser{rid, puser.ID, replyContent, common.ParseMessage(replyContent, 0, ""), replyCreatedBy, common.BuildProfileURL(common.NameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyMicroAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, 0, "", "", nil}) + replyList = append(replyList, c.ReplyUser{rid, puser.ID, replyContent, c.ParseMessage(replyContent, 0, ""), replyCreatedBy, c.BuildProfileURL(c.NameToSlug(replyCreatedByName), replyCreatedBy), replyCreatedByName, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, replyAvatar, replyMicroAvatar, replyClassName, replyLines, replyTag, "", "", "", 0, "", replyLiked, replyLikeCount, 0, "", "", nil}) } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Normalise the score so that the user sees their relative progress to the next level rather than showing them their total score - prevScore := common.GetLevelScore(puser.Level) + prevScore := c.GetLevelScore(puser.Level) currentScore := puser.Score - prevScore - nextScore := common.GetLevelScore(puser.Level+1) - prevScore + nextScore := c.GetLevelScore(puser.Level+1) - prevScore - ppage := common.ProfilePage{header, replyList, *puser, currentScore, nextScore} + ppage := c.ProfilePage{header, replyList, *puser, currentScore, nextScore} return renderTemplate("profile", w, r, header, ppage) } diff --git a/routes/reply.go b/routes/reply.go index 7218d3bc..314a4bff 100644 --- a/routes/reply.go +++ b/routes/reply.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" @@ -23,7 +23,7 @@ var replyStmts ReplyStmts // TODO: Move this statement somewhere else func init() { - common.DbInits.Add(func(acc *qgen.Accumulator) error { + c.DbInits.Add(func(acc *qgen.Accumulator) error { replyStmts = ReplyStmts{ // TODO: Less race-y attachment count updates updateAttachs: acc.Update("replies").Set("attachCount = ?").Where("rid = ?").Prepare(), @@ -37,43 +37,43 @@ type JsonReply struct { Content string } -func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { // TODO: Use this js := r.FormValue("js") == "1" tid, err := strconv.Atoi(r.PostFormValue("tid")) if err != nil { - return common.PreErrorJSQ("Failed to convert the Topic ID", w, r, js) + return c.PreErrorJSQ("Failed to convert the Topic ID", w, r, js) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("Couldn't find the parent topic", w, r, js) + return c.PreErrorJSQ("Couldn't find the parent topic", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateReply { - return common.NoPermissionsJSQ(w, r, user, js) + return c.NoPermissionsJSQ(w, r, user, js) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJSQ(w, r, user, js) + return c.NoPermissionsJSQ(w, r, user, js) } - content := common.PreparseMessage(r.PostFormValue("reply-content")) + content := c.PreparseMessage(r.PostFormValue("reply-content")) // TODO: Fully parse the post and put that in the parsed column - rid, err := common.Rstore.Create(topic, content, user.LastIP, user.ID) + rid, err := c.Rstore.Create(topic, content, user.LastIP, user.ID) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err != nil { - return common.LocalErrorJSQ("Unable to load the reply", w, r, user, js) + return c.LocalErrorJSQ("Unable to load the reply", w, r, user, js) } // Handle the file attachments @@ -89,26 +89,26 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) var maxPollOptions = 10 var pollInputItems = make(map[int]string) for key, values := range r.Form { - //common.DebugDetail("key: ", key) - //common.DebugDetailf("values: %+v\n", values) + //c.DebugDetail("key: ", key) + //c.DebugDetailf("values: %+v\n", values) for _, value := range values { if strings.HasPrefix(key, "pollinputitem[") { halves := strings.Split(key, "[") if len(halves) != 2 { - return common.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js) + return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js) } halves[1] = strings.TrimSuffix(halves[1], "]") index, err := strconv.Atoi(halves[1]) if err != nil { - return common.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js) + return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js) } // If there are duplicates, then something has gone horribly wrong, so let's ignore them, this'll likely happen during an attack _, exists := pollInputItems[index] // TODO: Should we use SanitiseBody instead to keep the newlines? - if !exists && len(common.SanitiseSingleLine(value)) != 0 { - pollInputItems[index] = common.SanitiseSingleLine(value) + if !exists && len(c.SanitiseSingleLine(value)) != 0 { + pollInputItems[index] = c.SanitiseSingleLine(value) if len(pollInputItems) >= maxPollOptions { break } @@ -124,40 +124,40 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) } pollType := 0 // Basic single choice - _, err := common.Polls.Create(reply, pollType, seqPollInputItems) + _, err := c.Polls.Create(reply, pollType, seqPollInputItems) if err != nil { - return common.LocalErrorJSQ("Failed to add poll to reply", w, r, user, js) // TODO: Might need to be an internal error as it could leave phantom polls? + return c.LocalErrorJSQ("Failed to add poll to reply", w, r, user, js) // TODO: Might need to be an internal error as it could leave phantom polls? } } - err = common.Forums.UpdateLastTopic(tid, user.ID, topic.ParentID) + err = c.Forums.UpdateLastTopic(tid, user.ID, topic.ParentID) if err != nil && err != sql.ErrNoRows { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - common.AddActivityAndNotifyAll(user.ID, topic.CreatedBy, "reply", "topic", tid) + c.AddActivityAndNotifyAll(user.ID, topic.CreatedBy, "reply", "topic", tid) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - wcount := common.WordCount(content) + wcount := c.WordCount(content) err = user.IncreasePostStats(wcount, false) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - nTopic, err := common.Topics.Get(tid) + nTopic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("Couldn't find the parent topic", w, r, js) + return c.PreErrorJSQ("Couldn't find the parent topic", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } - page := common.LastPage(nTopic.PostCount, common.Config.ItemsPerPage) + page := c.LastPage(nTopic.PostCount, c.Config.ItemsPerPage) rows, err := replyStmts.createReplyPaging.Query(reply.ID, topic.ID) if err != nil && err != sql.ErrNoRows { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } defer rows.Close() @@ -166,16 +166,16 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) var rid int err := rows.Scan(&rid) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } rids = append(rids, rid) } err = rows.Err() if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } if len(rids) == 0 { - return common.NotFoundJSQ(w, r, nil, js) + return c.NotFoundJSQ(w, r, nil, js) } if page > 1 { @@ -185,7 +185,7 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) } else if len(rids) == 2 && rids[1] == reply.ID { offset = 2 } - page = common.LastPage(nTopic.PostCount-(len(rids)+offset), common.Config.ItemsPerPage) + page = c.LastPage(nTopic.PostCount-(len(rids)+offset), c.Config.ItemsPerPage) } counters.PostCounter.Bump() @@ -196,9 +196,9 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) prid, _ := strconv.Atoi(r.FormValue("prid")) if js && (prid == 0 || rids[0] == prid) { - outBytes, err := json.Marshal(JsonReply{common.ParseMessage(reply.Content, topic.ParentID, "forums")}) + outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums")}) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } w.Write(outBytes) } else { @@ -213,52 +213,52 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User) // TODO: Disable stat updates in posts handled by plugin_guilds // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes -func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { js := (r.PostFormValue("js") == "1") rid, err := strconv.Atoi(srid) if err != nil { - return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js) + return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The target reply doesn't exist.", w, r, js) + return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } topic, err := reply.Topic() if err == sql.ErrNoRows { - return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, js) + return c.PreErrorJSQ("The parent topic doesn't exist.", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditReply { - return common.NoPermissionsJSQ(w, r, user, js) + return c.NoPermissionsJSQ(w, r, user, js) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJSQ(w, r, user, js) + return c.NoPermissionsJSQ(w, r, user, js) } err = reply.SetPost(r.PostFormValue("edit_item")) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, js) + return c.PreErrorJSQ("The parent topic doesn't exist.", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } // TODO: Avoid the load to get this faster? - reply, err = common.Rstore.Get(rid) + reply, err = c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The updated reply doesn't exist.", w, r, js) + return c.PreErrorJSQ("The updated reply doesn't exist.", w, r, js) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } skip, rerr := lite.Hooks.VhookSkippable("action_end_edit_reply", reply.ID, &user) @@ -269,9 +269,9 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, s if !js { http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther) } else { - outBytes, err := json.Marshal(JsonReply{common.ParseMessage(reply.Content, topic.ParentID, "forums")}) + outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums")}) if err != nil { - return common.InternalErrorJSQ(err, w, r, js) + return c.InternalErrorJSQ(err, w, r, js) } w.Write(outBytes) } @@ -281,39 +281,39 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, s // TODO: Refactor this // TODO: Disable stat updates in posts handled by plugin_guilds -func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { isJs := (r.PostFormValue("isJs") == "1") rid, err := strconv.Atoi(srid) if err != nil { - return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) + return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - topic, err := common.Topics.Get(reply.ParentID) + topic, err := c.Topics.Get(reply.ParentID) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.DeleteReply { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } err = reply.Delete() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } skip, rerr := lite.Hooks.VhookSkippable("action_end_delete_reply", reply.ID, &user) @@ -321,7 +321,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, return rerr } - //log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID) + //log.Printf("Reply #%d was deleted by c.User #%d", rid, user.ID) if !isJs { http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther) } else { @@ -329,20 +329,20 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, } // ? - What happens if an error fires after a redirect...? - replyCreator, err := common.Users.Get(reply.CreatedBy) + replyCreator, err := c.Users.Get(reply.CreatedBy) if err == nil { - wcount := common.WordCount(reply.Content) + wcount := c.WordCount(reply.Content) err = replyCreator.DecreasePostStats(wcount, false) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } } else if err != sql.ErrNoRows { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - err = common.ModLogs.Create("delete", reply.ParentID, "reply", user.LastIP, user.ID) + err = c.ModLogs.Create("delete", reply.ParentID, "reply", user.LastIP, user.ID) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } return nil } @@ -350,33 +350,33 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, // TODO: Avoid uploading this again if the attachment already exists? They'll resolve to the same hash either way, but we could save on some IO / bandwidth here // TODO: Enforce the max request limit on all of this topic's attachments // TODO: Test this route -func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { rid, err := strconv.Atoi(srid) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJS("You can't attach to something which doesn't exist!", w, r) + return c.PreErrorJS("You can't attach to something which doesn't exist!", w, r) } else if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } - topic, err := common.Topics.Get(reply.ParentID) + topic, err := c.Topics.Get(reply.ParentID) if err != nil { - return common.NotFoundJS(w, r) + return c.NotFoundJS(w, r) } - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditReply || !user.Perms.UploadFiles { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } // Handle the file attachments @@ -386,7 +386,7 @@ func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user common. return rerr } if len(pathMap) == 0 { - return common.InternalErrorJS(errors.New("no paths for attachment add"), w, r) + return c.InternalErrorJS(errors.New("no paths for attachment add"), w, r) } skip, rerr := lite.Hooks.VhookSkippable("action_end_add_attach_to_reply", reply.ID, &user) @@ -407,43 +407,43 @@ func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user common. } // TODO: Reduce the amount of duplication between this and RemoveAttachFromTopicSubmit -func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { rid, err := strconv.Atoi(srid) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJS("You can't attach from something which doesn't exist!", w, r) + return c.PreErrorJS("You can't attach from something which doesn't exist!", w, r) } else if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } - topic, err := common.Topics.Get(reply.ParentID) + topic, err := c.Topics.Get(reply.ParentID) if err != nil { - return common.NotFoundJS(w, r) + return c.NotFoundJS(w, r) } - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditReply { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } saids := strings.Split(r.PostFormValue("aids"), ",") if len(saids) == 0 { - return common.LocalErrorJS("No aids provided", w, r) + return c.LocalErrorJS("No aids provided", w, r) } for _, said := range saids { aid, err := strconv.Atoi(said) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } rerr := deleteAttachment(w, r, user, aid, true) if rerr != nil { @@ -462,35 +462,35 @@ func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user co } // TODO: Move the profile reply routes to their own file? -func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { if !user.Perms.ViewTopic || !user.Perms.CreateReply { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } uid, err := strconv.Atoi(r.PostFormValue("uid")) if err != nil { - return common.LocalError("Invalid UID", w, r, user) + return c.LocalError("Invalid UID", w, r, user) } - profileOwner, err := common.Users.Get(uid) + profileOwner, err := c.Users.Get(uid) if err == sql.ErrNoRows { - return common.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) + return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - content := common.PreparseMessage(r.PostFormValue("reply-content")) + content := c.PreparseMessage(r.PostFormValue("reply-content")) // TODO: Fully parse the post and store it in the parsed column - _, err = common.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP) + _, err = c.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // ! Be careful about leaking per-route permission state with &user - alert := common.Alert{0, user.ID, profileOwner.ID, "reply", "user", profileOwner.ID, &user} - err = common.AddActivityAndNotifyTarget(alert) + alert := c.Alert{0, user.ID, profileOwner.ID, "reply", "user", profileOwner.ID, &user} + err = c.AddActivityAndNotifyTarget(alert) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } counters.PostCounter.Bump() @@ -498,34 +498,34 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user commo return nil } -func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { isJs := (r.PostFormValue("js") == "1") rid, err := strconv.Atoi(srid) if err != nil { - return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) + return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) } - reply, err := common.Prstore.Get(rid) + reply, err := c.Prstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - creator, err := common.Users.Get(reply.CreatedBy) + creator, err := c.Users.Get(reply.CreatedBy) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // ? Does the admin understand that this group perm affects this? if user.ID != creator.ID && !user.Perms.EditReply { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } err = reply.SetBody(r.PostFormValue("edit_item")) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } if !isJs { @@ -536,35 +536,35 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common. return nil } -func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { isJs := (r.PostFormValue("isJs") == "1") rid, err := strconv.Atoi(srid) if err != nil { - return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) + return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs) } - reply, err := common.Prstore.Get(rid) + reply, err := c.Prstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - creator, err := common.Users.Get(reply.CreatedBy) + creator, err := c.Users.Get(reply.CreatedBy) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } if user.ID != creator.ID && !user.Perms.DeleteReply { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } err = reply.Delete() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - //log.Printf("The profile post '%d' was deleted by common.User #%d", reply.ID, user.ID) + //log.Printf("The profile post '%d' was deleted by c.User #%d", reply.ID, user.ID) if !isJs { //http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther) @@ -574,59 +574,59 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user commo return nil } -func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { +func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { isJs := (r.PostFormValue("isJs") == "1") rid, err := strconv.Atoi(srid) if err != nil { - return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) + return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) } - reply, err := common.Rstore.Get(rid) + reply, err := c.Rstore.Get(rid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("You can't like something which doesn't exist!", w, r, isJs) + return c.PreErrorJSQ("You can't like something which doesn't exist!", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - topic, err := common.Topics.Get(reply.ParentID) + topic, err := c.Topics.Get(reply.ParentID) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } if reply.CreatedBy == user.ID { - return common.LocalErrorJSQ("You can't like your own replies", w, r, user, isJs) + return c.LocalErrorJSQ("You can't like your own replies", w, r, user, isJs) } - _, err = common.Users.Get(reply.CreatedBy) + _, err = c.Users.Get(reply.CreatedBy) if err != nil && err != sql.ErrNoRows { - return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) + return c.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } err = reply.Like(user.ID) - if err == common.ErrAlreadyLiked { - return common.LocalErrorJSQ("You've already liked this!", w, r, user, isJs) + if err == c.ErrAlreadyLiked { + return c.LocalErrorJSQ("You've already liked this!", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // ! Be careful about leaking per-route permission state with &user - alert := common.Alert{0, user.ID, reply.CreatedBy, "like", "post", rid, &user} - err = common.AddActivityAndNotifyTarget(alert) + alert := c.Alert{0, user.ID, reply.CreatedBy, "like", "post", rid, &user} + err = c.AddActivityAndNotifyTarget(alert) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } skip, rerr := lite.Hooks.VhookSkippable("action_end_like_reply", reply.ID, &user) diff --git a/routes/reports.go b/routes/reports.go index aed09c6c..f2a87793 100644 --- a/routes/reports.go +++ b/routes/reports.go @@ -5,12 +5,12 @@ import ( "net/http" "strconv" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/counters" ) -func ReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { - headerLite, ferr := common.SimpleUserCheck(w, r, &user) +func ReportSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError { + headerLite, ferr := c.SimpleUserCheck(w, r, &user) if ferr != nil { return ferr } @@ -18,51 +18,51 @@ func ReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, site itemID, err := strconv.Atoi(sitemID) if err != nil { - return common.LocalError("Bad ID", w, r, user) + return c.LocalError("Bad ID", w, r, user) } itemType := r.FormValue("type") // TODO: Localise these titles and bodies var title, content string if itemType == "reply" { - reply, err := common.Rstore.Get(itemID) + reply, err := c.Rstore.Get(itemID) if err == sql.ErrNoRows { - return common.LocalError("We were unable to find the reported post", w, r, user) + return c.LocalError("We were unable to find the reported post", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - topic, err := common.Topics.Get(reply.ParentID) + topic, err := c.Topics.Get(reply.ParentID) if err == sql.ErrNoRows { - return common.LocalError("We weren't able to find the topic the reported post is supposed to be in", w, r, user) + return c.LocalError("We weren't able to find the topic the reported post is supposed to be in", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } title = "Reply: " + topic.Title content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(itemID) } else if itemType == "user-reply" { - userReply, err := common.Prstore.Get(itemID) + userReply, err := c.Prstore.Get(itemID) if err == sql.ErrNoRows { - return common.LocalError("We weren't able to find the reported post", w, r, user) + return c.LocalError("We weren't able to find the reported post", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - profileOwner, err := common.Users.Get(userReply.ParentID) + profileOwner, err := c.Users.Get(userReply.ParentID) if err == sql.ErrNoRows { - return common.LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user) + return c.LocalError("We weren't able to find the profile the reported post is supposed to be on", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } title = "Profile: " + profileOwner.Name content = userReply.Content + "\n\nOriginal Post: @" + strconv.Itoa(userReply.ParentID) } else if itemType == "topic" { - topic, err := common.Topics.Get(itemID) + topic, err := c.Topics.Get(itemID) if err == sql.ErrNoRows { - return common.NotFound(w, r, nil) + return c.NotFound(w, r, nil) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } title = "Topic: " + topic.Title content = topic.Content + "\n\nOriginal Post: #tid-" + strconv.Itoa(itemID) @@ -73,13 +73,13 @@ func ReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, site } // Don't try to guess the type - return common.LocalError("Unknown type", w, r, user) + return c.LocalError("Unknown type", w, r, user) } // TODO: Repost attachments in the reports forum, so that the mods can see them - _, err = common.Reports.Create(title, content, &user, itemType, itemID) - if err == common.ErrAlreadyReported { - return common.LocalError("Someone has already reported this!", w, r, user) + _, err = c.Reports.Create(title, content, &user, itemType, itemID) + if err == c.ErrAlreadyReported { + return c.LocalError("Someone has already reported this!", w, r, user) } counters.PostCounter.Bump() diff --git a/routes/topic.go b/routes/topic.go index 43d17238..0dfe4821 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -14,7 +14,7 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" @@ -30,7 +30,7 @@ var topicStmts TopicStmts // TODO: Move these DbInits into a TopicList abstraction func init() { - common.DbInits.Add(func(acc *qgen.Accumulator) error { + c.DbInits.Add(func(acc *qgen.Accumulator) error { topicStmts = TopicStmts{ getReplies: acc.SimpleLeftJoin("replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.attachCount, replies.actionType", "replies.createdBy = users.uid", "replies.tid = ?", "replies.rid ASC", "?,?"), getLikedTopic: acc.Select("likes").Columns("targetItem").Where("sentBy = ? && targetItem = ? && targetType = 'topics'").Prepare(), @@ -41,33 +41,33 @@ func init() { }) } -func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header, urlBit string) common.RouteError { +func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, urlBit string) c.RouteError { page, _ := strconv.Atoi(r.FormValue("page")) _, tid, err := ParseSEOURL(urlBit) if err != nil { - return common.PreError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r) + return c.PreError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r) } // Get the topic... - topic, err := common.GetTopicUser(&user, tid) + topic, err := c.GetTopicUser(&user, tid) if err == sql.ErrNoRows { - return common.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of header here? This is likely to be an extremely common NotFound + return c.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of header here? This is likely to be an extremely common NotFound } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - ferr := common.ForumUserCheck(header, w, r, &user, topic.ParentID) + ferr := c.ForumUserCheck(header, w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } header.Title = topic.Title - header.Path = common.BuildTopicURL(common.NameToSlug(topic.Title), topic.ID) + header.Path = c.BuildTopicURL(c.NameToSlug(topic.Title), topic.ID) // TODO: Cache ContentHTML when possible? - topic.ContentHTML = common.ParseMessage(topic.Content, topic.ParentID, "forums") + topic.ContentHTML = c.ParseMessage(topic.Content, topic.ParentID, "forums") topic.ContentLines = strings.Count(topic.Content, "\n") header.OGDesc = topic.Content @@ -75,27 +75,27 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header header.OGDesc = header.OGDesc[:197] + "..." } - postGroup, err := common.Groups.Get(topic.Group) + postGroup, err := c.Groups.Get(topic.Group) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } topic.Tag = postGroup.Tag if postGroup.IsMod { - topic.ClassName = common.Config.StaffCSS + topic.ClassName = c.Config.StaffCSS } - forum, err := common.Forums.Get(topic.ParentID) + forum, err := c.Forums.Get(topic.ParentID) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - var poll common.Poll + var poll c.Poll if topic.Poll != 0 { - pPoll, err := common.Polls.Get(topic.Poll) + pPoll, err := c.Polls.Get(topic.Poll) if err != nil { log.Print("Couldn't find the attached poll for topic " + strconv.Itoa(topic.ID)) - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } poll = pPoll.Copy() header.AddSheet("chartist/chartist.min.css") @@ -108,23 +108,23 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header if err == nil { topic.Liked = true } else if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } if topic.AttachCount > 0 { - attachs, err := common.Attachments.MiniGetList("topics", topic.ID) + attachs, err := c.Attachments.MiniGetList("topics", topic.ID) if err != nil { // TODO: We might want to be a little permissive here in-case of a desync? - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } topic.Attachments = attachs } // Calculate the offset - offset, page, lastPage := common.PageOffset(topic.PostCount, page, common.Config.ItemsPerPage) - pageList := common.Paginate(topic.PostCount, common.Config.ItemsPerPage, 5) - tpage := common.TopicPage{header, []common.ReplyUser{}, topic, forum, poll, common.Paginator{pageList, page, lastPage}} + offset, page, lastPage := c.PageOffset(topic.PostCount, page, c.Config.ItemsPerPage) + pageList := c.Paginate(topic.PostCount, c.Config.ItemsPerPage, 5) + tpage := c.TopicPage{header, []c.ReplyUser{}, topic, forum, poll, c.Paginator{pageList, page, lastPage}} // Get the replies if we have any... if topic.PostCount > 0 { @@ -144,25 +144,25 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header } var attachQueryList = []int{} - rows, err := topicStmts.getReplies.Query(topic.ID, offset, common.Config.ItemsPerPage) + rows, err := topicStmts.getReplies.Query(topic.ID, offset, c.Config.ItemsPerPage) if err == sql.ErrNoRows { - return common.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user) + return c.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user) } else if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } defer rows.Close() // TODO: Factor the user fields out and embed a user struct instead - replyItem := common.ReplyUser{ClassName: ""} + replyItem := c.ReplyUser{ClassName: ""} for rows.Next() { err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress, &replyItem.LikeCount, &replyItem.AttachCount, &replyItem.ActionType) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - replyItem.UserLink = common.BuildProfileURL(common.NameToSlug(replyItem.CreatedByName), replyItem.CreatedBy) + replyItem.UserLink = c.BuildProfileURL(c.NameToSlug(replyItem.CreatedByName), replyItem.CreatedBy) replyItem.ParentID = topic.ID - replyItem.ContentHtml = common.ParseMessage(replyItem.Content, topic.ParentID, "forums") + replyItem.ContentHtml = c.ParseMessage(replyItem.Content, topic.ParentID, "forums") replyItem.ContentLines = strings.Count(replyItem.Content, "\n") if replyItem.ID == pFrag { @@ -172,19 +172,19 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header } } - postGroup, err = common.Groups.Get(replyItem.Group) + postGroup, err = c.Groups.Get(replyItem.Group) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } if postGroup.IsMod { - replyItem.ClassName = common.Config.StaffCSS + replyItem.ClassName = c.Config.StaffCSS } else { replyItem.ClassName = "" } - // TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the common.UserStore initialise this? - replyItem.Avatar, replyItem.MicroAvatar = common.BuildAvatar(replyItem.CreatedBy, replyItem.Avatar) + // TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the c.UserStore initialise this? + replyItem.Avatar, replyItem.MicroAvatar = c.BuildAvatar(replyItem.CreatedBy, replyItem.Avatar) replyItem.Tag = postGroup.Tag // We really shouldn't have inline HTML, we should do something about this... @@ -207,7 +207,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header case "move": if len(aarr) == 2 { fid, _ := strconv.Atoi(aarr[1]) - forum, err := common.Forums.Get(fid) + forum, err := c.Forums.Get(fid) if err == nil { replyItem.ActionType = phrases.GetTmplPhrasef("topic.action_topic_move_dest", forum.Link, forum.Name, replyItem.UserLink, replyItem.CreatedByName) } else { @@ -243,7 +243,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // TODO: Add a config setting to disable the liked query for a burst of extra speed @@ -251,7 +251,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header // TODO: Abstract this rows, err := qgen.NewAcc().Select("likes").Columns("targetItem").Where("sentBy = ? AND targetType = 'replies'").In("targetItem", likedQueryList[1:]).Query(user.ID) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } defer rows.Close() @@ -259,21 +259,21 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header var likeRid int err := rows.Scan(&likeRid) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } tpage.ItemList[likedMap[likeRid]].Liked = true } err = rows.Err() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } if user.Perms.EditReply && len(attachQueryList) > 0 { //log.Printf("attachQueryList: %+v\n", attachQueryList) - amap, err := common.Attachments.BulkMiniGetList("replies", attachQueryList) + amap, err := c.Attachments.BulkMiniGetList("replies", attachQueryList) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } //log.Printf("amap: %+v\n", amap) //log.Printf("attachMap: %+v\n", attachMap) @@ -299,25 +299,25 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header // TODO: Avoid uploading this again if the attachment already exists? They'll resolve to the same hash either way, but we could save on some IO / bandwidth here // TODO: Enforce the max request limit on all of this topic's attachments // TODO: Test this route -func AddAttachToTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func AddAttachToTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { tid, err := strconv.Atoi(stid) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err != nil { - return common.NotFoundJS(w, r) + return c.NotFoundJS(w, r) } - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditTopic || !user.Perms.UploadFiles { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } // Handle the file attachments @@ -327,7 +327,7 @@ func AddAttachToTopicSubmit(w http.ResponseWriter, r *http.Request, user common. return rerr } if len(pathMap) == 0 { - return common.InternalErrorJS(errors.New("no paths for attachment add"), w, r) + return c.InternalErrorJS(errors.New("no paths for attachment add"), w, r) } var elemStr string @@ -342,31 +342,31 @@ func AddAttachToTopicSubmit(w http.ResponseWriter, r *http.Request, user common. return nil } -func RemoveAttachFromTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func RemoveAttachFromTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { tid, err := strconv.Atoi(stid) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err != nil { - return common.NotFoundJS(w, r) + return c.NotFoundJS(w, r) } - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } for _, said := range strings.Split(r.PostFormValue("aids"), ",") { aid, err := strconv.Atoi(said) if err != nil { - return common.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.LocalErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } rerr := deleteAttachment(w, r, user, aid, true) if rerr != nil { @@ -385,25 +385,25 @@ func RemoveAttachFromTopicSubmit(w http.ResponseWriter, r *http.Request, user co // ? - Log username changes and put restrictions on this? // TODO: Test this // TODO: Revamp this route -func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header, sfid string) common.RouteError { +func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, sfid string) c.RouteError { var fid int var err error if sfid != "" { fid, err = strconv.Atoi(sfid) if err != nil { - return common.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) + return c.LocalError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, user) } } if fid == 0 { - fid = common.Config.DefaultForum + fid = c.Config.DefaultForum } - ferr := common.ForumUserCheck(header, w, r, &user, fid) + ferr := c.ForumUserCheck(header, w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } // TODO: Add a phrase for this header.Title = phrases.GetTitlePhrase("create_topic") @@ -415,19 +415,19 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, heade header.Hooks.VhookNoRet("topic_create_pre_loop", w, r, fid, &header, &user, &strictmode) // TODO: Re-add support for plugin_guilds - var forumList []common.Forum + var forumList []c.Forum var canSee []int if user.IsSuperAdmin { - canSee, err = common.Forums.GetAllVisibleIDs() + canSee, err = c.Forums.GetAllVisibleIDs() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } else { - group, err := common.Groups.Get(user.Group) + group, err := c.Groups.Get(user.Group) if err != nil { // TODO: Refactor this - common.LocalError("Something weird happened behind the scenes", w, r, user) - log.Printf("Group #%d doesn't exist, but it's set on common.User #%d", user.Group, user.ID) + c.LocalError("Something weird happened behind the scenes", w, r, user) + log.Printf("Group #%d doesn't exist, but it's set on c.User #%d", user.Group, user.ID) return nil } canSee = group.CanSee @@ -441,7 +441,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, heade } // Do a bulk forum fetch, just in case it's the SqlForumStore? - forum := common.Forums.DirtyGet(ffid) + forum := c.Forums.DirtyGet(ffid) if forum.Name != "" && forum.Active { fcopy := forum.Copy() // TODO: Abstract this @@ -452,46 +452,46 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, heade } } - ctpage := common.CreateTopicPage{header, forumList, fid} + ctpage := c.CreateTopicPage{header, forumList, fid} return renderTemplate("create_topic", w, r, header, ctpage) } -func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { fid, err := strconv.Atoi(r.PostFormValue("topic-board")) if err != nil { - return common.LocalError("The provided ForumID is not a valid number.", w, r, user) + return c.LocalError("The provided ForumID is not a valid number.", w, r, user) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, fid) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CreateTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } - topicName := common.SanitiseSingleLine(r.PostFormValue("topic-name")) - content := common.PreparseMessage(r.PostFormValue("topic-content")) + topicName := c.SanitiseSingleLine(r.PostFormValue("topic-name")) + content := c.PreparseMessage(r.PostFormValue("topic-content")) // TODO: Fully parse the post and store it in the parsed column - tid, err := common.Topics.Create(fid, topicName, content, user.ID, user.LastIP) + tid, err := c.Topics.Create(fid, topicName, content, user.ID, user.LastIP) if err != nil { switch err { - case common.ErrNoRows: - return common.LocalError("Something went wrong, perhaps the forum got deleted?", w, r, user) - case common.ErrNoTitle: - return common.LocalError("This topic doesn't have a title", w, r, user) - case common.ErrLongTitle: - return common.LocalError("The length of the title is too long, max: "+strconv.Itoa(common.Config.MaxTopicTitleLength), w, r, user) - case common.ErrNoBody: - return common.LocalError("This topic doesn't have a body", w, r, user) + case c.ErrNoRows: + return c.LocalError("Something went wrong, perhaps the forum got deleted?", w, r, user) + case c.ErrNoTitle: + return c.LocalError("This topic doesn't have a title", w, r, user) + case c.ErrLongTitle: + return c.LocalError("The length of the title is too long, max: "+strconv.Itoa(c.Config.MaxTopicTitleLength), w, r, user) + case c.ErrNoBody: + return c.LocalError("This topic doesn't have a body", w, r, user) } - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err != nil { - return common.LocalError("Unable to load the topic", w, r, user) + return c.LocalError("Unable to load the topic", w, r, user) } if r.PostFormValue("has_poll") == "1" { var maxPollOptions = 10 @@ -501,20 +501,20 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) if strings.HasPrefix(key, "pollinputitem[") { halves := strings.Split(key, "[") if len(halves) != 2 { - return common.LocalError("Malformed pollinputitem", w, r, user) + return c.LocalError("Malformed pollinputitem", w, r, user) } halves[1] = strings.TrimSuffix(halves[1], "]") index, err := strconv.Atoi(halves[1]) if err != nil { - return common.LocalError("Malformed pollinputitem", w, r, user) + return c.LocalError("Malformed pollinputitem", w, r, user) } // If there are duplicates, then something has gone horribly wrong, so let's ignore them, this'll likely happen during an attack _, exists := pollInputItems[index] // TODO: Should we use SanitiseBody instead to keep the newlines? - if !exists && len(common.SanitiseSingleLine(value)) != 0 { - pollInputItems[index] = common.SanitiseSingleLine(value) + if !exists && len(c.SanitiseSingleLine(value)) != 0 { + pollInputItems[index] = c.SanitiseSingleLine(value) if len(pollInputItems) >= maxPollOptions { break } @@ -530,20 +530,20 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) } pollType := 0 // Basic single choice - _, err := common.Polls.Create(topic, pollType, seqPollInputItems) + _, err := c.Polls.Create(topic, pollType, seqPollInputItems) if err != nil { - return common.LocalError("Failed to add poll to topic", w, r, user) // TODO: Might need to be an internal error as it could leave phantom polls? + return c.LocalError("Failed to add poll to topic", w, r, user) // TODO: Might need to be an internal error as it could leave phantom polls? } } - err = common.Subscriptions.Add(user.ID, tid, "topic") + err = c.Subscriptions.Add(user.ID, tid, "topic") if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } - err = user.IncreasePostStats(common.WordCount(content), true) + err = user.IncreasePostStats(c.WordCount(content), true) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // Handle the file attachments @@ -565,47 +565,47 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) return nil } -func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user common.User, dir string) (filenames []string, rerr common.RouteError) { +func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user c.User, dir string) (filenames []string, rerr c.RouteError) { files, ok := r.MultipartForm.File["upload_files"] if !ok { return nil, nil } if len(files) > 5 { - return nil, common.LocalError("You can't attach more than five files", w, r, user) + return nil, c.LocalError("You can't attach more than five files", w, r, user) } for _, file := range files { if file.Filename == "" { continue } - //common.DebugLog("file.Filename ", file.Filename) + //c.DebugLog("file.Filename ", file.Filename) extarr := strings.Split(file.Filename, ".") if len(extarr) < 2 { - return nil, common.LocalError("Bad file", w, r, user) + return nil, c.LocalError("Bad file", w, r, user) } ext := extarr[len(extarr)-1] // TODO: Can we do this without a regex? reg, err := regexp.Compile("[^A-Za-z0-9]+") if err != nil { - return nil, common.LocalError("Bad file extension", w, r, user) + return nil, c.LocalError("Bad file extension", w, r, user) } ext = strings.ToLower(reg.ReplaceAllString(ext, "")) - if !common.AllowedFileExts.Contains(ext) { - return nil, common.LocalError("You're not allowed to upload files with this extension", w, r, user) + if !c.AllowedFileExts.Contains(ext) { + return nil, c.LocalError("You're not allowed to upload files with this extension", w, r, user) } infile, err := file.Open() if err != nil { - return nil, common.LocalError("Upload failed", w, r, user) + return nil, c.LocalError("Upload failed", w, r, user) } defer infile.Close() hasher := sha256.New() _, err = io.Copy(hasher, infile) if err != nil { - return nil, common.LocalError("Upload failed [Hashing Failed]", w, r, user) + return nil, c.LocalError("Upload failed [Hashing Failed]", w, r, user) } infile.Close() @@ -613,19 +613,19 @@ func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user common.Use filename := checksum + "." + ext outfile, err := os.Create(dir + filename) if err != nil { - return nil, common.LocalError("Upload failed [File Creation Failed]", w, r, user) + return nil, c.LocalError("Upload failed [File Creation Failed]", w, r, user) } defer outfile.Close() infile, err = file.Open() if err != nil { - return nil, common.LocalError("Upload failed", w, r, user) + return nil, c.LocalError("Upload failed", w, r, user) } defer infile.Close() _, err = io.Copy(outfile, infile) if err != nil { - return nil, common.LocalError("Upload failed [Copy Failed]", w, r, user) + return nil, c.LocalError("Upload failed [Copy Failed]", w, r, user) } filenames = append(filenames, filename) @@ -636,57 +636,57 @@ func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user common.Use // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes // TODO: Disable stat updates in posts handled by plugin_guilds -func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { isJs := (r.PostFormValue("js") == "1") tid, err := strconv.Atoi(stid) if err != nil { - return common.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, isJs) + return c.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, isJs) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The topic you tried to edit doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.EditTopic { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } if topic.IsClosed && !user.Perms.CloseTopic { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } err = topic.Update(r.PostFormValue("topic_name"), r.PostFormValue("topic_content")) // TODO: Avoid duplicating this across this route and the topic creation route if err != nil { switch err { - case common.ErrNoTitle: - return common.LocalErrorJSQ("This topic doesn't have a title", w, r, user, isJs) - case common.ErrLongTitle: - return common.LocalErrorJSQ("The length of the title is too long, max: "+strconv.Itoa(common.Config.MaxTopicTitleLength), w, r, user, isJs) - case common.ErrNoBody: - return common.LocalErrorJSQ("This topic doesn't have a body", w, r, user, isJs) + case c.ErrNoTitle: + return c.LocalErrorJSQ("This topic doesn't have a title", w, r, user, isJs) + case c.ErrLongTitle: + return c.LocalErrorJSQ("The length of the title is too long, max: "+strconv.Itoa(c.Config.MaxTopicTitleLength), w, r, user, isJs) + case c.ErrNoBody: + return c.LocalErrorJSQ("This topic doesn't have a body", w, r, user, isJs) } - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - err = common.Forums.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) + err = c.Forums.UpdateLastTopic(topic.ID, user.ID, topic.ParentID) if err != nil && err != sql.ErrNoRows { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Avoid the load to get this faster? - topic, err = common.Topics.Get(topic.ID) + topic, err = c.Topics.Get(topic.ID) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The updated topic doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The updated topic doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } skip, rerr := lite.Hooks.VhookSkippable("action_end_edit_topic", topic.ID, &user) @@ -697,9 +697,9 @@ func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s if !isJs { http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) } else { - outBytes, err := json.Marshal(JsonReply{common.ParseMessage(topic.Content, topic.ParentID, "forums")}) + outBytes, err := json.Marshal(JsonReply{c.ParseMessage(topic.Content, topic.ParentID, "forums")}) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } w.Write(outBytes) } @@ -708,62 +708,62 @@ func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s // TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual // TODO: Disable stat updates in posts handled by plugin_guilds -func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { // TODO: Move this to some sort of middleware var tids []int var isJs = false - if common.ReqIsJson(r) { + if c.ReqIsJson(r) { if r.Body == nil { - return common.PreErrorJS("No request body", w, r) + return c.PreErrorJS("No request body", w, r) } err := json.NewDecoder(r.Body).Decode(&tids) if err != nil { - return common.PreErrorJS("We weren't able to parse your data", w, r) + return c.PreErrorJS("We weren't able to parse your data", w, r) } isJs = true } else { tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):]) if err != nil { - return common.PreError("The provided TopicID is not a valid number.", w, r) + return c.PreError("The provided TopicID is not a valid number.", w, r) } tids = append(tids, tid) } if len(tids) == 0 { - return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) + return c.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) } for _, tid := range tids { - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.DeleteTopic { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } // We might be able to handle this err better err = topic.Delete() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } - err = common.ModLogs.Create("delete", tid, "topic", user.LastIP, user.ID) + err = c.ModLogs.Create("delete", tid, "topic", user.LastIP, user.ID) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // ? - We might need to add soft-delete before we can do an action reply for this /*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID) if err != nil { - return common.InternalErrorJSQ(err,w,r,isJs) + return c.InternalErrorJSQ(err,w,r,isJs) }*/ // TODO: Do a bulk delete action hook? @@ -778,32 +778,32 @@ func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) return nil } -func StickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func StickTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { topic, lite,rerr := topicActionPre(stid, "pin", w, r, user) if rerr != nil { return rerr } if !user.Perms.ViewTopic || !user.Perms.PinTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } return topicActionPost(topic.Stick(), "stick", w, r, lite,topic, user) } -func topicActionPre(stid string, action string, w http.ResponseWriter, r *http.Request, user common.User) (*common.Topic, *common.HeaderLite, common.RouteError) { +func topicActionPre(stid string, action string, w http.ResponseWriter, r *http.Request, user c.User) (*c.Topic, *c.HeaderLite, c.RouteError) { tid, err := strconv.Atoi(stid) if err != nil { - return nil, nil,common.PreError(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return nil, nil,c.PreError(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return nil, nil,common.PreError("The topic you tried to "+action+" doesn't exist.", w, r) + return nil, nil,c.PreError("The topic you tried to "+action+" doesn't exist.", w, r) } else if err != nil { - return nil, nil,common.InternalError(err, w, r) + return nil, nil,c.InternalError(err, w, r) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return nil, nil,ferr } @@ -811,13 +811,13 @@ func topicActionPre(stid string, action string, w http.ResponseWriter, r *http.R return topic, lite, nil } -func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Request, lite *common.HeaderLite, topic *common.Topic, user common.User) common.RouteError { +func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Request, lite *c.HeaderLite, topic *c.Topic, user c.User) c.RouteError { if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } err = addTopicAction(action, topic, user) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } skip, rerr := lite.Hooks.VhookSkippable("action_end_"+action+"_topic", topic.ID, &user) if skip || rerr != nil { @@ -827,66 +827,66 @@ func topicActionPost(err error, action string, w http.ResponseWriter, r *http.Re return nil } -func UnstickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func UnstickTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { topic, lite, rerr := topicActionPre(stid, "unpin", w, r, user) if rerr != nil { return rerr } if !user.Perms.ViewTopic || !user.Perms.PinTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } return topicActionPost(topic.Unstick(), "unstick", w, r, lite,topic, user) } -func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { +func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { // TODO: Move this to some sort of middleware var tids []int var isJs = false - if common.ReqIsJson(r) { + if c.ReqIsJson(r) { if r.Body == nil { - return common.PreErrorJS("No request body", w, r) + return c.PreErrorJS("No request body", w, r) } err := json.NewDecoder(r.Body).Decode(&tids) if err != nil { - return common.PreErrorJS("We weren't able to parse your data", w, r) + return c.PreErrorJS("We weren't able to parse your data", w, r) } isJs = true } else { tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):]) if err != nil { - return common.PreError("The provided TopicID is not a valid number.", w, r) + return c.PreError("The provided TopicID is not a valid number.", w, r) } tids = append(tids, tid) } if len(tids) == 0 { - return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) + return c.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs) } for _, tid := range tids { - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.CloseTopic { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } err = topic.Lock() if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } err = addTopicAction("lock", topic, user) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Do a bulk lock action hook? @@ -902,71 +902,71 @@ func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) c return nil } -func UnlockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func UnlockTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { topic, lite,rerr := topicActionPre(stid, "unlock", w, r, user) if rerr != nil { return rerr } if !user.Perms.ViewTopic || !user.Perms.CloseTopic { - return common.NoPermissions(w, r, user) + return c.NoPermissions(w, r, user) } return topicActionPost(topic.Unlock(), "unlock", w, r, lite,topic, user) } // ! JS only route // TODO: Figure a way to get this route to work without JS -func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError { +func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid string) c.RouteError { fid, err := strconv.Atoi(sfid) if err != nil { - return common.PreErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) + return c.PreErrorJS(phrases.GetErrorPhrase("id_must_be_integer"), w, r) } // TODO: Move this to some sort of middleware var tids []int if r.Body == nil { - return common.PreErrorJS("No request body", w, r) + return c.PreErrorJS("No request body", w, r) } err = json.NewDecoder(r.Body).Decode(&tids) if err != nil { - return common.PreErrorJS("We weren't able to parse your data", w, r) + return c.PreErrorJS("We weren't able to parse your data", w, r) } if len(tids) == 0 { - return common.LocalErrorJS("You haven't provided any IDs", w, r) + return c.LocalErrorJS("You haven't provided any IDs", w, r) } for _, tid := range tids { - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJS("The topic you tried to move doesn't exist.", w, r) + return c.PreErrorJS("The topic you tried to move doesn't exist.", w, r) } else if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } // TODO: Add hooks to make use of headerLite - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + _, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.MoveTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } - lite, ferr := common.SimpleForumUserCheck(w, r, &user, fid) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.MoveTopic { - return common.NoPermissionsJS(w, r, user) + return c.NoPermissionsJS(w, r, user) } err = topic.MoveTo(fid) if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } // ? - Is there a better way of doing this? err = addTopicAction("move-"+strconv.Itoa(fid), topic, user) if err != nil { - return common.InternalErrorJS(err, w, r) + return c.InternalErrorJS(err, w, r) } // TODO: Do a bulk move action hook? @@ -982,8 +982,8 @@ func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s return nil } -func addTopicAction(action string, topic *common.Topic, user common.User) error { - err := common.ModLogs.Create(action, topic.ID, "topic", user.LastIP, user.ID) +func addTopicAction(action string, topic *c.Topic, user c.User) error { + err := c.ModLogs.Create(action, topic.ID, "topic", user.LastIP, user.ID) if err != nil { return err } @@ -991,52 +991,52 @@ func addTopicAction(action string, topic *common.Topic, user common.User) error } // TODO: Refactor this -func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { +func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { isJs := (r.PostFormValue("isJs") == "1") tid, err := strconv.Atoi(stid) if err != nil { - return common.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, isJs) + return c.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, isJs) } - topic, err := common.Topics.Get(tid) + topic, err := c.Topics.Get(tid) if err == sql.ErrNoRows { - return common.PreErrorJSQ("The requested topic doesn't exist.", w, r, isJs) + return c.PreErrorJSQ("The requested topic doesn't exist.", w, r, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // TODO: Add hooks to make use of headerLite - lite, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + lite, ferr := c.SimpleForumUserCheck(w, r, &user, topic.ParentID) if ferr != nil { return ferr } if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return common.NoPermissionsJSQ(w, r, user, isJs) + return c.NoPermissionsJSQ(w, r, user, isJs) } if topic.CreatedBy == user.ID { - return common.LocalErrorJSQ("You can't like your own topics", w, r, user, isJs) + return c.LocalErrorJSQ("You can't like your own topics", w, r, user, isJs) } - _, err = common.Users.Get(topic.CreatedBy) + _, err = c.Users.Get(topic.CreatedBy) if err != nil && err == sql.ErrNoRows { - return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) + return c.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } score := 1 err = topic.Like(score, user.ID) - if err == common.ErrAlreadyLiked { - return common.LocalErrorJSQ("You already liked this", w, r, user, isJs) + if err == c.ErrAlreadyLiked { + return c.LocalErrorJSQ("You already liked this", w, r, user, isJs) } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } // ! Be careful about leaking per-route permission state with &user - alert := common.Alert{0, user.ID, topic.CreatedBy, "like", "topic", tid, &user} - err = common.AddActivityAndNotifyTarget(alert) + alert := c.Alert{0, user.ID, topic.CreatedBy, "like", "topic", tid, &user} + err = c.AddActivityAndNotifyTarget(alert) if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) + return c.InternalErrorJSQ(err, w, r, isJs) } skip, rerr := lite.Hooks.VhookSkippable("action_end_like_topic", topic.ID, &user) diff --git a/routes/topic_list.go b/routes/topic_list.go index a5c5289c..a934530c 100644 --- a/routes/topic_list.go +++ b/routes/topic_list.go @@ -7,37 +7,37 @@ import ( "strconv" "strings" - "github.com/Azareal/Gosora/common" + c "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/phrases" ) -func wsTopicList(topicList []*common.TopicsRow, lastPage int) *common.WsTopicList { - wsTopicList := make([]*common.WsTopicsRow, len(topicList)) +func wsTopicList(topicList []*c.TopicsRow, lastPage int) *c.WsTopicList { + wsTopicList := make([]*c.WsTopicsRow, len(topicList)) for i, topicRow := range topicList { wsTopicList[i] = topicRow.WebSockets() } - return &common.WsTopicList{wsTopicList, lastPage} + return &c.WsTopicList{wsTopicList, lastPage} } -func TopicList(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func TopicList(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { return TopicListCommon(w, r, user, header, "lastupdated", "") } -func TopicListMostViewed(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header) common.RouteError { +func TopicListMostViewed(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { return TopicListCommon(w, r, user, header, "mostviewed", "most-viewed") } // TODO: Implement search -func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, header *common.Header, torder string, tsorder string) common.RouteError { +func TopicListCommon(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, torder string, tsorder string) c.RouteError { header.Title = phrases.GetTitlePhrase("topics") header.Zone = "topics" header.Path = "/topics/" header.MetaDesc = header.Settings["meta_desc"].(string) - group, err := common.Groups.Get(user.Group) + group, err := c.Groups.Get(user.Group) if err != nil { - log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) - return common.LocalError("Something weird happened", w, r, user) + log.Printf("Group #%d doesn't exist despite being used by c.User #%d", user.Group, user.ID) + return c.LocalError("Something weird happened", w, r, user) } // Get the current page @@ -48,14 +48,14 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h for _, sfid := range strings.Split(sfids, ",") { fid, err := strconv.Atoi(sfid) if err != nil { - return common.LocalError("Invalid fid", w, r, user) + return c.LocalError("Invalid fid", w, r, user) } fids = append(fids, fid) } if len(fids) == 1 { - forum, err := common.Forums.Get(fids[0]) + forum, err := c.Forums.Get(fids[0]) if err != nil { - return common.LocalError("Invalid fid forum", w, r, user) + return c.LocalError("Invalid fid forum", w, r, user) } header.Title = forum.Name header.ZoneID = forum.ID @@ -64,16 +64,16 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h // TODO: Allow multiple forums in searches // TODO: Simplify this block after initially landing search - var topicList []*common.TopicsRow - var forumList []common.Forum - var paginator common.Paginator + var topicList []*c.TopicsRow + var forumList []c.Forum + var paginator c.Paginator q := r.FormValue("q") - if q != "" && common.RepliesSearch != nil { + if q != "" && c.RepliesSearch != nil { var canSee []int if user.IsSuperAdmin { - canSee, err = common.Forums.GetAllVisibleIDs() + canSee, err = c.Forums.GetAllVisibleIDs() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } } else { canSee = group.CanSee @@ -91,7 +91,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h } for _, fid := range fids { if inSlice(canSee, fid) { - forum := common.Forums.DirtyGet(fid) + forum := c.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active && (forum.ParentType == "" || forum.ParentType == "forum") { // TODO: Add a hook here for plugin_guilds? cfids = append(cfids, fid) @@ -102,16 +102,16 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h cfids = canSee } - tids, err := common.RepliesSearch.Query(q, cfids) + tids, err := c.RepliesSearch.Query(q, cfids) if err != nil && err != sql.ErrNoRows { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } //fmt.Printf("tids %+v\n", tids) // TODO: Handle the case where there aren't any items... // TODO: Add a BulkGet method which returns a slice? - tMap, err := common.Topics.BulkGetMap(tids) + tMap, err := c.Topics.BulkGetMap(tids) if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } var reqUserList = make(map[int]bool) for _, topic := range tMap { @@ -131,21 +131,21 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h // TODO: What if a user is deleted via the Control Panel? //fmt.Printf("idSlice %+v\n", idSlice) - userList, err := common.Users.BulkGetMap(idSlice) + userList, err := c.Users.BulkGetMap(idSlice) if err != nil { return nil // TODO: Implement this! } // TODO: De-dupe this logic in common/topic_list.go? for _, topic := range topicList { - topic.Link = common.BuildTopicURL(common.NameToSlug(topic.Title), topic.ID) + topic.Link = c.BuildTopicURL(c.NameToSlug(topic.Title), topic.ID) // TODO: Pass forum to something like topic.Forum and use that instead of these two properties? Could be more flexible. - forum := common.Forums.DirtyGet(topic.ParentID) + forum := c.Forums.DirtyGet(topic.ParentID) topic.ForumName = forum.Name topic.ForumLink = forum.Link // TODO: Create a specialised function with a bit less overhead for getting the last page for a post count - _, _, lastPage := common.PageOffset(topic.PostCount, 1, common.Config.ItemsPerPage) + _, _, lastPage := c.PageOffset(topic.PostCount, 1, c.Config.ItemsPerPage) topic.LastPage = lastPage topic.Creator = userList[topic.CreatedBy] topic.LastUser = userList[topic.LastReplyBy] @@ -155,41 +155,41 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h if r.FormValue("js") == "1" { outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } w.Write(outBytes) return nil } header.Title = phrases.GetTitlePhrase("topics_search") - pi := common.TopicListPage{header, topicList, forumList, common.Config.DefaultForum, common.TopicListSort{torder, false}, paginator} + pi := c.TopicListPage{header, topicList, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, paginator} return renderTemplate("topics", w, r, header, pi) } // TODO: Pass a struct back rather than passing back so many variables if user.IsSuperAdmin { - topicList, forumList, paginator, err = common.TopicList.GetList(page, tsorder, fids) + topicList, forumList, paginator, err = c.TopicList.GetList(page, tsorder, fids) } else { - topicList, forumList, paginator, err = common.TopicList.GetListByGroup(group, page, tsorder, fids) + topicList, forumList, paginator, err = c.TopicList.GetListByGroup(group, page, tsorder, fids) } if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } // ! Need an inline error not a page level error if len(topicList) == 0 { - return common.NotFound(w, r, header) + return c.NotFound(w, r, header) } // TODO: Reduce the amount of boilerplate here if r.FormValue("js") == "1" { outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON() if err != nil { - return common.InternalError(err, w, r) + return c.InternalError(err, w, r) } w.Write(outBytes) return nil } - pi := common.TopicListPage{header, topicList, forumList, common.Config.DefaultForum, common.TopicListSort{torder, false}, paginator} + pi := c.TopicListPage{header, topicList, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, paginator} return renderTemplate("topics", w, r, header, pi) }