Shorten the common namespaces in some areas to reduce the amount of boilerplate.

This commit is contained in:
Azareal 2019-04-19 16:36:26 +10:00
parent 00e30460b5
commit 20a6a22e78
27 changed files with 1250 additions and 1250 deletions

View File

@ -10,25 +10,25 @@ import (
"os" "os"
"strconv" "strconv"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
"gopkg.in/olivere/elastic.v6" "gopkg.in/olivere/elastic.v6"
) )
func main() { func main() {
log.Print("Loading the configuration data") log.Print("Loading the configuration data")
err := common.LoadConfig() err := c.LoadConfig()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Processing configuration data") log.Print("Processing configuration data")
err = common.ProcessConfig() err = c.ProcessConfig()
if err != nil { if err != nil {
log.Fatal(err) 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") 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 { func prepMySQL() error {
return qgen.Builder.Init("mysql", map[string]string{ return qgen.Builder.Init("mysql", map[string]string{
"host": common.DbConfig.Host, "host": c.DbConfig.Host,
"port": common.DbConfig.Port, "port": c.DbConfig.Port,
"name": common.DbConfig.Dbname, "name": c.DbConfig.Dbname,
"username": common.DbConfig.Username, "username": c.DbConfig.Username,
"password": common.DbConfig.Password, "password": c.DbConfig.Password,
"collation": "utf8mb4_general_ci", "collation": "utf8mb4_general_ci",
}) })
} }

View File

@ -3,7 +3,7 @@ package counters
import ( import (
"database/sql" "database/sql"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -23,9 +23,9 @@ func NewDefaultAgentViewCounter(acc *qgen.Accumulator) (*DefaultAgentViewCounter
agentBuckets: agentBuckets, agentBuckets: agentBuckets,
insert: acc.Insert("viewchunks_agents").Columns("count, createdAt, browser").Fields("?,UTC_TIMESTAMP(),?").Prepare(), insert: acc.Insert("viewchunks_agents").Columns("count, createdAt, browser").Fields("?,UTC_TIMESTAMP(),?").Prepare(),
} }
common.AddScheduledFifteenMinuteTask(counter.Tick) c.AddScheduledFifteenMinuteTask(counter.Tick)
//common.AddScheduledSecondTask(counter.Tick) //c.AddScheduledSecondTask(counter.Tick)
common.AddShutdownTask(counter.Tick) c.AddShutdownTask(counter.Tick)
return counter, acc.FirstError() return counter, acc.FirstError()
} }
@ -50,14 +50,14 @@ func (counter *DefaultAgentViewCounter) insertChunk(count int, agent int) error
return nil return nil
} }
var agentName = reverseAgentMapEnum[agent] 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) _, err := counter.insert.Exec(count, agentName)
return err return err
} }
func (counter *DefaultAgentViewCounter) Bump(agent int) { func (counter *DefaultAgentViewCounter) Bump(agent int) {
// TODO: Test this check // 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 { if len(counter.agentBuckets) <= agent || agent < 0 {
return return
} }

View File

@ -4,7 +4,7 @@ import (
"database/sql" "database/sql"
"sync" "sync"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -28,9 +28,9 @@ func NewDefaultForumViewCounter() (*DefaultForumViewCounter, error) {
evenMap: make(map[int]*RWMutexCounterBucket), evenMap: make(map[int]*RWMutexCounterBucket),
insert: acc.Insert("viewchunks_forums").Columns("count, createdAt, forum").Fields("?,UTC_TIMESTAMP(),?").Prepare(), 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 c.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) //c.AddScheduledSecondTask(counter.Tick)
common.AddShutdownTask(counter.Tick) c.AddShutdownTask(counter.Tick)
return counter, acc.FirstError() return counter, acc.FirstError()
} }
@ -78,7 +78,7 @@ func (counter *DefaultForumViewCounter) insertChunk(count int, forum int) error
if count == 0 { if count == 0 {
return nil 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) _, err := counter.insert.Exec(count, forum)
return err return err
} }

View File

@ -1,7 +1,7 @@
package counters package counters
import "database/sql" import "database/sql"
import "github.com/Azareal/Gosora/common" import c "github.com/Azareal/Gosora/common"
import "github.com/Azareal/Gosora/query_gen" import "github.com/Azareal/Gosora/query_gen"
var LangViewCounter *DefaultLangViewCounter 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(), insert: acc.Insert("viewchunks_langs").Columns("count, createdAt, lang").Fields("?,UTC_TIMESTAMP(),?").Prepare(),
} }
common.AddScheduledFifteenMinuteTask(counter.Tick) c.AddScheduledFifteenMinuteTask(counter.Tick)
//common.AddScheduledSecondTask(counter.Tick) //c.AddScheduledSecondTask(counter.Tick)
common.AddShutdownTask(counter.Tick) c.AddShutdownTask(counter.Tick)
return counter, acc.FirstError() return counter, acc.FirstError()
} }
@ -143,7 +143,7 @@ func (counter *DefaultLangViewCounter) insertChunk(count int, id int) error {
return nil return nil
} }
var langCode = langCodes[id] 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) _, err := counter.insert.Exec(count, langCode)
return err return err
} }
@ -158,7 +158,7 @@ func (counter *DefaultLangViewCounter) Bump(langCode string) (validCode bool) {
} }
// TODO: Test this check // 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 { if len(counter.buckets) <= id || id < 0 {
return validCode return validCode
} }

View File

@ -4,7 +4,7 @@ import (
"database/sql" "database/sql"
"sync/atomic" "sync/atomic"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -23,9 +23,9 @@ func NewPostCounter() (*DefaultPostCounter, error) {
currentBucket: 0, currentBucket: 0,
insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(), insert: acc.Insert("postchunks").Columns("count, createdAt").Fields("?,UTC_TIMESTAMP()").Prepare(),
} }
common.AddScheduledFifteenMinuteTask(counter.Tick) c.AddScheduledFifteenMinuteTask(counter.Tick)
//common.AddScheduledSecondTask(counter.Tick) //c.AddScheduledSecondTask(counter.Tick)
common.AddShutdownTask(counter.Tick) c.AddShutdownTask(counter.Tick)
return counter, acc.FirstError() return counter, acc.FirstError()
} }
@ -52,7 +52,7 @@ func (counter *DefaultPostCounter) insertChunk(count int64) error {
if count == 0 { if count == 0 {
return nil 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) _, err := counter.insert.Exec(count)
return err return err
} }

View File

@ -5,7 +5,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -28,9 +28,9 @@ func NewDefaultTopicViewCounter() (*DefaultTopicViewCounter, error) {
evenTopics: make(map[int]*RWMutexCounterBucket), evenTopics: make(map[int]*RWMutexCounterBucket),
update: acc.Update("topics").Set("views = views + ?").Where("tid = ?").Prepare(), 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 c.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) //c.AddScheduledSecondTask(counter.Tick)
common.AddShutdownTask(counter.Tick) c.AddShutdownTask(counter.Tick)
return counter, acc.FirstError() return counter, acc.FirstError()
} }
@ -82,14 +82,14 @@ func (counter *DefaultTopicViewCounter) insertChunk(count int, topicID int) erro
return nil 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) _, err := counter.update.Exec(count, topicID)
if err != nil { if err != nil {
return err return err
} }
// TODO: Add a way to disable this for extra speed ;) // TODO: Add a way to disable this for extra speed ;)
tcache := common.Topics.GetCache() tcache := c.Topics.GetCache()
if tcache != nil { if tcache != nil {
topic, err := tcache.Get(topicID) topic, err := tcache.Get(topicID)
if err != nil { if err != nil {

View File

@ -10,7 +10,7 @@ import (
"strconv" "strconv"
"strings" "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 // 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 LastUpdateTime string
MainForumID int MainForumID int
MainForum *common.Forum MainForum *c.Forum
Forums []*common.Forum Forums []*c.Forum
ExtData common.ExtData ExtData c.ExtData
} }
type Page struct { type Page struct {
Title string Title string
Header *common.Header Header *c.Header
ItemList []*common.TopicsRow ItemList []*c.TopicsRow
Forum *common.Forum Forum *c.Forum
Guild *Guild Guild *Guild
Page int Page int
LastPage int LastPage int
@ -61,13 +61,13 @@ type Page struct {
// ListPage is a page struct for constructing a list of every guild // ListPage is a page struct for constructing a list of every guild
type ListPage struct { type ListPage struct {
Title string Title string
Header *common.Header Header *c.Header
GuildList []*Guild GuildList []*Guild
} }
type MemberListPage struct { type MemberListPage struct {
Title string Title string
Header *common.Header Header *c.Header
ItemList []Member ItemList []Member
Guild *Guild Guild *Guild
Page int Page int
@ -83,15 +83,15 @@ type Member struct {
JoinedAt string JoinedAt string
Offline bool // TODO: Need to track the online states of members when WebSockets are enabled 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{ var guildList = []*Guild{
&Guild{ &Guild{
ID: 1, ID: 1,
Name: "lol", Name: "lol",
Link: BuildGuildURL(common.NameToSlug("lol"), 1), Link: BuildGuildURL(c.NameToSlug("lol"), 1),
Desc: "A group for people who like to laugh", Desc: "A group for people who like to laugh",
Active: true, Active: true,
MemberCount: 1, MemberCount: 1,
@ -99,26 +99,26 @@ func PrebuildTmplList(user common.User, header *common.Header) common.CTmpl {
CreatedAt: "date", CreatedAt: "date",
LastUpdateTime: "date", LastUpdateTime: "date",
MainForumID: 1, MainForumID: 1,
MainForum: common.Forums.DirtyGet(1), MainForum: c.Forums.DirtyGet(1),
Forums: []*common.Forum{common.Forums.DirtyGet(1)}, Forums: []*c.Forum{c.Forums.DirtyGet(1)},
}, },
} }
listPage := ListPage{"Guild List", user, header, guildList} 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: Do this properly via the widget system
// TODO: REWRITE THIS // TODO: REWRITE THIS
func CommonAreaWidgets(header *common.Header) { func CommonAreaWidgets(header *c.Header) {
// TODO: Hot Groups? Featured Groups? Official Groups? // TODO: Hot Groups? Featured Groups? Official Groups?
var b bytes.Buffer var b bytes.Buffer
var menu = common.WidgetMenu{"Guilds", []common.WidgetMenuItem{ var menu = c.WidgetMenu{"Guilds", []c.WidgetMenuItem{
common.WidgetMenuItem{"Create Guild", "/guild/create/", false}, c.WidgetMenuItem{"Create Guild", "/guild/create/", false},
}} }}
err := header.Theme.RunTmpl("widget_menu", pi, w) err := header.Theme.RunTmpl("widget_menu", pi, w)
if err != nil { if err != nil {
common.LogError(err) c.LogError(err)
return return
} }
@ -131,7 +131,7 @@ func CommonAreaWidgets(header *common.Header) {
// TODO: Do this properly via the widget system // TODO: Do this properly via the widget system
// TODO: Make a better more customisable group 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 return false // Disabled until the next commit
/*var b bytes.Buffer /*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) err := templates.ExecuteTemplate(&b, "widget_menu.html", menu)
if err != nil { if err != nil {
common.LogError(err) c.LogError(err)
return false return false
} }
@ -160,16 +160,16 @@ func GuildWidgets(header *common.Header, guildItem *Guild) (success bool) {
Custom Pages Custom Pages
*/ */
func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func RouteGuildList(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
header, ferr := common.UserCheck(w, r, &user) header, ferr := c.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
CommonAreaWidgets(header) CommonAreaWidgets(header)
rows, err := ListStmt.Query() rows, err := ListStmt.Query()
if err != nil && err != common.ErrNoRows { if err != nil && err != c.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
defer rows.Close() defer rows.Close()
@ -178,37 +178,37 @@ func RouteGuildList(w http.ResponseWriter, r *http.Request, user common.User) co
guildItem := &Guild{ID: 0} 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) 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 { 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) guildList = append(guildList, guildItem)
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
pi := ListPage{"Guild List", user, header, guildList} pi := ListPage{"Guild List", user, header, guildList}
err = header.Theme.RunTmpl("guilds_guild_list", pi, w) err = header.Theme.RunTmpl("guilds_guild_list", pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil 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/"):]) _, guildID, err := routes.ParseSEOURL(r.URL.Path[len("/guild/"):])
if err != nil { 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) guildItem, err := Gstore.Get(guildID)
if err != nil { if err != nil {
return common.LocalError("Bad guild", w, r, user) return c.LocalError("Bad guild", w, r, user)
} }
// TODO: Build and pass header // TODO: Build and pass header
if !guildItem.Active { if !guildItem.Active {
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} }
return 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)) //return routeForum(w, r.WithContext(ctx), user, strconv.Itoa(guildItem.MainForumID))
} }
func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func RouteCreateGuild(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
header, ferr := common.UserCheck(w, r, &user) header, ferr := c.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
header.Title = "Create Guild" header.Title = "Create Guild"
// TODO: Add an approval queue mode for group creation // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateGuild"] { if !user.Loggedin || !user.PluginPerms["CreateGuild"] {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
CommonAreaWidgets(header) CommonAreaWidgets(header)
pi := common.Page{header, tList, nil} pi := c.Page{header, tList, nil}
err := header.Theme.RunTmpl("guilds_create_guild", pi, w) err := header.Theme.RunTmpl("guilds_create_guild", pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil 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 // TODO: Add an approval queue mode for group creation
if !user.Loggedin || !user.PluginPerms["CreateGuild"] { if !user.Loggedin || !user.PluginPerms["CreateGuild"] {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
var guildActive = true 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? // 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 gprivacy = r.PostFormValue("group_privacy")
var guildPrivacy int var guildPrivacy int
@ -264,53 +264,53 @@ func RouteCreateGuildSubmit(w http.ResponseWriter, r *http.Request, user common.
} }
// Create the backing forum // Create the backing forum
fid, err := common.Forums.Create(guildName, "", true, "") fid, err := c.Forums.Create(guildName, "", true, "")
if err != nil { 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) gid, err := Gstore.Create(guildName, guildDesc, guildActive, guildPrivacy, user.ID, fid)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// Add the main backing forum to the forum list // Add the main backing forum to the forum list
err = AttachForum(gid, fid) err = AttachForum(gid, fid)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
_, err = AddMemberStmt.Exec(gid, user.ID, 2) _, err = AddMemberStmt.Exec(gid, user.ID, 2)
if err != nil { 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 return nil
} }
func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func RouteMemberList(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
header, ferr := common.UserCheck(w, r, &user) header, ferr := c.UserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
_, guildID, err := routes.ParseSEOURL(r.URL.Path[len("/guild/members/"):]) _, guildID, err := routes.ParseSEOURL(r.URL.Path[len("/guild/members/"):])
if err != nil { 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) guildItem, err := Gstore.Get(guildID)
if err != nil { 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) GuildWidgets(header, guildItem)
rows, err := MemberListJoinStmt.Query(guildID) rows, err := MemberListJoinStmt.Query(guildID)
if err != nil && err != common.ErrNoRows { if err != nil && err != c.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var guildMembers []Member var guildMembers []Member
@ -318,11 +318,11 @@ func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) c
guildMember := Member{PostCount: 0} guildMember := Member{PostCount: 0}
err := rows.Scan(&guildMember.User.ID, &guildMember.Rank, &guildMember.PostCount, &guildMember.JoinedAt, &guildMember.User.Name, &guildMember.User.RawAvatar) err := rows.Scan(&guildMember.User.ID, &guildMember.Rank, &guildMember.PostCount, &guildMember.JoinedAt, &guildMember.User.Name, &guildMember.User.RawAvatar)
if err != nil { 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.Link = c.BuildProfileURL(c.NameToSlug(guildMember.User.Name), guildMember.User.ID)
guildMember.User.Avatar, guildMember.User.MicroAvatar = common.BuildAvatar(guildMember.User.ID, guildMember.User.RawAvatar) guildMember.User.Avatar, guildMember.User.MicroAvatar = c.BuildAvatar(guildMember.User.ID, guildMember.User.RawAvatar)
guildMember.JoinedAt, _ = common.RelativeTimeFromString(guildMember.JoinedAt) guildMember.JoinedAt, _ = c.RelativeTimeFromString(guildMember.JoinedAt)
if guildItem.Owner == guildMember.User.ID { if guildItem.Owner == guildMember.User.ID {
guildMember.RankString = "Owner" guildMember.RankString = "Owner"
} else { } else {
@ -339,18 +339,18 @@ func RouteMemberList(w http.ResponseWriter, r *http.Request, user common.User) c
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
rows.Close() rows.Close()
pi := MemberListPage{"Guild Member List", user, header, guildMembers, guildItem, 0, 0} pi := MemberListPage{"Guild Member List", user, header, guildMembers, guildItem, 0, 0}
// A plugin with plugins. Pluginception! // 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 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil return nil
} }
@ -366,7 +366,7 @@ func UnattachForum(fid int) error {
} }
func BuildGuildURL(slug string, id int) string { func BuildGuildURL(slug string, id int) string {
if slug == "" || !common.Config.BuildSlugs { if slug == "" || !c.Config.BuildSlugs {
return "/guild/" + strconv.Itoa(id) return "/guild/" + strconv.Itoa(id)
} }
return "/guild/" + slug + "." + strconv.Itoa(id) return "/guild/" + slug + "." + strconv.Itoa(id)
@ -377,8 +377,8 @@ func BuildGuildURL(slug string, id int) string {
*/ */
// TODO: Prebuild this template // TODO: Prebuild this template
func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.User, data interface{}) (halt bool) { func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *c.User, data interface{}) (halt bool) {
pi := data.(*common.ForumPage) pi := data.(*c.ForumPage)
if pi.Header.ExtData.Items != nil { if pi.Header.ExtData.Items != nil {
if guildData, ok := pi.Header.ExtData.Items["guilds_current_group"]; ok { if guildData, ok := pi.Header.ExtData.Items["guilds_current_group"]; ok {
guildItem := guildData.(*Guild) 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} guildpi := Page{pi.Title, pi.Header, pi.ItemList, pi.Forum, guildItem, pi.Page, pi.LastPage}
err := header.Theme.RunTmpl("guilds_view_guild", guildpi, w) err := header.Theme.RunTmpl("guilds_view_guild", guildpi, w)
if err != nil { if err != nil {
common.LogError(err) c.LogError(err)
return false return false
} }
return true return true
@ -396,10 +396,10 @@ func PreRenderViewForum(w http.ResponseWriter, r *http.Request, user *common.Use
} }
func TrowAssign(args ...interface{}) interface{} { func TrowAssign(args ...interface{}) interface{} {
var forum = args[1].(*common.Forum) var forum = args[1].(*c.Forum)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
var topicItem = args[0].(*common.TopicsRow) var topicItem = args[0].(*c.TopicsRow)
topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, common.GetForumURLPrefix()) topicItem.ForumLink = "/guild/" + strings.TrimPrefix(topicItem.ForumLink, c.GetForumURLPrefix())
} }
return nil 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 // 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{} { func TopicCreatePreLoop(args ...interface{}) interface{} {
var fid = args[2].(int) var fid = args[2].(int)
if common.Forums.DirtyGet(fid).ParentType == "guild" { if c.Forums.DirtyGet(fid).ParentType == "guild" {
var strictmode = args[5].(*bool) var strictmode = args[5].(*bool)
*strictmode = true *strictmode = true
} }
@ -417,10 +417,10 @@ func TopicCreatePreLoop(args ...interface{}) interface{} {
// TODO: Add privacy options // TODO: Add privacy options
// TODO: Add support for multiple boards and add per-board simplified permissions // TODO: Add support for multiple boards and add per-board simplified permissions
// TODO: Take isJs into account for routes which expect JSON responses // 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 r = args[1].(*http.Request)
var fid = args[3].(*int) var fid = args[3].(*int)
var forum = common.Forums.DirtyGet(*fid) var forum = c.Forums.DirtyGet(*fid)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
var err error var err error
@ -429,15 +429,15 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) {
if !ok { if !ok {
guildItem, err = Gstore.Get(forum.ParentID) guildItem, err = Gstore.Get(forum.ParentID)
if err != nil { 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 { 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)) 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 rank int
var posts int var posts int
var joinedAt string var joinedAt string
@ -446,32 +446,32 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) {
// Clear the default group permissions // Clear the default group permissions
// TODO: Do this more efficiently, doing it quick and dirty for now to get this out quickly // 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 user.Perms.ViewTopic = true
err = GetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt) err = GetMemberStmt.QueryRow(guildItem.ID, user.ID).Scan(&rank, &posts, &joinedAt)
if err != nil && err != common.ErrNoRows { if err != nil && err != c.ErrNoRows {
return true, common.InternalError(err, w, r) return true, c.InternalError(err, w, r)
} else if err != nil { } else if err != nil {
// TODO: Should we let admins / guests into public groups? // 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: 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! // TODO: How does this even work? Refactor it along with the rest of this plugin!
if rank < 0 { 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! // Basic permissions for members, more complicated permissions coming in the next commit!
if guildItem.Owner == user.ID { if guildItem.Owner == user.ID {
common.OverrideForumPerms(&user.Perms, true) c.OverrideForumPerms(&user.Perms, true)
} else if rank == 0 { } else if rank == 0 {
user.Perms.LikeItem = true user.Perms.LikeItem = true
user.Perms.CreateTopic = true user.Perms.CreateTopic = true
user.Perms.CreateReply = true user.Perms.CreateReply = true
} else { } else {
common.OverrideForumPerms(&user.Perms, true) c.OverrideForumPerms(&user.Perms, true)
} }
return true, nil return true, nil
} }
@ -483,19 +483,19 @@ func ForumCheck(args ...interface{}) (skip bool, rerr common.RouteError) {
func Widgets(args ...interface{}) interface{} { func Widgets(args ...interface{}) interface{} {
var zone = args[0].(string) var zone = args[0].(string)
var header = args[2].(*common.Header) var header = args[2].(*c.Header)
var request = args[3].(*http.Request) var request = args[3].(*http.Request)
if zone != "view_forum" { if zone != "view_forum" {
return false return false
} }
var forum = args[1].(*common.Forum) var forum = args[1].(*c.Forum)
if forum.ParentType == "guild" { if forum.ParentType == "guild" {
// This is why I hate using contexts, all the daisy chains and interface casts x.x // 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) guildItem, ok := request.Context().Value("guilds_current_group").(*Guild)
if !ok { 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 return false
} }

View File

@ -11,7 +11,7 @@ import (
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
@ -38,18 +38,18 @@ func main() {
}() }()
log.Print("Loading the configuration data") log.Print("Loading the configuration data")
err := common.LoadConfig() err := c.LoadConfig()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Processing configuration data") log.Print("Processing configuration data")
err = common.ProcessConfig() err = c.ProcessConfig()
if err != nil { if err != nil {
log.Fatal(err) 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") 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 { func prepMySQL() error {
return qgen.Builder.Init("mysql", map[string]string{ return qgen.Builder.Init("mysql", map[string]string{
"host": common.DbConfig.Host, "host": c.DbConfig.Host,
"port": common.DbConfig.Port, "port": c.DbConfig.Port,
"name": common.DbConfig.Dbname, "name": c.DbConfig.Dbname,
"username": common.DbConfig.Username, "username": c.DbConfig.Username,
"password": common.DbConfig.Password, "password": c.DbConfig.Password,
"collation": "utf8mb4_general_ci", "collation": "utf8mb4_general_ci",
}) })
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,12 @@ import (
"strconv" "strconv"
"strings" "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: 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 // 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? // TODO: Do we have to put * or something at the end of the paths?
_, _ = w.Write([]byte(`User-agent: * _, _ = w.Write([]byte(`User-agent: *
Disallow: /panel/* 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 // 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 var sslBit string
if common.Site.EnableSsl { if c.Site.EnableSsl {
sslBit = "s" sslBit = "s"
} }
var sitemapItem = func(path string) { var sitemapItem = func(path string) {
w.Write([]byte(`<sitemap> w.Write([]byte(`<sitemap>
<loc>http` + sslBit + `://` + common.Site.URL + "/" + path + `</loc> <loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
</sitemap> </sitemap>
`)) `))
} }
@ -55,13 +55,13 @@ func SitemapXml(w http.ResponseWriter, r *http.Request) common.RouteError {
type FuzzyRoute struct { type FuzzyRoute struct {
Path string 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: Add a sitemap API and clean things up
// TODO: ^-- Make sure that the API is concurrent // TODO: ^-- Make sure that the API is concurrent
// TODO: Add a social group sitemap // 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, "forums.xml": SitemapForums,
"topics.xml": SitemapTopics, "topics.xml": SitemapTopics,
} }
@ -71,7 +71,7 @@ var fuzzySitemapRoutes = map[string]FuzzyRoute{
"topics_page_": FuzzyRoute{"topics_page_(%d).xml", SitemapTopic}, "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/"):] var path = r.URL.Path[len("/sitemaps/"):]
for name, fuzzy := range fuzzySitemapRoutes { for name, fuzzy := range fuzzySitemapRoutes {
if strings.HasPrefix(path, name) && strings.HasSuffix(path, ".xml") { 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) page, err := strconv.Atoi(spath)
if err != nil { if err != nil {
// ? What's this? Do we need it? Was it just a quick trace? // ? 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) c.DebugLogf("Unable to convert string '%s' to integer in fuzzy route", spath)
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} }
return fuzzy.Handle(w, r, page) return fuzzy.Handle(w, r, page)
} }
@ -89,26 +89,26 @@ func sitemapSwitch(w http.ResponseWriter, r *http.Request) common.RouteError {
route, ok := sitemapRoutes[path] route, ok := sitemapRoutes[path]
if !ok { if !ok {
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} }
return route(w, r) 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 var sslBit string
if common.Site.EnableSsl { if c.Site.EnableSsl {
sslBit = "s" sslBit = "s"
} }
var sitemapItem = func(path string) { var sitemapItem = func(path string) {
w.Write([]byte(`<url> w.Write([]byte(`<url>
<loc>http` + sslBit + `://` + common.Site.URL + path + `</loc> <loc>http` + sslBit + `://` + c.Site.URL + path + `</loc>
</url> </url>
`)) `))
} }
group, err := common.Groups.Get(common.GuestUser.Group) group, err := c.Groups.Get(c.GuestUser.Group)
if err != nil { 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) writeXMLHeader(w, r)
@ -116,9 +116,9 @@ func SitemapForums(w http.ResponseWriter, r *http.Request) common.RouteError {
for _, fid := range group.CanSee { 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 // 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.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? // 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 // ? 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 var sslBit string
if common.Site.EnableSsl { if c.Site.EnableSsl {
sslBit = "s" sslBit = "s"
} }
var sitemapItem = func(path string) { var sitemapItem = func(path string) {
w.Write([]byte(`<sitemap> w.Write([]byte(`<sitemap>
<loc>http` + sslBit + `://` + common.Site.URL + "/" + path + `</loc> <loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
</sitemap> </sitemap>
`)) `))
} }
group, err := common.Groups.Get(common.GuestUser.Group) group, err := c.Groups.Get(c.GuestUser.Group)
if err != nil { 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 { for _, fid := range group.CanSee {
forum := common.Forums.DirtyGet(fid) forum := c.Forums.DirtyGet(fid)
if forum.Name != "" && forum.Active { if forum.Name != "" && forum.Active {
visibleForums = append(visibleForums, forum.Copy()) visibleForums = append(visibleForums, forum.Copy())
} }
} }
topicCount, err := common.TopicCountInForums(visibleForums) topicCount, err := c.TopicCountInForums(visibleForums)
if err != nil { if err != nil {
return common.InternalErrorXML(err, w, r) return c.InternalErrorXML(err, w, r)
} }
var pageCount = topicCount / sitemapPageCap var pageCount = topicCount / sitemapPageCap
@ -170,35 +170,35 @@ func SitemapTopics(w http.ResponseWriter, r *http.Request) common.RouteError {
return nil 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 /*var sslBit string
if common.Site.EnableSsl { if c.Site.EnableSsl {
sslBit = "s" sslBit = "s"
} }
var sitemapItem = func(path string) { var sitemapItem = func(path string) {
w.Write([]byte(`<url> w.Write([]byte(`<url>
<loc>http` + sslBit + `://` + common.Site.URL + "/" + path + `</loc> <loc>http` + sslBit + `://` + c.Site.URL + "/" + path + `</loc>
</url> </url>
`)) `))
}*/ }*/
group, err := common.Groups.Get(common.GuestUser.Group) group, err := c.Groups.Get(c.GuestUser.Group)
if err != nil { 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 { for _, fid := range group.CanSee {
forum := common.Forums.DirtyGet(fid) forum := c.Forums.DirtyGet(fid)
if forum.Name != "" && forum.Active { if forum.Name != "" && forum.Active {
visibleForums = append(visibleForums, forum.Copy()) visibleForums = append(visibleForums, forum.Copy())
} }
} }
argList, qlist := common.ForumListToArgQ(visibleForums) argList, qlist := c.ForumListToArgQ(visibleForums)
topicCount, err := common.ArgQToTopicCount(argList, qlist) topicCount, err := c.ArgQToTopicCount(argList, qlist)
if err != nil { if err != nil {
return common.InternalErrorXML(err, w, r) return c.InternalErrorXML(err, w, r)
} }
var pageCount = topicCount / sitemapPageCap var pageCount = topicCount / sitemapPageCap
@ -216,18 +216,18 @@ func SitemapTopic(w http.ResponseWriter, r *http.Request, page int) common.Route
return nil 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) writeXMLHeader(w, r)
w.Write([]byte("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n")) w.Write([]byte("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n"))
return nil return nil
} }
type JsonMe struct { type JsonMe struct {
User *common.MeUser User *c.MeUser
Site MeSite 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 { type MeSite struct {
MaxRequestSize int MaxRequestSize int
} }
@ -235,18 +235,18 @@ type MeSite struct {
// APIMe returns information about the current logged-in user // 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: 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? // 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 // 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") w.Header().Set("Content-Type", "application/json")
// We don't want an intermediary accidentally caching this // We don't want an intermediary accidentally caching this
// TODO: Use this header anywhere with a user check? // TODO: Use this header anywhere with a user check?
w.Header().Set("Cache-Control", "private") 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) jsonBytes, err := json.Marshal(me)
if err != nil { if err != nil {
return common.InternalErrorJS(err, w, r) return c.InternalErrorJS(err, w, r)
} }
w.Write(jsonBytes) w.Write(jsonBytes)

View File

@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -20,7 +20,7 @@ var attachmentStmts AttachmentStmts
// TODO: Abstract this with an attachment store // TODO: Abstract this with an attachment store
func init() { func init() {
common.DbInits.Add(func(acc *qgen.Accumulator) error { c.DbInits.Add(func(acc *qgen.Accumulator) error {
attachmentStmts = AttachmentStmts{ attachmentStmts = AttachmentStmts{
get: acc.Select("attachments").Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path").Where("path = ? AND sectionID = ? AND sectionTable = ?").Prepare(), 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 { func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filename string) c.RouteError {
filename = common.Stripslashes(filename) filename = c.Stripslashes(filename)
var ext = filepath.Ext("./attachs/" + filename) var ext = filepath.Ext("./attachs/" + filename)
if !common.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { if !c.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) {
return common.LocalError("Bad extension", w, r, user) return c.LocalError("Bad extension", w, r, user)
} }
sectionID, err := strconv.Atoi(r.FormValue("sectionID")) sectionID, err := strconv.Atoi(r.FormValue("sectionID"))
if err != nil { 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") 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 var originID, uploadedBy int
err = attachmentStmts.get.QueryRow(filename, sectionID, sectionTable).Scan(&sectionID, &sectionTable, &originID, &originTable, &uploadedBy, &filename) err = attachmentStmts.get.QueryRow(filename, sectionID, sectionTable).Scan(&sectionID, &sectionTable, &originID, &originTable, &uploadedBy, &filename)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
if sectionTable == "forums" { if sectionTable == "forums" {
_, ferr := common.SimpleForumUserCheck(w, r, &user, sectionID) _, ferr := c.SimpleForumUserCheck(w, r, &user, sectionID)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic { if !user.Perms.ViewTopic {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
} else { } else {
return common.LocalError("Unknown section", w, r, user) return c.LocalError("Unknown section", w, r, user)
} }
if originTable != "topics" && originTable != "replies" { if originTable != "topics" && originTable != "replies" {
return common.LocalError("Unknown origin", w, r, user) return c.LocalError("Unknown origin", w, r, user)
} }
if !user.Loggedin { 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 { } else {
guest := common.GuestUser guest := c.GuestUser
_, ferr := common.SimpleForumUserCheck(w, r, &guest, sectionID) _, ferr := c.SimpleForumUserCheck(w, r, &guest, sectionID)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if guest.Perms.ViewTopic { 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 { } else {
w.Header().Set("Cache-Control", "private") 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 // 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 { func deleteAttachment(w http.ResponseWriter, r *http.Request, user c.User, aid int, js bool) c.RouteError {
attach, err := common.Attachments.Get(aid) attach, err := c.Attachments.Get(aid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return common.NotFoundJSQ(w, r, nil, js) return c.NotFoundJSQ(w, r, nil, js)
} else if err != nil { } 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 { 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 { if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
if count == 0 { if count == 0 {
err := os.Remove("./attachs/" + attach.Path) err := os.Remove("./attachs/" + attach.Path)
if err != nil { 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: Stop duplicating this code
// TODO: Use a transaction here // TODO: Use a transaction here
// TODO: Move this function to neutral ground // 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) pathMap = make(map[string]string)
files, rerr := uploadFilesWithHash(w, r, user, "./attachs/") files, rerr := uploadFilesWithHash(w, r, user, "./attachs/")
if rerr != nil { if rerr != nil {
@ -125,9 +125,9 @@ func uploadAttachment(w http.ResponseWriter, r *http.Request, user common.User,
} }
for _, filename := range files { 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 { if err != nil {
return nil, common.InternalError(err, w, r) return nil, c.InternalError(err, w, r)
} }
_, ok := pathMap[filename] _, ok := pathMap[filename]
@ -139,18 +139,18 @@ func uploadAttachment(w http.ResponseWriter, r *http.Request, user common.User,
switch originTable { switch originTable {
case "topics": 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 { 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 { if err != nil {
return nil, common.InternalError(err, w, r) return nil, c.InternalError(err, w, r)
} }
case "replies": 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 { if err != nil {
return nil, common.InternalError(err, w, r) return nil, c.InternalError(err, w, r)
} }
} }
} }

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
) )
var successJSONBytes = []byte(`{"success":"1"}`) var successJSONBytes = []byte(`{"success":"1"}`)
@ -21,9 +21,9 @@ func ParseSEOURL(urlBit string) (slug string, id int, err error) {
return halves[0], tid, err 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") //fmt.Println("in doPush")
if common.Config.EnableCDNPush { if c.Config.EnableCDNPush {
// TODO: Faster string building... // TODO: Faster string building...
var sbuf string var sbuf string
var push = func(in []string) { var push = func(in []string) {
@ -46,9 +46,9 @@ func doPush(w http.ResponseWriter, header *common.Header) {
sbuf = sbuf[:len(sbuf)-1] sbuf = sbuf[:len(sbuf)-1]
w.Header().Set("Link", sbuf) w.Header().Set("Link", sbuf)
} }
} else if !common.Config.DisableServerPush { } else if !c.Config.DisableServerPush {
//fmt.Println("push enabled") //fmt.Println("push enabled")
gzw, ok := w.(common.GzipResponseWriter) gzw, ok := w.(c.GzipResponseWriter)
if ok { if ok {
w = gzw.ResponseWriter 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 { if header.CurrentUser.Loggedin {
header.MetaDesc = "" header.MetaDesc = ""
header.OGDesc = "" header.OGDesc = ""
@ -83,7 +83,7 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea
header.OGDesc = header.MetaDesc header.OGDesc = header.MetaDesc
} }
// TODO: Expand this to non-HTTPS requests too // 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") 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") header.AddScript("global.js")
@ -98,12 +98,12 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea
if header.CurrentUser.IsAdmin { if header.CurrentUser.IsAdmin {
header.Elapsed1 = time.Since(header.StartedAt).String() 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 return nil
} }
err := header.Theme.RunTmpl(tmplName, pi, w) err := header.Theme.RunTmpl(tmplName, pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil return nil
} }

View File

@ -5,7 +5,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/counters"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
@ -19,7 +19,7 @@ var forumStmts ForumStmts
// TODO: Move these DbInits into *Forum as Topics() // TODO: Move these DbInits into *Forum as Topics()
func init() { func init() {
common.DbInits.Add(func(acc *qgen.Accumulator) error { c.DbInits.Add(func(acc *qgen.Accumulator) error {
forumStmts = ForumStmts{ 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(), 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/? // 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")) page, _ := strconv.Atoi(r.FormValue("page"))
_, fid, err := ParseSEOURL(sfid) _, fid, err := ParseSEOURL(sfid)
if err != nil { 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic { if !user.Perms.ViewTopic {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
header.Path = "/forums/" header.Path = "/forums/"
// TODO: Fix this double-check // TODO: Fix this double-check
forum, err := common.Forums.Get(fid) forum, err := c.Forums.Get(fid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return common.NotFound(w, r, header) return c.NotFound(w, r, header)
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
header.Title = forum.Name header.Title = forum.Name
header.OGDesc = forum.Desc 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 // 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 // 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
defer rows.Close() 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? // 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) var reqUserList = make(map[int]bool)
for rows.Next() { 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) 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 { 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 // 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 topicItem.LastPage = lastPage
header.Hooks.VhookNoRet("forum_trow_assign", &topicItem, &forum) 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() err = rows.Err()
if err != nil { 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 // 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? // 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// Second pass to the add the user data // 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" { if r.FormValue("js") == "1" {
outBytes, err := wsTopicList(topicList, lastPage).MarshalJSON() outBytes, err := wsTopicList(topicList, lastPage).MarshalJSON()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
w.Write(outBytes) w.Write(outBytes)
return nil return nil
} }
pageList := common.Paginate(forum.TopicCount, common.Config.ItemsPerPage, 5) pageList := c.Paginate(forum.TopicCount, c.Config.ItemsPerPage, 5)
pi := common.ForumPage{header, topicList, forum, common.Paginator{pageList, page, lastPage}} pi := c.ForumPage{header, topicList, forum, c.Paginator{pageList, page, lastPage}}
ferr = renderTemplate("forum", w, r, header, pi) ferr = renderTemplate("forum", w, r, header, pi)
counters.ForumViewCounter.Bump(forum.ID) counters.ForumViewCounter.Bump(forum.ID)
return ferr return ferr

View File

@ -4,40 +4,40 @@ import (
"log" "log"
"net/http" "net/http"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "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.Title = phrases.GetTitlePhrase("forums")
header.Zone = "forums" header.Zone = "forums"
header.Path = "/forums/" header.Path = "/forums/"
header.MetaDesc = header.Settings["meta_desc"].(string) header.MetaDesc = header.Settings["meta_desc"].(string)
var err error var err error
var forumList []common.Forum var forumList []c.Forum
var canSee []int var canSee []int
if user.IsSuperAdmin { if user.IsSuperAdmin {
canSee, err = common.Forums.GetAllVisibleIDs() canSee, err = c.Forums.GetAllVisibleIDs()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
} else { } else {
group, err := common.Groups.Get(user.Group) group, err := c.Groups.Get(user.Group)
if err != nil { if err != nil {
log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) log.Printf("Group #%d doesn't exist despite being used by c.User #%d", user.Group, user.ID)
return common.LocalError("Something weird happened", w, r, user) return c.LocalError("Something weird happened", w, r, user)
} }
canSee = group.CanSee canSee = group.CanSee
} }
for _, fid := range canSee { for _, fid := range canSee {
// Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else // Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else
var forum = common.Forums.DirtyGet(fid).Copy() var forum = c.Forums.DirtyGet(fid).Copy()
if forum.ParentID == 0 && forum.Name != "" && forum.Active { if forum.ParentID == 0 && forum.Name != "" && forum.Active {
if forum.LastTopicID != 0 { if forum.LastTopicID != 0 {
if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 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 { } else {
forum.LastTopicTime = "" 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) return renderTemplate("forums", w, r, header, pi)
} }

View File

@ -9,17 +9,17 @@ import (
"strings" "strings"
"time" "time"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "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 // GET functions
func StaticFile(w http.ResponseWriter, r *http.Request) { 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 { 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) w.WriteHeader(http.StatusNotFound)
return 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() // 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.Title = phrases.GetTitlePhrase("overview")
header.Zone = "overview" header.Zone = "overview"
pi := common.Page{header, tList, nil} pi := c.Page{header, tList, nil}
return renderTemplate("overview", w, r, header, pi) 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" header.Zone = "custom_page"
name = common.SanitiseSingleLine(name) name = c.SanitiseSingleLine(name)
page, err := common.Pages.GetByName(name) page, err := c.Pages.GetByName(name)
if err == nil { if err == nil {
header.Title = page.Title header.Title = page.Title
pi := common.CustomPagePage{header, page} pi := c.CustomPagePage{header, page}
return renderTemplate("custom_page", w, r, header, pi) return renderTemplate("custom_page", w, r, header, pi)
} else if err != sql.ErrNoRows { } else if err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// ! Is this safe? // ! Is this safe?
if common.DefaultTemplates.Lookup("page_"+name+".html") == nil { if c.DefaultTemplates.Lookup("page_"+name+".html") == nil {
return common.NotFound(w, r, header) return c.NotFound(w, r, header)
} }
header.Title = phrases.GetTitlePhrase("page") 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? // 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 return nil
} }
err = header.Theme.RunTmpl("page_"+name, pi, w) err = header.Theme.RunTmpl("page_"+name, pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil return nil
} }
// TODO: Set the cookie domain // 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) //headerLite, _ := SimpleUserCheck(w, r, &user)
// TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly? // TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly?
isJs := (r.PostFormValue("isJs") == "1") 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 { 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) http.SetCookie(w, &cookie)
if !isJs { if !isJs {

View File

@ -3,37 +3,37 @@ package routes
import ( import (
"net/http" "net/http"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "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") header.Title = phrases.GetTitlePhrase("ip_search")
// TODO: How should we handle the permissions if we extend this into an alt detector of sorts? // TODO: How should we handle the permissions if we extend this into an alt detector of sorts?
if !user.Perms.ViewIPs { if !user.Perms.ViewIPs {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
// TODO: Reject IP Addresses with illegal characters // TODO: Reject IP Addresses with illegal characters
var ip = common.SanitiseSingleLine(r.FormValue("ip")) var ip = c.SanitiseSingleLine(r.FormValue("ip"))
uids, err := common.IPSearch.Lookup(ip) uids, err := c.IPSearch.Lookup(ip)
if err != nil { 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 // 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
pi := common.IPSearchPage{header, userList, ip} pi := c.IPSearchPage{header, userList, ip}
if common.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) { if c.RunPreRenderHook("pre_render_ip_search", w, r, &user, &pi) {
return nil return nil
} }
err = header.Theme.RunTmpl("ip_search", pi, w) err = header.Theme.RunTmpl("ip_search", pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil return nil
} }

View File

@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -103,7 +103,7 @@ func analyticsRowsToViewMap(rows *sql.Rows, labelList []int64, viewMap map[int64
} }
var unixCreatedAt = createdAt.Unix() var unixCreatedAt = createdAt.Unix()
// TODO: Bulk log this // TODO: Bulk log this
if common.Dev.SuperDebug { if c.Dev.SuperDebug {
log.Print("count: ", count) log.Print("count: ", count)
log.Print("createdAt: ", createdAt) log.Print("createdAt: ", createdAt)
log.Print("unixCreatedAt: ", unixCreatedAt) log.Print("unixCreatedAt: ", unixCreatedAt)
@ -118,7 +118,7 @@ func analyticsRowsToViewMap(rows *sql.Rows, labelList []int64, viewMap map[int64
return viewMap, rows.Err() 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") basePage, ferr := buildBasePage(w, r, user, "analytics", "analytics")
if ferr != nil { if ferr != nil {
return nil, ferr return nil, ferr
@ -129,336 +129,336 @@ func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *common.Use
return basePage, nil 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
common.DebugLog("in panel.AnalyticsViews") c.DebugLog("in panel.AnalyticsViews")
// TODO: Add some sort of analytics store / iterator? // 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() rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, createdAt").Where("route = ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
var viewItems []common.PanelAnalyticsItem var viewItems []c.PanelAnalyticsItem
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) 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} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
var ttime string var ttime string
if timeRange.Range == "six-hours" || timeRange.Range == "twelve-hours" || timeRange.Range == "one-day" { if timeRange.Range == "six-hours" || timeRange.Range == "twelve-hours" || timeRange.Range == "one-day" {
ttime = "time" 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
common.DebugLog("in panel.AnalyticsRouteViews") c.DebugLog("in panel.AnalyticsRouteViews")
// TODO: Validate the route is valid // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
var viewItems []common.PanelAnalyticsItem var viewItems []c.PanelAnalyticsItem
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) 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} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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 // ? 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 // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) viewList = append(viewList, viewMap[value])
} }
graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
friendlyAgent, ok := phrases.GetUserAgentPhrase(agent) friendlyAgent, ok := phrases.GetUserAgentPhrase(agent)
if !ok { if !ok {
friendlyAgent = agent 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { 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 // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) viewList = append(viewList, viewMap[value])
} }
graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
forum, err := common.Forums.Get(fid) forum, err := c.Forums.Get(fid)
if err != nil { 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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 // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) viewList = append(viewList, viewMap[value])
} }
graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
friendlySystem, ok := phrases.GetOSPhrase(system) friendlySystem, ok := phrases.GetOSPhrase(system)
if !ok { if !ok {
friendlySystem = system 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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 // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) viewList = append(viewList, viewMap[value])
} }
graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
friendlyLang, ok := phrases.GetHumanLangPhrase(lang) friendlyLang, ok := phrases.GetHumanLangPhrase(lang)
if !ok { if !ok {
friendlyLang = lang 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
common.DebugLog("in panel.AnalyticsReferrerViews") c.DebugLog("in panel.AnalyticsReferrerViews")
// TODO: Verify the agent is valid // 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) 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 { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) viewList = append(viewList, viewMap[value])
} }
graph := common.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
pi := common.PanelAnalyticsAgentPage{basePage, common.SanitiseSingleLine(domain), "", graph, timeRange.Range} pi := c.PanelAnalyticsAgentPage{basePage, c.SanitiseSingleLine(domain), "", graph, timeRange.Range}
return renderTemplate("panel_analytics_referrer_views", w, r, basePage.Header, &pi) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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() rows, err := qgen.NewAcc().Select("topicchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
var viewItems []common.PanelAnalyticsItem var viewItems []c.PanelAnalyticsItem
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) 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} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
pi := common.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} pi := c.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"}
return renderTemplate("panel_analytics_topics", w, r, basePage.Header, &pi) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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() rows, err := qgen.NewAcc().Select("postchunks").Columns("count, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap) viewMap, err = analyticsRowsToViewMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var viewList []int64 var viewList []int64
var viewItems []common.PanelAnalyticsItem var viewItems []c.PanelAnalyticsItem
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, viewMap[value]) 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} graph := c.PanelTimeGraph{Series: [][]int64{viewList}, Labels: labelList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
pi := common.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"} pi := c.PanelAnalyticsPage{basePage, graph, viewItems, timeRange.Range, timeRange.Unit, "time"}
return renderTemplate("panel_analytics_posts", w, r, basePage.Header, &pi) 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 return nameMap, err
} }
// TODO: Bulk log this // TODO: Bulk log this
if common.Dev.SuperDebug { if c.Dev.SuperDebug {
log.Print("count: ", count) log.Print("count: ", count)
log.Print("name: ", name) log.Print("name: ", name)
} }
@ -497,7 +497,7 @@ func analyticsRowsToDuoMap(rows *sql.Rows, labelList []int64, viewMap map[int64]
// TODO: Bulk log this // TODO: Bulk log this
var unixCreatedAt = createdAt.Unix() var unixCreatedAt = createdAt.Unix()
if common.Dev.SuperDebug { if c.Dev.SuperDebug {
log.Print("count: ", count) log.Print("count: ", count)
log.Print("name: ", name) log.Print("name: ", name)
log.Print("createdAt: ", createdAt) log.Print("createdAt: ", createdAt)
@ -557,7 +557,7 @@ func analyticsVMapToOVList(vMap map[string]map[int64]int64) (ovList []OVItem) {
return tOVList 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -567,17 +567,17 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) 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() 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 { 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) vMap, forumMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
@ -592,15 +592,15 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c
vList = append(vList, viewList) vList = append(vList, viewList)
fid, err := strconv.Atoi(ovitem.name) fid, err := strconv.Atoi(ovitem.name)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var lName string var lName string
forum, err := common.Forums.Get(fid) forum, err := c.Forums.Get(fid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
// TODO: Localise this // TODO: Localise this
lName = "Deleted Forum" lName = "Deleted Forum"
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} else { } else {
lName = forum.Name lName = forum.Name
} }
@ -610,38 +610,38 @@ func AnalyticsForums(w http.ResponseWriter, r *http.Request, user common.User) c
} }
i++ i++
} }
graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
// TODO: Sort this slice // TODO: Sort this slice
var forumItems []common.PanelAnalyticsAgentsItem var forumItems []c.PanelAnalyticsAgentsItem
for sfid, count := range forumMap { for sfid, count := range forumMap {
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var lName string var lName string
forum, err := common.Forums.Get(fid) forum, err := c.Forums.Get(fid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
// TODO: Localise this // TODO: Localise this
lName = "Deleted Forum" lName = "Deleted Forum"
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} else { } else {
lName = forum.Name lName = forum.Name
} }
forumItems = append(forumItems, common.PanelAnalyticsAgentsItem{ forumItems = append(forumItems, c.PanelAnalyticsAgentsItem{
Agent: sfid, Agent: sfid,
FriendlyAgent: lName, FriendlyAgent: lName,
Count: count, 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -651,17 +651,17 @@ func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) c
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
rows, err := qgen.NewAcc().Select("viewchunks").Columns("count, route, createdAt").Where("route != ''").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() 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 { 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) vMap, routeMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
@ -680,24 +680,24 @@ func AnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) c
} }
i++ i++
} }
graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
// TODO: Sort this slice // TODO: Sort this slice
var routeItems []common.PanelAnalyticsRoutesItem var routeItems []c.PanelAnalyticsRoutesItem
for route, count := range routeMap { for route, count := range routeMap {
routeItems = append(routeItems, common.PanelAnalyticsRoutesItem{ routeItems = append(routeItems, c.PanelAnalyticsRoutesItem{
Route: route, Route: route,
Count: count, 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) return renderTemplate("panel_analytics_routes", w, r, basePage.Header, &pi)
} }
// Trialling multi-series charts // 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -707,17 +707,17 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) c
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, browser, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() rows, err := qgen.NewAcc().Select("viewchunks_agents").Columns("count, browser, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { 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) vMap, agentMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
@ -740,28 +740,28 @@ func AnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) c
} }
i++ i++
} }
graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
// TODO: Sort this slice // TODO: Sort this slice
var agentItems []common.PanelAnalyticsAgentsItem var agentItems []c.PanelAnalyticsAgentsItem
for agent, count := range agentMap { for agent, count := range agentMap {
aAgent, ok := phrases.GetUserAgentPhrase(agent) aAgent, ok := phrases.GetUserAgentPhrase(agent)
if !ok { if !ok {
aAgent = agent aAgent = agent
} }
agentItems = append(agentItems, common.PanelAnalyticsAgentsItem{ agentItems = append(agentItems, c.PanelAnalyticsAgentsItem{
Agent: agent, Agent: agent,
FriendlyAgent: aAgent, FriendlyAgent: aAgent,
Count: count, 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -771,17 +771,17 @@ func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user common.User)
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, system, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() rows, err := qgen.NewAcc().Select("viewchunks_systems").Columns("count, system, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { 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) vMap, osMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
@ -804,28 +804,28 @@ func AnalyticsSystems(w http.ResponseWriter, r *http.Request, user common.User)
} }
i++ i++
} }
graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
// TODO: Sort this slice // TODO: Sort this slice
var systemItems []common.PanelAnalyticsAgentsItem var systemItems []c.PanelAnalyticsAgentsItem
for system, count := range osMap { for system, count := range osMap {
sSystem, ok := phrases.GetOSPhrase(system) sSystem, ok := phrases.GetOSPhrase(system)
if !ok { if !ok {
sSystem = system sSystem = system
} }
systemItems = append(systemItems, common.PanelAnalyticsAgentsItem{ systemItems = append(systemItems, c.PanelAnalyticsAgentsItem{
Agent: system, Agent: system,
FriendlyAgent: sSystem, FriendlyAgent: sSystem,
Count: count, 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) 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) basePage, ferr := PreAnalyticsDetail(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -835,17 +835,17 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user common.User
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { if err != nil {
return common.LocalError(err.Error(), w, r, user) return c.LocalError(err.Error(), w, r, user)
} }
revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange) revLabelList, labelList, viewMap := analyticsTimeRangeToLabelList(timeRange)
rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, lang, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query() rows, err := qgen.NewAcc().Select("viewchunks_langs").Columns("count, lang, createdAt").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { 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) vMap, langMap, err := analyticsRowsToDuoMap(rows, labelList, viewMap)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
@ -868,56 +868,56 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user common.User
} }
i++ i++
} }
graph := common.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList} graph := c.PanelTimeGraph{Series: vList, Labels: labelList, Legends: legendList}
common.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
// TODO: Can we de-duplicate these analytics functions further? // TODO: Can we de-duplicate these analytics functions further?
// TODO: Sort this slice // TODO: Sort this slice
var langItems []common.PanelAnalyticsAgentsItem var langItems []c.PanelAnalyticsAgentsItem
for lang, count := range langMap { for lang, count := range langMap {
lLang, ok := phrases.GetHumanLangPhrase(lang) lLang, ok := phrases.GetHumanLangPhrase(lang)
if !ok { if !ok {
lLang = lang lLang = lang
} }
langItems = append(langItems, common.PanelAnalyticsAgentsItem{ langItems = append(langItems, c.PanelAnalyticsAgentsItem{
Agent: lang, Agent: lang,
FriendlyAgent: lLang, FriendlyAgent: lLang,
Count: count, 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) 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") basePage, ferr := buildBasePage(w, r, &user, "analytics", "analytics")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
timeRange, err := analyticsTimeRange(r.FormValue("timeRange")) timeRange, err := analyticsTimeRange(r.FormValue("timeRange"))
if err != nil { 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() rows, err := qgen.NewAcc().Select("viewchunks_referrers").Columns("count, domain").DateCutoff("createdAt", timeRange.Quantity, timeRange.Unit).Query()
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
refMap, err := analyticsRowsToNameMap(rows) refMap, err := analyticsRowsToNameMap(rows)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// TODO: Sort this slice // TODO: Sort this slice
var refItems []common.PanelAnalyticsAgentsItem var refItems []c.PanelAnalyticsAgentsItem
for domain, count := range refMap { for domain, count := range refMap {
refItems = append(refItems, common.PanelAnalyticsAgentsItem{ refItems = append(refItems, c.PanelAnalyticsAgentsItem{
Agent: common.SanitiseSingleLine(domain), Agent: c.SanitiseSingleLine(domain),
Count: count, 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) return renderTemplate("panel_analytics_referrers", w, r, basePage.Header, &pi)
} }

View File

@ -7,10 +7,10 @@ import (
"path/filepath" "path/filepath"
"strconv" "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") basePage, ferr := buildBasePage(w, r, &user, "backups", "backups")
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -18,15 +18,15 @@ func Backups(w http.ResponseWriter, r *http.Request, user common.User, backupURL
if 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 // 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) var ext = filepath.Ext("./backups/" + backupURL)
if ext != ".sql" && ext != ".zip" { 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) info, err := os.Stat("./backups/" + backupURL)
if err != nil { 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)) 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 return nil
} }
var backupList []common.BackupItem var backupList []c.BackupItem
backupFiles, err := ioutil.ReadDir("./backups") backupFiles, err := ioutil.ReadDir("./backups")
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
for _, backupFile := range backupFiles { for _, backupFile := range backupFiles {
var ext = filepath.Ext(backupFile.Name()) var ext = filepath.Ext(backupFile.Name())
if ext != ".sql" { if ext != ".sql" {
continue 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) return renderTemplate("panel_backups", w, r, basePage.Header, &pi)
} }

View File

@ -3,7 +3,7 @@ package panel
import ( import (
"net/http" "net/http"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
) )
@ -12,7 +12,7 @@ var tList []interface{}
var successJSONBytes = []byte(`{"success":"1"}`) 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 // 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 { if !isJs {
http.Redirect(w, r, dest, http.StatusSeeOther) http.Redirect(w, r, dest, http.StatusSeeOther)
} else { } else {
@ -21,25 +21,25 @@ func successRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs b
return nil 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") 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 return nil
} }
// TODO: Prepend this with panel_? // TODO: Prepend this with panel_?
err := header.Theme.RunTmpl(tmplName, pi, w) err := header.Theme.RunTmpl(tmplName, pi, w)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return nil return nil
} }
func buildBasePage(w http.ResponseWriter, r *http.Request, user *common.User, titlePhrase string, zone string) (*common.BasePanelPage, common.RouteError) { func buildBasePage(w http.ResponseWriter, r *http.Request, user *c.User, titlePhrase string, zone string) (*c.BasePanelPage, c.RouteError) {
header, stats, ferr := common.PanelUserCheck(w, r, user) header, stats, ferr := c.PanelUserCheck(w, r, user)
if ferr != nil { if ferr != nil {
return nil, ferr return nil, ferr
} }
header.Title = phrases.GetTitlePhrase("panel_" + titlePhrase) header.Title = phrases.GetTitlePhrase("panel_" + titlePhrase)
return &common.BasePanelPage{header, stats, zone, common.ReportForumID}, nil return &c.BasePanelPage{header, stats, zone, c.ReportForumID}, nil
} }

View File

@ -6,11 +6,11 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "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") basePage, ferr := buildBasePage(w, r, &user, "debug", "debug")
if ferr != nil { if ferr != nil {
return ferr return ferr
@ -19,7 +19,7 @@ func Debug(w http.ResponseWriter, r *http.Request, user common.User) common.Rout
goVersion := runtime.Version() goVersion := runtime.Version()
dbVersion := qgen.Builder.DbVersion() dbVersion := qgen.Builder.DbVersion()
var uptime string var uptime string
upDuration := time.Since(common.StartTime) upDuration := time.Since(c.StartTime)
hours := int(upDuration.Hours()) hours := int(upDuration.Hours())
minutes := int(upDuration.Minutes()) minutes := int(upDuration.Minutes())
if hours > 24 { if hours > 24 {
@ -41,6 +41,6 @@ func Debug(w http.ResponseWriter, r *http.Request, user common.User) common.Rout
var memStats runtime.MemStats var memStats runtime.MemStats
runtime.ReadMemStats(&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) return renderTemplate("panel_debug", w, r, basePage.Header, &pi)
} }

View File

@ -8,21 +8,21 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "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") basePage, ferr := buildBasePage(w, r, &user, "themes", "themes")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
var pThemeList, vThemeList []*common.Theme var pThemeList, vThemeList []*c.Theme
for _, theme := range common.Themes { for _, theme := range c.Themes {
if theme.HideFromThemes { if theme.HideFromThemes {
continue 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) return renderTemplate("panel_themes", w, r, basePage.Header, &pi)
} }
func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError { func ThemesSetDefault(w http.ResponseWriter, r *http.Request, user c.User, uname string) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { 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 { 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 { 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther) http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther)
return nil 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") basePage, ferr := buildBasePage(w, r, &user, "themes_menus", "themes")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
var menuList []common.PanelMenuListItem var menuList []c.PanelMenuListItem
for mid, list := range common.Menus.GetAllMap() { for mid, list := range c.Menus.GetAllMap() {
var name = "" var name = ""
if mid == 1 { if mid == 1 {
name = phrases.GetTmplPhrase("panel_themes_menus_main") name = phrases.GetTmplPhrase("panel_themes_menus_main")
} }
menuList = append(menuList, common.PanelMenuListItem{ menuList = append(menuList, c.PanelMenuListItem{
Name: name, Name: name,
ID: mid, ID: mid,
ItemCount: len(list.List), ItemCount: len(list.List),
}) })
} }
pi := common.PanelMenuListPage{basePage, menuList} pi := c.PanelMenuListPage{basePage, menuList}
return renderTemplate("panel_themes_menus", w, r, basePage.Header, &pi) 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? // TODO: Something like Menu #1 for the title?
basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes") basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { 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") basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js")
mid, err := strconv.Atoi(smid) mid, err := strconv.Atoi(smid)
if err != nil { 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 { if err == sql.ErrNoRows {
return common.NotFound(w, r, basePage.Header) return c.NotFound(w, r, basePage.Header)
} else if err != nil { } 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 { 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}}")), item.TmplName: menuHold.Parse(item.Name, []byte("{{.Name}}")),
} }
var renderBuffer [][]byte var renderBuffer [][]byte
@ -132,39 +132,39 @@ func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user common.User, s
menuList = append(menuList, item) 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) 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? // TODO: Something like Menu #1 for the title?
basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes") basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
itemID, err := strconv.Atoi(sitemID) itemID, err := strconv.Atoi(sitemID)
if err != nil { 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 { if err == sql.ErrNoRows {
return common.NotFound(w, r, basePage.Header) return c.NotFound(w, r, basePage.Header)
} else if err != nil { } 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) 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 { 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.Name = getItem("name")
menuItem.HTMLID = getItem("htmlid") menuItem.HTMLID = getItem("htmlid")
@ -208,113 +208,113 @@ func themesMenuItemSetters(r *http.Request, menuItem common.MenuItem) common.Men
return menuItem return menuItem
} }
func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
itemID, err := strconv.Atoi(sitemID) itemID, err := strconv.Atoi(sitemID)
if err != nil { 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 { 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 { } 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 = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
menuItem = themesMenuItemSetters(r, menuItem) menuItem = themesMenuItemSetters(r, menuItem)
err = menuItem.Commit() err = menuItem.Commit()
if err != nil { 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) 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 { func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
smenuID := r.PostFormValue("mid") smenuID := r.PostFormValue("mid")
if smenuID == "" { 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) menuID, err := strconv.Atoi(smenuID)
if err != nil { 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) menuItem = themesMenuItemSetters(r, menuItem)
itemID, err := menuItem.Create() itemID, err := menuItem.Create()
if err != nil { 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) 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 { func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
itemID, err := strconv.Atoi(sitemID) itemID, err := strconv.Atoi(sitemID)
if err != nil { 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 { 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 { } 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 = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
err = menuItem.Delete() err = menuItem.Delete()
if err != nil { 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) return successRedirect("/panel/themes/menus/", w, r, isJs)
} }
func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError { func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user c.User, smid string) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
mid, err := strconv.Atoi(smid) mid, err := strconv.Atoi(smid)
if err != nil { 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 { 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 { } 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"), "{"), "}") 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, ",") { for index, smiid := range strings.Split(sitems, ",") {
miid, err := strconv.Atoi(smiid) miid, err := strconv.Atoi(smiid)
if err != nil { 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 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) 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") basePage, ferr := buildBasePage(w, r, &user, "themes_widgets", "themes")
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
basePage.Header.AddScript("widgets.js") basePage.Header.AddScript("widgets.js")
var docks = make(map[string][]common.WidgetEdit) var docks = make(map[string][]c.WidgetEdit)
for _, name := range common.GetDockList() { for _, name := range c.GetDockList() {
if name == "leftOfNav" || name == "rightOfNav" { if name == "leftOfNav" || name == "rightOfNav" {
continue continue
} }
var widgets []common.WidgetEdit var widgets []c.WidgetEdit
for _, widget := range common.GetDock(name) { for _, widget := range c.GetDock(name) {
var data = make(map[string]string) var data = make(map[string]string)
err := json.Unmarshal([]byte(widget.RawBody), &data) err := json.Unmarshal([]byte(widget.RawBody), &data)
if err != nil { if err != nil {
return 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 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) 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) var data = make(map[string]string)
widget.Enabled = (r.FormValue("wenabled") == "1") widget.Enabled = (r.FormValue("wenabled") == "1")
widget.Location = r.FormValue("wlocation") widget.Location = r.FormValue("wlocation")
@ -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.") return nil, errors.New("You need to specify a location for this widget.")
} }
widget.Side = r.FormValue("wside") 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.") 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 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 // 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") //fmt.Println("in ThemesWidgetsEditSubmit")
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
wid, err := strconv.Atoi(swid) wid, err := strconv.Atoi(swid)
if err != nil { 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 { if err == sql.ErrNoRows {
return common.NotFoundJSQ(w, r, nil, isJs) return c.NotFoundJSQ(w, r, nil, isJs)
} else if err != nil { } else if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs) return c.InternalErrorJSQ(err, w, r, isJs)
} }
ewidget, err := widgetsParseInputs(r, widget.Copy()) ewidget, err := widgetsParseInputs(r, widget.Copy())
if err != nil { if err != nil {
return common.LocalErrorJSQ(err.Error(), w, r, user, isJs) return c.LocalErrorJSQ(err.Error(), w, r, user, isJs)
} }
err = ewidget.Commit() err = ewidget.Commit()
if err != nil { 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) return successRedirect("/panel/themes/widgets/", w, r, isJs)
} }
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget // ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
//fmt.Println("in ThemesWidgetsCreateSubmit") //fmt.Println("in ThemesWidgetsCreateSubmit")
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ManageThemes { 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 { if err != nil {
return common.LocalErrorJSQ(err.Error(), w, r, user, isJs) return c.LocalErrorJSQ(err.Error(), w, r, user, isJs)
} }
err = ewidget.Create() err = ewidget.Create()
if err != nil { 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) return successRedirect("/panel/themes/widgets/", w, r, isJs)
} }
func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError { func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, swid string) c.RouteError {
_, ferr := common.SimplePanelUserCheck(w, r, &user) _, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
isJs := (r.PostFormValue("js") == "1") isJs := (r.PostFormValue("js") == "1")
if !user.Perms.ManageThemes { if !user.Perms.ManageThemes {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
wid, err := strconv.Atoi(swid) wid, err := strconv.Atoi(swid)
if err != nil { 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 { if err == sql.ErrNoRows {
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
err = widget.Delete() err = widget.Delete()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
return successRedirect("/panel/themes/widgets/", w, r, isJs) return successRedirect("/panel/themes/widgets/", w, r, isJs)

View File

@ -6,85 +6,85 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/query_gen" "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) pollID, err := strconv.Atoi(sPollID)
if err != nil { 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 { 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 { } 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" { if poll.ParentTable == "replies" {
reply, err := common.Rstore.Get(poll.ParentID) reply, err := c.Rstore.Get(poll.ParentID)
if err == sql.ErrNoRows { 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 { } 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" { } else if poll.ParentTable == "topics" {
topic, err = common.Topics.Get(poll.ParentID) topic, err = c.Topics.Get(poll.ParentID)
} else { } 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 { 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 { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// TODO: Add hooks to make use of headerLite // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic { 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")) optionIndex, err := strconv.Atoi(r.PostFormValue("poll_option_input"))
if err != nil { 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) err = poll.CastVote(optionIndex, user.ID, user.LastIP)
if err != nil { 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) http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID), http.StatusSeeOther)
return nil 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") //log.Print("in PollResults")
pollID, err := strconv.Atoi(sPollID) pollID, err := strconv.Atoi(sPollID)
if err != nil { 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 { 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 { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// TODO: Abstract this // TODO: Abstract this
rows, err := qgen.NewAcc().Select("polls_options").Columns("votes").Where("pollID = ?").Orderby("option ASC").Query(poll.ID) rows, err := qgen.NewAcc().Select("polls_options").Columns("votes").Where("pollID = ?").Orderby("option ASC").Query(poll.ID)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
defer rows.Close() defer rows.Close()
@ -93,13 +93,13 @@ func PollResults(w http.ResponseWriter, r *http.Request, user common.User, sPoll
var votes int var votes int
err := rows.Scan(&votes) err := rows.Scan(&votes)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
optionList += strconv.Itoa(votes) + "," optionList += strconv.Itoa(votes) + ","
} }
err = rows.Err() err = rows.Err()
if err != nil { 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 // TODO: Implement a version of this which doesn't rely so much on sequential order

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
) )
@ -19,7 +19,7 @@ var profileStmts ProfileStmts
// TODO: Move these DbInits into some sort of abstraction // TODO: Move these DbInits into some sort of abstraction
func init() { func init() {
common.DbInits.Add(func(acc *qgen.Accumulator) error { c.DbInits.Add(func(acc *qgen.Accumulator) error {
profileStmts = ProfileStmts{ 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 = ?", "", ""), 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? // 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? // TODO: Preload this?
header.AddSheet(header.Theme.Name + "/profile.css") header.AddSheet(header.Theme.Name + "/profile.css")
if user.Loggedin { if user.Loggedin {
@ -39,57 +39,57 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, heade
var replyCreatedAt time.Time var replyCreatedAt time.Time
var replyContent, replyCreatedByName, replyAvatar, replyMicroAvatar, replyTag, replyClassName string var replyContent, replyCreatedByName, replyAvatar, replyMicroAvatar, replyTag, replyClassName string
var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyLines, replyGroup int 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? // TODO: Do a 301 if it's the wrong username? Do a canonical too?
_, pid, err := ParseSEOURL(r.URL.Path[len("/user/"):]) _, pid, err := ParseSEOURL(r.URL.Path[len("/user/"):])
if err != nil { 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 { if pid == user.ID {
user.IsMod = true user.IsMod = true
puser = &user puser = &user
} else { } else {
// Fetch the user data // Fetch the user data
// TODO: Add a shared function for checking for ErrNoRows and internal erroring if it's not that case? // 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 { if err == sql.ErrNoRows {
return common.NotFound(w, r, header) return c.NotFound(w, r, header)
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
puser.Init() puser.Init()
} }
header.Title = phrases.GetTitlePhrasef("profile", puser.Name) 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.. // Get the replies..
rows, err := profileStmts.getReplies.Query(puser.ID) rows, err := profileStmts.getReplies.Query(puser.ID)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup) err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup)
if err != nil { 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
replyLines = strings.Count(replyContent, "\n") replyLines = strings.Count(replyContent, "\n")
if group.IsMod { if group.IsMod {
replyClassName = common.Config.StaffCSS replyClassName = c.Config.StaffCSS
} else { } else {
replyClassName = "" replyClassName = ""
} }
replyAvatar, replyMicroAvatar = common.BuildAvatar(replyCreatedBy, replyAvatar) replyAvatar, replyMicroAvatar = c.BuildAvatar(replyCreatedBy, replyAvatar)
if group.Tag != "" { if group.Tag != "" {
replyTag = group.Tag replyTag = group.Tag
@ -103,18 +103,18 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user common.User, heade
replyLikeCount := 0 replyLikeCount := 0
// TODO: Add a hook here // 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() err = rows.Err()
if err != nil { 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 // 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 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) return renderTemplate("profile", w, r, header, ppage)
} }

View File

@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/counters"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/query_gen"
@ -23,7 +23,7 @@ var replyStmts ReplyStmts
// TODO: Move this statement somewhere else // TODO: Move this statement somewhere else
func init() { func init() {
common.DbInits.Add(func(acc *qgen.Accumulator) error { c.DbInits.Add(func(acc *qgen.Accumulator) error {
replyStmts = ReplyStmts{ replyStmts = ReplyStmts{
// TODO: Less race-y attachment count updates // TODO: Less race-y attachment count updates
updateAttachs: acc.Update("replies").Set("attachCount = ?").Where("rid = ?").Prepare(), updateAttachs: acc.Update("replies").Set("attachCount = ?").Where("rid = ?").Prepare(),
@ -37,43 +37,43 @@ type JsonReply struct {
Content string 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 // TODO: Use this
js := r.FormValue("js") == "1" js := r.FormValue("js") == "1"
tid, err := strconv.Atoi(r.PostFormValue("tid")) tid, err := strconv.Atoi(r.PostFormValue("tid"))
if err != nil { 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 { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.CreateReply { 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 { 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 // 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 { 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 { 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 // Handle the file attachments
@ -89,26 +89,26 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User)
var maxPollOptions = 10 var maxPollOptions = 10
var pollInputItems = make(map[int]string) var pollInputItems = make(map[int]string)
for key, values := range r.Form { for key, values := range r.Form {
//common.DebugDetail("key: ", key) //c.DebugDetail("key: ", key)
//common.DebugDetailf("values: %+v\n", values) //c.DebugDetailf("values: %+v\n", values)
for _, value := range values { for _, value := range values {
if strings.HasPrefix(key, "pollinputitem[") { if strings.HasPrefix(key, "pollinputitem[") {
halves := strings.Split(key, "[") halves := strings.Split(key, "[")
if len(halves) != 2 { 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], "]") halves[1] = strings.TrimSuffix(halves[1], "]")
index, err := strconv.Atoi(halves[1]) index, err := strconv.Atoi(halves[1])
if err != nil { 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 // 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] _, exists := pollInputItems[index]
// TODO: Should we use SanitiseBody instead to keep the newlines? // TODO: Should we use SanitiseBody instead to keep the newlines?
if !exists && len(common.SanitiseSingleLine(value)) != 0 { if !exists && len(c.SanitiseSingleLine(value)) != 0 {
pollInputItems[index] = common.SanitiseSingleLine(value) pollInputItems[index] = c.SanitiseSingleLine(value)
if len(pollInputItems) >= maxPollOptions { if len(pollInputItems) >= maxPollOptions {
break break
} }
@ -124,40 +124,40 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User)
} }
pollType := 0 // Basic single choice pollType := 0 // Basic single choice
_, err := common.Polls.Create(reply, pollType, seqPollInputItems) _, err := c.Polls.Create(reply, pollType, seqPollInputItems)
if err != nil { 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 { 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 { 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) err = user.IncreasePostStats(wcount, false)
if err != nil { 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 { 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 { } 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) rows, err := replyStmts.createReplyPaging.Query(reply.ID, topic.ID)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
defer rows.Close() defer rows.Close()
@ -166,16 +166,16 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User)
var rid int var rid int
err := rows.Scan(&rid) err := rows.Scan(&rid)
if err != nil { if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
rids = append(rids, rid) rids = append(rids, rid)
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
if len(rids) == 0 { if len(rids) == 0 {
return common.NotFoundJSQ(w, r, nil, js) return c.NotFoundJSQ(w, r, nil, js)
} }
if page > 1 { 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 { } else if len(rids) == 2 && rids[1] == reply.ID {
offset = 2 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() counters.PostCounter.Bump()
@ -196,9 +196,9 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user common.User)
prid, _ := strconv.Atoi(r.FormValue("prid")) prid, _ := strconv.Atoi(r.FormValue("prid"))
if js && (prid == 0 || rids[0] == 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 { if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
w.Write(outBytes) w.Write(outBytes)
} else { } 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: 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 // 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") js := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } else if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
topic, err := reply.Topic() topic, err := reply.Topic()
if err == sql.ErrNoRows { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.EditReply { 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 { 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")) err = reply.SetPost(r.PostFormValue("edit_item"))
if err == sql.ErrNoRows { 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 { } 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? // TODO: Avoid the load to get this faster?
reply, err = common.Rstore.Get(rid) reply, err = c.Rstore.Get(rid)
if err == sql.ErrNoRows { 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 { } 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) 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 { if !js {
http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther) http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
} else { } 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 { if err != nil {
return common.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
w.Write(outBytes) w.Write(outBytes)
} }
@ -281,39 +281,39 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, s
// TODO: Refactor this // TODO: Refactor this
// TODO: Disable stat updates in posts handled by plugin_guilds // 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") isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.DeleteReply { if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
return common.NoPermissionsJSQ(w, r, user, isJs) return c.NoPermissionsJSQ(w, r, user, isJs)
} }
err = reply.Delete() err = reply.Delete()
if err != nil { 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) 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 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 { if !isJs {
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther) http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
} else { } 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...? // ? - 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 { if err == nil {
wcount := common.WordCount(reply.Content) wcount := c.WordCount(reply.Content)
err = replyCreator.DecreasePostStats(wcount, false) err = replyCreator.DecreasePostStats(wcount, false)
if err != nil { if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs) return c.InternalErrorJSQ(err, w, r, isJs)
} }
} else if err != sql.ErrNoRows { } 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 { if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs) return c.InternalErrorJSQ(err, w, r, isJs)
} }
return nil 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: 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: Enforce the max request limit on all of this topic's attachments
// TODO: Test this route // 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) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.EditReply || !user.Perms.UploadFiles { 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 { if topic.IsClosed && !user.Perms.CloseTopic {
return common.NoPermissionsJS(w, r, user) return c.NoPermissionsJS(w, r, user)
} }
// Handle the file attachments // Handle the file attachments
@ -386,7 +386,7 @@ func AddAttachToReplySubmit(w http.ResponseWriter, r *http.Request, user common.
return rerr return rerr
} }
if len(pathMap) == 0 { 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) 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 // 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) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.EditReply { 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 { if topic.IsClosed && !user.Perms.CloseTopic {
return common.NoPermissionsJS(w, r, user) return c.NoPermissionsJS(w, r, user)
} }
saids := strings.Split(r.PostFormValue("aids"), ",") saids := strings.Split(r.PostFormValue("aids"), ",")
if len(saids) == 0 { if len(saids) == 0 {
return common.LocalErrorJS("No aids provided", w, r) return c.LocalErrorJS("No aids provided", w, r)
} }
for _, said := range saids { for _, said := range saids {
aid, err := strconv.Atoi(said) aid, err := strconv.Atoi(said)
if err != nil { 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) rerr := deleteAttachment(w, r, user, aid, true)
if rerr != nil { 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? // 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 { 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")) uid, err := strconv.Atoi(r.PostFormValue("uid"))
if err != nil { 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 { 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 { } 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 // 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 { 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 // ! Be careful about leaking per-route permission state with &user
alert := common.Alert{0, user.ID, profileOwner.ID, "reply", "user", profileOwner.ID, &user} alert := c.Alert{0, user.ID, profileOwner.ID, "reply", "user", profileOwner.ID, &user}
err = common.AddActivityAndNotifyTarget(alert) err = c.AddActivityAndNotifyTarget(alert)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
counters.PostCounter.Bump() counters.PostCounter.Bump()
@ -498,34 +498,34 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user commo
return nil 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") isJs := (r.PostFormValue("js") == "1")
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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? // ? Does the admin understand that this group perm affects this?
if user.ID != creator.ID && !user.Perms.EditReply { 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")) err = reply.SetBody(r.PostFormValue("edit_item"))
if err != nil { if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs) return c.InternalErrorJSQ(err, w, r, isJs)
} }
if !isJs { if !isJs {
@ -536,35 +536,35 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.
return nil 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") isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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 { 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() err = reply.Delete()
if err != nil { 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 { if !isJs {
//http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther) //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 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") isJs := (r.PostFormValue("isJs") == "1")
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { 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 { 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 { } 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 { 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 { } 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 // 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 { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.LikeItem { 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 { 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 { 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 { } else if err != nil {
return common.InternalErrorJSQ(err, w, r, isJs) return c.InternalErrorJSQ(err, w, r, isJs)
} }
err = reply.Like(user.ID) err = reply.Like(user.ID)
if err == common.ErrAlreadyLiked { if err == c.ErrAlreadyLiked {
return common.LocalErrorJSQ("You've already liked this!", w, r, user, isJs) return c.LocalErrorJSQ("You've already liked this!", w, r, user, isJs)
} else if err != nil { } 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 // ! Be careful about leaking per-route permission state with &user
alert := common.Alert{0, user.ID, reply.CreatedBy, "like", "post", rid, &user} alert := c.Alert{0, user.ID, reply.CreatedBy, "like", "post", rid, &user}
err = common.AddActivityAndNotifyTarget(alert) err = c.AddActivityAndNotifyTarget(alert)
if err != nil { 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) skip, rerr := lite.Hooks.VhookSkippable("action_end_like_reply", reply.ID, &user)

View File

@ -5,12 +5,12 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/counters"
) )
func ReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { func ReportSubmit(w http.ResponseWriter, r *http.Request, user c.User, sitemID string) c.RouteError {
headerLite, ferr := common.SimpleUserCheck(w, r, &user) headerLite, ferr := c.SimpleUserCheck(w, r, &user)
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
@ -18,51 +18,51 @@ func ReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, site
itemID, err := strconv.Atoi(sitemID) itemID, err := strconv.Atoi(sitemID)
if err != nil { if err != nil {
return common.LocalError("Bad ID", w, r, user) return c.LocalError("Bad ID", w, r, user)
} }
itemType := r.FormValue("type") itemType := r.FormValue("type")
// TODO: Localise these titles and bodies // TODO: Localise these titles and bodies
var title, content string var title, content string
if itemType == "reply" { if itemType == "reply" {
reply, err := common.Rstore.Get(itemID) reply, err := c.Rstore.Get(itemID)
if err == sql.ErrNoRows { 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 { } 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 { 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 { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
title = "Reply: " + topic.Title title = "Reply: " + topic.Title
content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(itemID) content = reply.Content + "\n\nOriginal Post: #rid-" + strconv.Itoa(itemID)
} else if itemType == "user-reply" { } else if itemType == "user-reply" {
userReply, err := common.Prstore.Get(itemID) userReply, err := c.Prstore.Get(itemID)
if err == sql.ErrNoRows { 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 { } 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 { 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 { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
title = "Profile: " + profileOwner.Name title = "Profile: " + profileOwner.Name
content = userReply.Content + "\n\nOriginal Post: @" + strconv.Itoa(userReply.ParentID) content = userReply.Content + "\n\nOriginal Post: @" + strconv.Itoa(userReply.ParentID)
} else if itemType == "topic" { } else if itemType == "topic" {
topic, err := common.Topics.Get(itemID) topic, err := c.Topics.Get(itemID)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return common.NotFound(w, r, nil) return c.NotFound(w, r, nil)
} else if err != nil { } else if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
title = "Topic: " + topic.Title title = "Topic: " + topic.Title
content = topic.Content + "\n\nOriginal Post: #tid-" + strconv.Itoa(itemID) 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 // 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 // TODO: Repost attachments in the reports forum, so that the mods can see them
_, err = common.Reports.Create(title, content, &user, itemType, itemID) _, err = c.Reports.Create(title, content, &user, itemType, itemID)
if err == common.ErrAlreadyReported { if err == c.ErrAlreadyReported {
return common.LocalError("Someone has already reported this!", w, r, user) return c.LocalError("Someone has already reported this!", w, r, user)
} }
counters.PostCounter.Bump() counters.PostCounter.Bump()

File diff suppressed because it is too large Load Diff

View File

@ -7,37 +7,37 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
) )
func wsTopicList(topicList []*common.TopicsRow, lastPage int) *common.WsTopicList { func wsTopicList(topicList []*c.TopicsRow, lastPage int) *c.WsTopicList {
wsTopicList := make([]*common.WsTopicsRow, len(topicList)) wsTopicList := make([]*c.WsTopicsRow, len(topicList))
for i, topicRow := range topicList { for i, topicRow := range topicList {
wsTopicList[i] = topicRow.WebSockets() 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", "") 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") return TopicListCommon(w, r, user, header, "mostviewed", "most-viewed")
} }
// TODO: Implement search // 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.Title = phrases.GetTitlePhrase("topics")
header.Zone = "topics" header.Zone = "topics"
header.Path = "/topics/" header.Path = "/topics/"
header.MetaDesc = header.Settings["meta_desc"].(string) header.MetaDesc = header.Settings["meta_desc"].(string)
group, err := common.Groups.Get(user.Group) group, err := c.Groups.Get(user.Group)
if err != nil { if err != nil {
log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) log.Printf("Group #%d doesn't exist despite being used by c.User #%d", user.Group, user.ID)
return common.LocalError("Something weird happened", w, r, user) return c.LocalError("Something weird happened", w, r, user)
} }
// Get the current page // 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, ",") { for _, sfid := range strings.Split(sfids, ",") {
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { if err != nil {
return common.LocalError("Invalid fid", w, r, user) return c.LocalError("Invalid fid", w, r, user)
} }
fids = append(fids, fid) fids = append(fids, fid)
} }
if len(fids) == 1 { if len(fids) == 1 {
forum, err := common.Forums.Get(fids[0]) forum, err := c.Forums.Get(fids[0])
if err != nil { 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.Title = forum.Name
header.ZoneID = forum.ID 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: Allow multiple forums in searches
// TODO: Simplify this block after initially landing search // TODO: Simplify this block after initially landing search
var topicList []*common.TopicsRow var topicList []*c.TopicsRow
var forumList []common.Forum var forumList []c.Forum
var paginator common.Paginator var paginator c.Paginator
q := r.FormValue("q") q := r.FormValue("q")
if q != "" && common.RepliesSearch != nil { if q != "" && c.RepliesSearch != nil {
var canSee []int var canSee []int
if user.IsSuperAdmin { if user.IsSuperAdmin {
canSee, err = common.Forums.GetAllVisibleIDs() canSee, err = c.Forums.GetAllVisibleIDs()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
} else { } else {
canSee = group.CanSee canSee = group.CanSee
@ -91,7 +91,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h
} }
for _, fid := range fids { for _, fid := range fids {
if inSlice(canSee, fid) { if inSlice(canSee, fid) {
forum := common.Forums.DirtyGet(fid) forum := c.Forums.DirtyGet(fid)
if forum.Name != "" && forum.Active && (forum.ParentType == "" || forum.ParentType == "forum") { if forum.Name != "" && forum.Active && (forum.ParentType == "" || forum.ParentType == "forum") {
// TODO: Add a hook here for plugin_guilds? // TODO: Add a hook here for plugin_guilds?
cfids = append(cfids, fid) cfids = append(cfids, fid)
@ -102,16 +102,16 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user common.User, h
cfids = canSee cfids = canSee
} }
tids, err := common.RepliesSearch.Query(q, cfids) tids, err := c.RepliesSearch.Query(q, cfids)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
//fmt.Printf("tids %+v\n", tids) //fmt.Printf("tids %+v\n", tids)
// TODO: Handle the case where there aren't any items... // TODO: Handle the case where there aren't any items...
// TODO: Add a BulkGet method which returns a slice? // TODO: Add a BulkGet method which returns a slice?
tMap, err := common.Topics.BulkGetMap(tids) tMap, err := c.Topics.BulkGetMap(tids)
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
var reqUserList = make(map[int]bool) var reqUserList = make(map[int]bool)
for _, topic := range tMap { 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? // TODO: What if a user is deleted via the Control Panel?
//fmt.Printf("idSlice %+v\n", idSlice) //fmt.Printf("idSlice %+v\n", idSlice)
userList, err := common.Users.BulkGetMap(idSlice) userList, err := c.Users.BulkGetMap(idSlice)
if err != nil { if err != nil {
return nil // TODO: Implement this! return nil // TODO: Implement this!
} }
// TODO: De-dupe this logic in common/topic_list.go? // TODO: De-dupe this logic in common/topic_list.go?
for _, topic := range topicList { 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. // 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.ForumName = forum.Name
topic.ForumLink = forum.Link topic.ForumLink = forum.Link
// TODO: Create a specialised function with a bit less overhead for getting the last page for a post count // 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.LastPage = lastPage
topic.Creator = userList[topic.CreatedBy] topic.Creator = userList[topic.CreatedBy]
topic.LastUser = userList[topic.LastReplyBy] 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" { if r.FormValue("js") == "1" {
outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON() outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
w.Write(outBytes) w.Write(outBytes)
return nil return nil
} }
header.Title = phrases.GetTitlePhrase("topics_search") 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) return renderTemplate("topics", w, r, header, pi)
} }
// TODO: Pass a struct back rather than passing back so many variables // TODO: Pass a struct back rather than passing back so many variables
if user.IsSuperAdmin { if user.IsSuperAdmin {
topicList, forumList, paginator, err = common.TopicList.GetList(page, tsorder, fids) topicList, forumList, paginator, err = c.TopicList.GetList(page, tsorder, fids)
} else { } 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 { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// ! Need an inline error not a page level error // ! Need an inline error not a page level error
if len(topicList) == 0 { if len(topicList) == 0 {
return common.NotFound(w, r, header) return c.NotFound(w, r, header)
} }
// TODO: Reduce the amount of boilerplate here // TODO: Reduce the amount of boilerplate here
if r.FormValue("js") == "1" { if r.FormValue("js") == "1" {
outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON() outBytes, err := wsTopicList(topicList, paginator.LastPage).MarshalJSON()
if err != nil { if err != nil {
return common.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
w.Write(outBytes) w.Write(outBytes)
return nil 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) return renderTemplate("topics", w, r, header, pi)
} }