Experiment with eliminating allocations.

Encode png images as pngs rather than turning them into jpgs.
Shorten things to eliminate bytes and boilerplate.
Remove some old code.
This commit is contained in:
Azareal 2019-10-28 17:46:14 +10:00
parent d9cffb2c5f
commit eb49dde076
15 changed files with 153 additions and 143 deletions

View File

@ -48,16 +48,17 @@ type DefaultAttachmentStore struct {
} }
func NewDefaultAttachmentStore(acc *qgen.Accumulator) (*DefaultAttachmentStore, error) { func NewDefaultAttachmentStore(acc *qgen.Accumulator) (*DefaultAttachmentStore, error) {
a := "attachments"
return &DefaultAttachmentStore{ return &DefaultAttachmentStore{
get: acc.Select("attachments").Columns("originID, sectionID, uploadedBy, path, extra").Where("attachID = ?").Prepare(), get: acc.Select(a).Columns("originID, sectionID, uploadedBy, path, extra").Where("attachID = ?").Prepare(),
getByObj: acc.Select("attachments").Columns("attachID, sectionID, uploadedBy, path, extra").Where("originTable = ? AND originID = ?").Prepare(), getByObj: acc.Select(a).Columns("attachID, sectionID, uploadedBy, path, extra").Where("originTable = ? AND originID = ?").Prepare(),
add: acc.Insert("attachments").Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path, extra").Fields("?,?,?,?,?,?,?").Prepare(), add: acc.Insert(a).Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path, extra").Fields("?,?,?,?,?,?,?").Prepare(),
count: acc.Count("attachments").Prepare(), count: acc.Count(a).Prepare(),
countIn: acc.Count("attachments").Where("originTable = ? and originID = ?").Prepare(), countIn: acc.Count(a).Where("originTable = ? and originID = ?").Prepare(),
countInPath: acc.Count("attachments").Where("path = ?").Prepare(), countInPath: acc.Count(a).Where("path = ?").Prepare(),
move: acc.Update("attachments").Set("sectionID = ?").Where("originID = ? AND originTable = ?").Prepare(), move: acc.Update(a).Set("sectionID = ?").Where("originID = ? AND originTable = ?").Prepare(),
moveByExtra: acc.Update("attachments").Set("sectionID = ?").Where("originTable = ? AND extra = ?").Prepare(), moveByExtra: acc.Update(a).Set("sectionID = ?").Where("originTable = ? AND extra = ?").Prepare(),
delete: acc.Delete("attachments").Where("attachID = ?").Prepare(), delete: acc.Delete(a).Where("attachID = ?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }
@ -93,7 +94,7 @@ func (s *DefaultAttachmentStore) BulkMiniGetList(originTable string, ids []int)
amap = make(map[int][]*MiniAttachment) amap = make(map[int][]*MiniAttachment)
var buffer []*MiniAttachment var buffer []*MiniAttachment
var currentID int var currentID int
rows, err := qgen.NewAcc().Select("attachments").Columns("attachID,sectionID,originID,uploadedBy,path").Where("originTable = ?").In("originID", ids).Orderby("originID ASC").Query(originTable) rows, err := qgen.NewAcc().Select("attachments").Columns("attachID,sectionID,originID,uploadedBy,path").Where("originTable=?").In("originID", ids).Orderby("originID ASC").Query(originTable)
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
a := &MiniAttachment{} a := &MiniAttachment{}

View File

@ -32,10 +32,11 @@ type SQLModLogStore struct {
} }
func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) { func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error) {
ml := "moderation_logs"
return &SQLModLogStore{ return &SQLModLogStore{
create: acc.Insert("moderation_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(), create: acc.Insert(ml).Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(),
count: acc.Count("moderation_logs").Prepare(), count: acc.Count(ml).Prepare(),
getOffset: acc.Select("moderation_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Prepare(), getOffset: acc.Select(ml).Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }
@ -83,10 +84,11 @@ type SQLAdminLogStore struct {
} }
func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) { func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error) {
al := "administration_logs"
return &SQLAdminLogStore{ return &SQLAdminLogStore{
create: acc.Insert("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(), create: acc.Insert(al).Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Fields("?,?,?,?,?,UTC_TIMESTAMP()").Prepare(),
count: acc.Count("administration_logs").Prepare(), count: acc.Count(al).Prepare(),
getOffset: acc.Select("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Prepare(), getOffset: acc.Select(al).Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }

View File

@ -30,15 +30,15 @@ func (list PluginList) Add(plugin *Plugin) {
list[plugin.UName] = plugin list[plugin.UName] = plugin
} }
func buildPlugin(plugin *Plugin) { func buildPlugin(pl *Plugin) {
plugin.Installable = (plugin.Install != nil) pl.Installable = (pl.Install != nil)
/* /*
The Active field should never be altered by a plugin. It's used internally by the software to determine whether an admin has enabled a plugin or not and whether to run it. This will be overwritten by the user's preference. The Active field should never be altered by a plugin. It's used internally by the software to determine whether an admin has enabled a plugin or not and whether to run it. This will be overwritten by the user's preference.
*/ */
plugin.Active = false pl.Active = false
plugin.Installed = false pl.Installed = false
plugin.Hooks = make(map[string]int) pl.Hooks = make(map[string]int)
plugin.Data = nil pl.Data = nil
} }
var hookTableBox atomic.Value var hookTableBox atomic.Value
@ -391,13 +391,14 @@ var extendStmts ExtendStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
pl := "plugins"
extendStmts = ExtendStmts{ extendStmts = ExtendStmts{
getPlugins: acc.Select("plugins").Columns("uname, active, installed").Prepare(), getPlugins: acc.Select(pl).Columns("uname, active, installed").Prepare(),
isActive: acc.Select("plugins").Columns("active").Where("uname = ?").Prepare(), isActive: acc.Select(pl).Columns("active").Where("uname = ?").Prepare(),
setActive: acc.Update("plugins").Set("active = ?").Where("uname = ?").Prepare(), setActive: acc.Update(pl).Set("active = ?").Where("uname = ?").Prepare(),
setInstalled: acc.Update("plugins").Set("installed = ?").Where("uname = ?").Prepare(), setInstalled: acc.Update(pl).Set("installed = ?").Where("uname = ?").Prepare(),
add: acc.Insert("plugins").Columns("uname, active, installed").Fields("?,?,?").Prepare(), add: acc.Insert(pl).Columns("uname, active, installed").Fields("?,?,?").Prepare(),
} }
return acc.FirstError() return acc.FirstError()
}) })
@ -564,8 +565,7 @@ func InitPlugins() {
// ? - Are the following functions racey? // ? - Are the following functions racey?
func RunTaskHook(name string) error { func RunTaskHook(name string) error {
for _, hook := range taskHooks[name] { for _, hook := range taskHooks[name] {
err := hook() if err := hook(); err != nil {
if err != nil {
return err return err
} }
} }

View File

@ -110,8 +110,8 @@ func PermmapToQuery(permmap map[string]*ForumPerms, fid int) error {
} }
addForumPermsToForumAdminsTx, err := qgen.Builder.SimpleInsertSelectTx(tx, addForumPermsToForumAdminsTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DBInsert{"forums_permissions", "gid,fid,preset,permissions", ""},
qgen.DBSelect{"users_groups", "gid, ?, '', ?", "is_admin = 1", "", ""}, qgen.DBSelect{"users_groups", "gid,?,'',?", "is_admin = 1", "", ""},
) )
if err != nil { if err != nil {
return err return err
@ -127,8 +127,8 @@ func PermmapToQuery(permmap map[string]*ForumPerms, fid int) error {
} }
addForumPermsToForumStaffTx, err := qgen.Builder.SimpleInsertSelectTx(tx, addForumPermsToForumStaffTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DBInsert{"forums_permissions", "gid,fid,preset,permissions", ""},
qgen.DBSelect{"users_groups", "gid, ?, '', ?", "is_admin = 0 AND is_mod = 1", "", ""}, qgen.DBSelect{"users_groups", "gid,?,'',?", "is_admin = 0 AND is_mod = 1", "", ""},
) )
if err != nil { if err != nil {
return err return err
@ -144,8 +144,8 @@ func PermmapToQuery(permmap map[string]*ForumPerms, fid int) error {
} }
addForumPermsToForumMembersTx, err := qgen.Builder.SimpleInsertSelectTx(tx, addForumPermsToForumMembersTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
qgen.DBInsert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DBInsert{"forums_permissions", "gid,fid,preset,permissions", ""},
qgen.DBSelect{"users_groups", "gid, ?, '', ?", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""}, qgen.DBSelect{"users_groups", "gid,?,'',?", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
) )
if err != nil { if err != nil {
return err return err

View File

@ -76,17 +76,18 @@ type MemoryForumStore struct {
// NewMemoryForumStore gives you a new instance of MemoryForumStore // NewMemoryForumStore gives you a new instance of MemoryForumStore
func NewMemoryForumStore() (*MemoryForumStore, error) { func NewMemoryForumStore() (*MemoryForumStore, error) {
acc := qgen.NewAcc() acc := qgen.NewAcc()
f := "forums"
// TODO: Do a proper delete // TODO: Do a proper delete
return &MemoryForumStore{ return &MemoryForumStore{
get: acc.Select("forums").Columns("name, desc, tmpl, active, order, preset, parentID, parentType, topicCount, lastTopicID, lastReplyerID").Where("fid = ?").Prepare(), get: acc.Select(f).Columns("name, desc, tmpl, active, order, preset, parentID, parentType, topicCount, lastTopicID, lastReplyerID").Where("fid = ?").Prepare(),
getAll: acc.Select("forums").Columns("fid, name, desc, tmpl, active, order, preset, parentID, parentType, topicCount, lastTopicID, lastReplyerID").Orderby("order ASC, fid ASC").Prepare(), getAll: acc.Select(f).Columns("fid, name, desc, tmpl, active, order, preset, parentID, parentType, topicCount, lastTopicID, lastReplyerID").Orderby("order ASC, fid ASC").Prepare(),
delete: acc.Update("forums").Set("name= '', active = 0").Where("fid = ?").Prepare(), delete: acc.Update(f).Set("name= '', active = 0").Where("fid = ?").Prepare(),
create: acc.Insert("forums").Columns("name, desc, tmpl, active, preset").Fields("?,?,'',?,?").Prepare(), create: acc.Insert(f).Columns("name, desc, tmpl, active, preset").Fields("?,?,'',?,?").Prepare(),
count: acc.Count("forums").Where("name != ''").Prepare(), count: acc.Count(f).Where("name != ''").Prepare(),
updateCache: acc.Update("forums").Set("lastTopicID = ?, lastReplyerID = ?").Where("fid = ?").Prepare(), updateCache: acc.Update(f).Set("lastTopicID = ?, lastReplyerID = ?").Where("fid = ?").Prepare(),
addTopics: acc.Update("forums").Set("topicCount = topicCount + ?").Where("fid = ?").Prepare(), addTopics: acc.Update(f).Set("topicCount = topicCount + ?").Where("fid = ?").Prepare(),
removeTopics: acc.Update("forums").Set("topicCount = topicCount - ?").Where("fid = ?").Prepare(), removeTopics: acc.Update(f).Set("topicCount = topicCount - ?").Where("fid = ?").Prepare(),
updateOrder: acc.Update("forums").Set("order = ?").Where("fid = ?").Prepare(), updateOrder: acc.Update(f).Set("order = ?").Where("fid = ?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }
@ -107,7 +108,7 @@ func (s *MemoryForumStore) LoadForums() error {
} }
defer rows.Close() defer rows.Close()
var i = 0 i := 0
for ; rows.Next(); i++ { for ; rows.Next(); i++ {
f := &Forum{ID: 0, Active: true, Preset: "all"} f := &Forum{ID: 0, Active: true, Preset: "all"}
err = rows.Scan(&f.ID, &f.Name, &f.Desc, &f.Tmpl, &f.Active, &f.Order, &f.Preset, &f.ParentID, &f.ParentType, &f.TopicCount, &f.LastTopicID, &f.LastReplyerID) err = rows.Scan(&f.ID, &f.Name, &f.Desc, &f.Tmpl, &f.Active, &f.Order, &f.Preset, &f.ParentID, &f.ParentType, &f.TopicCount, &f.LastTopicID, &f.LastReplyerID)
@ -254,7 +255,7 @@ func (s *MemoryForumStore) GetAllVisible() (forumView []*Forum, err error) {
func (s *MemoryForumStore) GetAllVisibleIDs() ([]int, error) { func (s *MemoryForumStore) GetAllVisibleIDs() ([]int, error) {
forumView := s.forumView.Load().([]*Forum) forumView := s.forumView.Load().([]*Forum)
var ids = make([]int, len(forumView)) ids := make([]int, len(forumView))
for i := 0; i < len(forumView); i++ { for i := 0; i < len(forumView); i++ {
ids[i] = forumView[i].ID ids[i] = forumView[i].ID
} }

View File

@ -44,10 +44,11 @@ var groupStmts GroupStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
ug := "users_groups"
groupStmts = GroupStmts{ groupStmts = GroupStmts{
updateGroup: acc.Update("users_groups").Set("name = ?, tag = ?").Where("gid = ?").Prepare(), updateGroup: acc.Update(ug).Set("name = ?, tag = ?").Where("gid = ?").Prepare(),
updateGroupRank: acc.Update("users_groups").Set("is_admin = ?, is_mod = ?, is_banned = ?").Where("gid = ?").Prepare(), updateGroupRank: acc.Update(ug).Set("is_admin = ?, is_mod = ?, is_banned = ?").Where("gid = ?").Prepare(),
updateGroupPerms: acc.Update("users_groups").Set("permissions = ?").Where("gid = ?").Prepare(), updateGroupPerms: acc.Update(ug).Set("permissions = ?").Where("gid = ?").Prepare(),
} }
return acc.FirstError() return acc.FirstError()
}) })

View File

@ -40,7 +40,7 @@ func (s *DefaultMenuStore) Get(mid int) (*MenuListHolder, error) {
} }
func (s *DefaultMenuStore) Items(mid int) (mlist MenuItemList, err error) { func (s *DefaultMenuStore) Items(mid int) (mlist MenuItemList, err error) {
err = qgen.NewAcc().Select("menu_items").Columns("miid, name, htmlID, cssClass, position, path, aria, tooltip, order, tmplName, guestOnly, memberOnly, staffOnly, adminOnly").Where("mid = " + strconv.Itoa(mid)).Orderby("order ASC").Each(func(rows *sql.Rows) error { err = qgen.NewAcc().Select("menu_items").Columns("miid,name,htmlID,cssClass,position,path,aria,tooltip,order,tmplName,guestOnly,memberOnly,staffOnly,adminOnly").Where("mid = " + strconv.Itoa(mid)).Orderby("order ASC").Each(func(rows *sql.Rows) error {
i := MenuItem{MenuID: mid} i := MenuItem{MenuID: mid}
err := rows.Scan(&i.ID, &i.Name, &i.HTMLID, &i.CSSClass, &i.Position, &i.Path, &i.Aria, &i.Tooltip, &i.Order, &i.TmplName, &i.GuestOnly, &i.MemberOnly, &i.SuperModOnly, &i.AdminOnly) err := rows.Scan(&i.ID, &i.Name, &i.HTMLID, &i.CSSClass, &i.Position, &i.Path, &i.Aria, &i.Tooltip, &i.Order, &i.TmplName, &i.GuestOnly, &i.MemberOnly, &i.SuperModOnly, &i.AdminOnly)
if err != nil { if err != nil {

View File

@ -64,63 +64,64 @@ var menuItemStmts MenuItemStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
mi := "menu_items"
menuItemStmts = MenuItemStmts{ menuItemStmts = MenuItemStmts{
update: acc.Update("menu_items").Set("name = ?, htmlID = ?, cssClass = ?, position = ?, path = ?, aria = ?, tooltip = ?, tmplName = ?, guestOnly = ?, memberOnly = ?, staffOnly = ?, adminOnly = ?").Where("miid = ?").Prepare(), update: acc.Update(mi).Set("name = ?, htmlID = ?, cssClass = ?, position = ?, path = ?, aria = ?, tooltip = ?, tmplName = ?, guestOnly = ?, memberOnly = ?, staffOnly = ?, adminOnly = ?").Where("miid = ?").Prepare(),
insert: acc.Insert("menu_items").Columns("mid, name, htmlID, cssClass, position, path, aria, tooltip, tmplName, guestOnly, memberOnly, staffOnly, adminOnly").Fields("?,?,?,?,?,?,?,?,?,?,?,?,?").Prepare(), insert: acc.Insert(mi).Columns("mid, name, htmlID, cssClass, position, path, aria, tooltip, tmplName, guestOnly, memberOnly, staffOnly, adminOnly").Fields("?,?,?,?,?,?,?,?,?,?,?,?,?").Prepare(),
delete: acc.Delete("menu_items").Where("miid = ?").Prepare(), delete: acc.Delete(mi).Where("miid = ?").Prepare(),
updateOrder: acc.Update("menu_items").Set("order = ?").Where("miid = ?").Prepare(), updateOrder: acc.Update(mi).Set("order = ?").Where("miid = ?").Prepare(),
} }
return acc.FirstError() return acc.FirstError()
}) })
} }
func (item MenuItem) Commit() error { func (i MenuItem) Commit() error {
_, err := menuItemStmts.update.Exec(item.Name, item.HTMLID, item.CSSClass, item.Position, item.Path, item.Aria, item.Tooltip, item.TmplName, item.GuestOnly, item.MemberOnly, item.SuperModOnly, item.AdminOnly, item.ID) _, err := menuItemStmts.update.Exec(i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly, i.ID)
Menus.Load(item.MenuID) Menus.Load(i.MenuID)
return err return err
} }
func (item MenuItem) Create() (int, error) { func (i MenuItem) Create() (int, error) {
res, err := menuItemStmts.insert.Exec(item.MenuID, item.Name, item.HTMLID, item.CSSClass, item.Position, item.Path, item.Aria, item.Tooltip, item.TmplName, item.GuestOnly, item.MemberOnly, item.SuperModOnly, item.AdminOnly) res, err := menuItemStmts.insert.Exec(i.MenuID, i.Name, i.HTMLID, i.CSSClass, i.Position, i.Path, i.Aria, i.Tooltip, i.TmplName, i.GuestOnly, i.MemberOnly, i.SuperModOnly, i.AdminOnly)
if err != nil { if err != nil {
return 0, err return 0, err
} }
Menus.Load(item.MenuID) Menus.Load(i.MenuID)
miid64, err := res.LastInsertId() miid64, err := res.LastInsertId()
return int(miid64), err return int(miid64), err
} }
func (item MenuItem) Delete() error { func (i MenuItem) Delete() error {
_, err := menuItemStmts.delete.Exec(item.ID) _, err := menuItemStmts.delete.Exec(i.ID)
Menus.Load(item.MenuID) Menus.Load(i.MenuID)
return err return err
} }
func (hold *MenuListHolder) LoadTmpl(name string) (menuTmpl MenuTmpl, err error) { func (h *MenuListHolder) LoadTmpl(name string) (menuTmpl MenuTmpl, err error) {
data, err := ioutil.ReadFile("./templates/" + name + ".html") data, err := ioutil.ReadFile("./templates/" + name + ".html")
if err != nil { if err != nil {
return menuTmpl, err return menuTmpl, err
} }
return hold.Parse(name, data), nil return h.Parse(name, data), nil
} }
// TODO: Make this atomic, maybe with a transaction or store the order on the menu itself? // TODO: Make this atomic, maybe with a transaction or store the order on the menu itself?
func (hold *MenuListHolder) UpdateOrder(updateMap map[int]int) error { func (h *MenuListHolder) UpdateOrder(updateMap map[int]int) error {
for miid, order := range updateMap { for miid, order := range updateMap {
_, err := menuItemStmts.updateOrder.Exec(order, miid) _, err := menuItemStmts.updateOrder.Exec(order, miid)
if err != nil { if err != nil {
return err return err
} }
} }
Menus.Load(hold.MenuID) Menus.Load(h.MenuID)
return nil return nil
} }
func (hold *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, err error) { func (h *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, err error) {
tmpls = make(map[string]MenuTmpl) tmpls = make(map[string]MenuTmpl)
var loadTmpl = func(name string) error { loadTmpl := func(name string) error {
menuTmpl, err := hold.LoadTmpl(name) menuTmpl, err := h.LoadTmpl(name)
if err != nil { if err != nil {
return err return err
} }
@ -136,32 +137,32 @@ func (hold *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, err error) {
} }
// TODO: Run this in main, sync ticks, when the phrase file changes (need to implement the sync for that first), and when the settings are changed // TODO: Run this in main, sync ticks, when the phrase file changes (need to implement the sync for that first), and when the settings are changed
func (hold *MenuListHolder) Preparse() error { func (h *MenuListHolder) Preparse() error {
tmpls, err := hold.LoadTmpls() tmpls, err := h.LoadTmpls()
if err != nil { if err != nil {
return err return err
} }
var addVariation = func(index int, callback func(mitem MenuItem) bool) { addVariation := func(index int, callback func(i MenuItem) bool) {
renderBuffer, variableIndices, pathList := hold.Scan(tmpls, callback) renderBuffer, variableIndices, pathList := h.Scan(tmpls, callback)
hold.Variations[index] = menuTmpl{renderBuffer, variableIndices, pathList} h.Variations[index] = menuTmpl{renderBuffer, variableIndices, pathList}
} }
// Guest Menu // Guest Menu
addVariation(0, func(mitem MenuItem) bool { addVariation(0, func(i MenuItem) bool {
return !mitem.MemberOnly return !i.MemberOnly
}) })
// Member Menu // Member Menu
addVariation(1, func(mitem MenuItem) bool { addVariation(1, func(i MenuItem) bool {
return !mitem.SuperModOnly && !mitem.GuestOnly return !i.SuperModOnly && !i.GuestOnly
}) })
// Super Mod Menu // Super Mod Menu
addVariation(2, func(mitem MenuItem) bool { addVariation(2, func(i MenuItem) bool {
return !mitem.AdminOnly && !mitem.GuestOnly return !i.AdminOnly && !i.GuestOnly
}) })
// Admin Menu // Admin Menu
addVariation(3, func(mitem MenuItem) bool { addVariation(3, func(i MenuItem) bool {
return !mitem.GuestOnly return !i.GuestOnly
}) })
return nil return nil
} }
@ -264,13 +265,13 @@ func menuDumpSlice(outerSlice [][]byte) {
} }
} }
func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTmpl) { func (h *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTmpl) {
var textBuffer, variableBuffer [][]byte var textBuffer, variableBuffer [][]byte
var renderList []menuRenderItem var renderList []menuRenderItem
var subBuffer []byte var subBuffer []byte
// ? We only support simple properties on MenuItem right now // ? We only support simple properties on MenuItem right now
var addVariable = func(name []byte) { addVariable := func(name []byte) {
// TODO: Check if the subBuffer has any items or is empty // TODO: Check if the subBuffer has any items or is empty
textBuffer = append(textBuffer, subBuffer) textBuffer = append(textBuffer, subBuffer)
subBuffer = nil subBuffer = nil
@ -325,13 +326,13 @@ func (hold *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTm
return MenuTmpl{name, textBuffer, variableBuffer, renderList} return MenuTmpl{name, textBuffer, variableBuffer, renderList}
} }
func (hold *MenuListHolder) Scan(menuTmpls map[string]MenuTmpl, showItem func(mitem MenuItem) bool) (renderBuffer [][]byte, variableIndices []int, pathList []menuPath) { func (h *MenuListHolder) Scan(menuTmpls map[string]MenuTmpl, showItem func(i MenuItem) bool) (renderBuffer [][]byte, variableIndices []int, pathList []menuPath) {
for _, mitem := range hold.List { for _, mitem := range h.List {
// Do we want this item in this variation of the menu? // Do we want this item in this variation of the menu?
if !showItem(mitem) { if !showItem(mitem) {
continue continue
} }
renderBuffer, variableIndices = hold.ScanItem(menuTmpls, mitem, renderBuffer, variableIndices) renderBuffer, variableIndices = h.ScanItem(menuTmpls, mitem, renderBuffer, variableIndices)
pathList = append(pathList, menuPath{mitem.Path, len(renderBuffer) - 1}) pathList = append(pathList, menuPath{mitem.Path, len(renderBuffer) - 1})
} }
@ -340,7 +341,7 @@ func (hold *MenuListHolder) Scan(menuTmpls map[string]MenuTmpl, showItem func(mi
} }
// Note: This doesn't do a visibility check like hold.Scan() does // Note: This doesn't do a visibility check like hold.Scan() does
func (hold *MenuListHolder) ScanItem(menuTmpls map[string]MenuTmpl, mitem MenuItem, renderBuffer [][]byte, variableIndices []int) ([][]byte, []int) { func (h *MenuListHolder) ScanItem(menuTmpls map[string]MenuTmpl, mitem MenuItem, renderBuffer [][]byte, variableIndices []int) ([][]byte, []int) {
menuTmpl, ok := menuTmpls[mitem.TmplName] menuTmpl, ok := menuTmpls[mitem.TmplName]
if !ok { if !ok {
menuTmpl = menuTmpls["menu_item"] menuTmpl = menuTmpls["menu_item"]
@ -416,16 +417,16 @@ func (hold *MenuListHolder) ScanItem(menuTmpls map[string]MenuTmpl, mitem MenuIt
} }
// TODO: Pre-render the lang stuff // TODO: Pre-render the lang stuff
func (hold *MenuListHolder) Build(w io.Writer, user *User, pathPrefix string) error { func (h *MenuListHolder) Build(w io.Writer, user *User, pathPrefix string) error {
var mTmpl menuTmpl var mTmpl menuTmpl
if !user.Loggedin { if !user.Loggedin {
mTmpl = hold.Variations[0] mTmpl = h.Variations[0]
} else if user.IsAdmin { } else if user.IsAdmin {
mTmpl = hold.Variations[3] mTmpl = h.Variations[3]
} else if user.IsSuperMod { } else if user.IsSuperMod {
mTmpl = hold.Variations[2] mTmpl = h.Variations[2]
} else { } else {
mTmpl = hold.Variations[1] mTmpl = h.Variations[1]
} }
if pathPrefix == "" { if pathPrefix == "" {
pathPrefix = Config.DefaultPath pathPrefix = Config.DefaultPath
@ -438,7 +439,7 @@ func (hold *MenuListHolder) Build(w io.Writer, user *User, pathPrefix string) er
return nil return nil
} }
var nearIndex = 0 nearIndex := 0
for index, renderItem := range mTmpl.RenderBuffer { for index, renderItem := range mTmpl.RenderBuffer {
if index != mTmpl.VariableIndices[nearIndex] { if index != mTmpl.VariableIndices[nearIndex] {
w.Write(renderItem) w.Write(renderItem)

View File

@ -26,16 +26,17 @@ type DefaultReportStore struct {
} }
func NewDefaultReportStore(acc *qgen.Accumulator) (*DefaultReportStore, error) { func NewDefaultReportStore(acc *qgen.Accumulator) (*DefaultReportStore, error) {
t := "topics"
return &DefaultReportStore{ return &DefaultReportStore{
create: acc.Insert("topics").Columns("title, content, parsed_content, ipaddress, createdAt, lastReplyAt, createdBy, lastReplyBy, data, parentID, css_class").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?,'report'").Prepare(), create: acc.Insert(t).Columns("title, content, parsed_content, ipaddress, createdAt, lastReplyAt, createdBy, lastReplyBy, data, parentID, css_class").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?,'report'").Prepare(),
exists: acc.Count("topics").Where("data = ? AND data != '' AND parentID = ?").Prepare(), exists: acc.Count(t).Where("data = ? AND data != '' AND parentID = ?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }
// ! There's a data race in this. If two users report one item at the exact same time, then both reports will go through // ! There's a data race in this. If two users report one item at the exact same time, then both reports will go through
func (s *DefaultReportStore) Create(title string, content string, user *User, itemType string, itemID int) (int, error) { func (s *DefaultReportStore) Create(title string, content string, user *User, itemType string, itemID int) (tid int, err error) {
var count int var count int
err := s.exists.QueryRow(itemType+"_"+strconv.Itoa(itemID), ReportForumID).Scan(&count) err = s.exists.QueryRow(itemType+"_"+strconv.Itoa(itemID), ReportForumID).Scan(&count)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return 0, err return 0, err
} }
@ -47,11 +48,10 @@ func (s *DefaultReportStore) Create(title string, content string, user *User, it
if err != nil { if err != nil {
return 0, err return 0, err
} }
lastID, err := res.LastInsertId() lastID, err := res.LastInsertId()
if err != nil { if err != nil {
return 0, err return 0, err
} }
tid = int(lastID)
return int(lastID), Forums.AddTopic(int(lastID), user.ID, ReportForumID) return tid, Forums.AddTopic(tid, user.ID, ReportForumID)
} }

View File

@ -41,11 +41,12 @@ var themeStmts ThemeStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
t := "themes"
themeStmts = ThemeStmts{ themeStmts = ThemeStmts{
getAll: acc.Select("themes").Columns("uname, default").Prepare(), getAll: acc.Select(t).Columns("uname, default").Prepare(),
isDefault: acc.Select("themes").Columns("default").Where("uname = ?").Prepare(), isDefault: acc.Select(t).Columns("default").Where("uname = ?").Prepare(),
update: acc.Update("themes").Set("default = ?").Where("uname = ?").Prepare(), update: acc.Update(t).Set("default = ?").Where("uname = ?").Prepare(),
add: acc.Insert("themes").Columns("uname, default").Fields("?,?").Prepare(), add: acc.Insert(t).Columns("uname, default").Fields("?,?").Prepare(),
} }
return acc.FirstError() return acc.FirstError()
}) })
@ -144,7 +145,7 @@ func NewThemeList() (themes ThemeList, err error) {
return themes, err return themes, err
} }
if len(overrides) > 0 { if len(overrides) > 0 {
var overCount = 0 overCount := 0
theme.OverridenMap = make(map[string]bool) theme.OverridenMap = make(map[string]bool)
for _, override := range overrides { for _, override := range overrides {
if override.IsDir() { if override.IsDir() {
@ -180,7 +181,6 @@ func NewThemeList() (themes ThemeList, err error) {
themes[theme.Name] = theme themes[theme.Name] = theme
} }
if defaultTheme == "" { if defaultTheme == "" {
defaultTheme = lastTheme defaultTheme = lastTheme
} }
@ -232,8 +232,7 @@ func (t ThemeList) LoadActiveStatus() error {
func (t ThemeList) LoadStaticFiles() error { func (t ThemeList) LoadStaticFiles() error {
for _, theme := range t { for _, theme := range t {
err := theme.LoadStaticFiles() if err := theme.LoadStaticFiles(); err != nil {
if err != nil {
return err return err
} }
} }
@ -244,7 +243,6 @@ func ResetTemplateOverrides() {
log.Print("Resetting the template overrides") log.Print("Resetting the template overrides")
for name := range overridenTemplates { for name := range overridenTemplates {
log.Print("Resetting '" + name + "' template override") log.Print("Resetting '" + name + "' template override")
originPointer, ok := TmplPtrMap["o_"+name] originPointer, ok := TmplPtrMap["o_"+name]
if !ok { if !ok {
log.Print("The origin template doesn't exist!") log.Print("The origin template doesn't exist!")
@ -269,7 +267,6 @@ func ResetTemplateOverrides() {
LogError(errors.New("The source and destination templates are incompatible")) LogError(errors.New("The source and destination templates are incompatible"))
return return
} }
*dPtr = oPtr *dPtr = oPtr
log.Print("The template override was reset") log.Print("The template override was reset")
} }

View File

@ -4,7 +4,7 @@ import (
"image" "image"
"image/gif" "image/gif"
"image/jpeg" "image/jpeg"
_ "image/png" "image/png"
"os" "os"
"strconv" "strconv"
@ -66,6 +66,14 @@ func ThumbTask(thumbChan chan bool) {
if err != nil { if err != nil {
LogError(err) LogError(err)
} }
/*
err := acc.Select("attach_image_queue").Columns("attachID").Limit("0,5").EachInt(func(attachID int) error {
return nil
_, err = acc.Delete("attach_image_queue").Where("attachID = ?").Run(uid)
}
*/
if err = acc.FirstError(); err != nil { if err = acc.FirstError(); err != nil {
LogError(err) LogError(err)
} }
@ -119,6 +127,8 @@ func precodeImage(format string, inPath string, tmpPath string) error {
// TODO: Make sure animated gifs work after being encoded // TODO: Make sure animated gifs work after being encoded
if format == "gif" { if format == "gif" {
return gif.Encode(outFile, img, nil) return gif.Encode(outFile, img, nil)
} else if format == "png" {
return png.Encode(outFile, img)
} }
return jpeg.Encode(outFile, img, nil) return jpeg.Encode(outFile, img, nil)
} }

View File

@ -212,24 +212,25 @@ var topicStmts TopicStmts
func init() { func init() {
DbInits.Add(func(acc *qgen.Accumulator) error { DbInits.Add(func(acc *qgen.Accumulator) error {
t := "topics"
topicStmts = TopicStmts{ topicStmts = TopicStmts{
getRids: acc.Select("replies").Columns("rid").Where("tid = ?").Orderby("rid ASC").Limit("?,?").Prepare(), getRids: acc.Select("replies").Columns("rid").Where("tid = ?").Orderby("rid ASC").Limit("?,?").Prepare(),
getReplies: acc.SimpleLeftJoin("replies AS r", "users AS u", "r.rid, r.content, r.createdBy, r.createdAt, r.lastEdit, r.lastEditBy, u.avatar, u.name, u.group, u.url_prefix, u.url_name, u.level, r.ipaddress, r.likeCount, r.attachCount, r.actionType", "r.createdBy = u.uid", "r.tid = ?", "r.rid ASC", "?,?"), getReplies: acc.SimpleLeftJoin("replies AS r", "users AS u", "r.rid, r.content, r.createdBy, r.createdAt, r.lastEdit, r.lastEditBy, u.avatar, u.name, u.group, u.url_prefix, u.url_name, u.level, r.ipaddress, r.likeCount, r.attachCount, r.actionType", "r.createdBy = u.uid", "r.tid = ?", "r.rid ASC", "?,?"),
addReplies: acc.Update("topics").Set("postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()").Where("tid = ?").Prepare(), addReplies: acc.Update(t).Set("postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()").Where("tid = ?").Prepare(),
updateLastReply: acc.Update("topics").Set("lastReplyID = ?").Where("lastReplyID > ? AND tid = ?").Prepare(), updateLastReply: acc.Update(t).Set("lastReplyID = ?").Where("lastReplyID > ? AND tid = ?").Prepare(),
lock: acc.Update("topics").Set("is_closed = 1").Where("tid = ?").Prepare(), lock: acc.Update(t).Set("is_closed = 1").Where("tid = ?").Prepare(),
unlock: acc.Update("topics").Set("is_closed = 0").Where("tid = ?").Prepare(), unlock: acc.Update(t).Set("is_closed = 0").Where("tid = ?").Prepare(),
moveTo: acc.Update("topics").Set("parentID = ?").Where("tid = ?").Prepare(), moveTo: acc.Update(t).Set("parentID = ?").Where("tid = ?").Prepare(),
stick: acc.Update("topics").Set("sticky = 1").Where("tid = ?").Prepare(), stick: acc.Update(t).Set("sticky = 1").Where("tid = ?").Prepare(),
unstick: acc.Update("topics").Set("sticky = 0").Where("tid = ?").Prepare(), unstick: acc.Update(t).Set("sticky = 0").Where("tid = ?").Prepare(),
hasLikedTopic: acc.Select("likes").Columns("targetItem").Where("sentBy = ? and targetItem = ? and targetType = 'topics'").Prepare(), hasLikedTopic: acc.Select("likes").Columns("targetItem").Where("sentBy = ? and targetItem = ? and targetType = 'topics'").Prepare(),
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(), createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy, createdAt").Fields("?,?,?,?,UTC_TIMESTAMP()").Prepare(),
addLikesToTopic: acc.Update("topics").Set("likeCount = likeCount + ?").Where("tid = ?").Prepare(), addLikesToTopic: acc.Update(t).Set("likeCount = likeCount + ?").Where("tid = ?").Prepare(),
delete: acc.Delete("topics").Where("tid = ?").Prepare(), delete: acc.Delete(t).Where("tid = ?").Prepare(),
deleteActivity: acc.Delete("activity_stream").Where("elementID = ? AND elementType = 'topic'").Prepare(), deleteActivity: acc.Delete("activity_stream").Where("elementID = ? AND elementType = 'topic'").Prepare(),
deleteActivitySubs: acc.Delete("activity_subscriptions").Where("targetID = ? AND targetType = 'topic'").Prepare(), deleteActivitySubs: acc.Delete("activity_subscriptions").Where("targetID = ? AND targetType = 'topic'").Prepare(),
edit: acc.Update("topics").Set("title = ?, content = ?, parsed_content = ?").Where("tid = ?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter? edit: acc.Update(t).Set("title = ?, content = ?, parsed_content = ?").Where("tid = ?").Prepare(), // TODO: Only run the content update bits on non-polls, does this matter?
setPoll: acc.Update("topics").Set("poll = ?").Where("tid = ? AND poll = 0").Prepare(), setPoll: acc.Update(t).Set("poll = ?").Where("tid = ? AND poll = 0").Prepare(),
createAction: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(), createAction: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
getTopicUser: acc.SimpleLeftJoin("topics AS t", "users AS u", "t.title, t.content, t.createdBy, t.createdAt, t.lastReplyAt, t.lastReplyBy, t.lastReplyID, t.is_closed, t.sticky, t.parentID, t.ipaddress, t.views, t.postCount, t.likeCount, t.attachCount,t.poll, u.name, u.avatar, u.group, u.url_prefix, u.url_name, u.level", "t.createdBy = u.uid", "tid = ?", "", ""), getTopicUser: acc.SimpleLeftJoin("topics AS t", "users AS u", "t.title, t.content, t.createdBy, t.createdAt, t.lastReplyAt, t.lastReplyBy, t.lastReplyID, t.is_closed, t.sticky, t.parentID, t.ipaddress, t.views, t.postCount, t.likeCount, t.attachCount,t.poll, u.name, u.avatar, u.group, u.url_prefix, u.url_name, u.level", "t.createdBy = u.uid", "tid = ?", "", ""),

View File

@ -56,12 +56,13 @@ func NewDefaultTopicStore(cache TopicCache) (*DefaultTopicStore, error) {
if cache == nil { if cache == nil {
cache = NewNullTopicCache() cache = NewNullTopicCache()
} }
t := "topics"
return &DefaultTopicStore{ return &DefaultTopicStore{
cache: cache, cache: cache,
get: acc.Select("topics").Columns("title, content, createdBy, createdAt, lastReplyBy, lastReplyAt, lastReplyID, is_closed, sticky, parentID, ipaddress, views, postCount, likeCount, attachCount, poll, data").Where("tid = ?").Prepare(), get: acc.Select(t).Columns("title, content, createdBy, createdAt, lastReplyBy, lastReplyAt, lastReplyID, is_closed, sticky, parentID, ipaddress, views, postCount, likeCount, attachCount, poll, data").Where("tid = ?").Prepare(),
exists: acc.Select("topics").Columns("tid").Where("tid = ?").Prepare(), exists: acc.Exists(t,"tid").Prepare(),
count: acc.Count("topics").Prepare(), count: acc.Count(t).Prepare(),
create: acc.Insert("topics").Columns("parentID, title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, ipaddress, words, createdBy").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?").Prepare(), create: acc.Insert(t).Columns("parentID, title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, ipaddress, words, createdBy").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?").Prepare(),
}, acc.FirstError() }, acc.FirstError()
} }
@ -159,8 +160,7 @@ func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err erro
s.cache.Set(t) s.cache.Set(t)
list[t.ID] = t list[t.ID] = t
} }
err = rows.Err() if err = rows.Err(); err != nil {
if err != nil {
return list, err return list, err
} }
@ -211,19 +211,18 @@ func (s *DefaultTopicStore) Create(fid int, topicName string, content string, ui
return 0, ErrNoBody return 0, ErrNoBody
} }
wcount := WordCount(content)
// TODO: Move this statement into the topic store // TODO: Move this statement into the topic store
res, err := s.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, wcount, uid) res, err := s.create.Exec(fid, topicName, content, parsedContent, uid, ipaddress, WordCount(content), uid)
if err != nil { if err != nil {
return 0, err return 0, err
} }
lastID, err := res.LastInsertId() lastID, err := res.LastInsertId()
if err != nil { if err != nil {
return 0, err return 0, err
} }
tid = int(lastID)
return int(lastID), Forums.AddTopic(int(lastID), uid, fid) return tid, Forums.AddTopic(tid, uid, fid)
} }
// ? - What is this? Do we need it? Should it be in the main store interface? // ? - What is this? Do we need it? Should it be in the main store interface?

View File

@ -38,12 +38,13 @@ type DefaultWordFilterStore struct {
} }
func NewDefaultWordFilterStore(acc *qgen.Accumulator) (*DefaultWordFilterStore, error) { func NewDefaultWordFilterStore(acc *qgen.Accumulator) (*DefaultWordFilterStore, error) {
wf := "word_filters"
store := &DefaultWordFilterStore{ store := &DefaultWordFilterStore{
getAll: acc.Select("word_filters").Columns("wfid, find, replacement").Prepare(), getAll: acc.Select(wf).Columns("wfid,find,replacement").Prepare(),
create: acc.Insert("word_filters").Columns("find, replacement").Fields("?,?").Prepare(), create: acc.Insert(wf).Columns("find,replacement").Fields("?,?").Prepare(),
delete: acc.Delete("word_filters").Where("wfid = ?").Prepare(), delete: acc.Delete(wf).Where("wfid = ?").Prepare(),
update: acc.Update("word_filters").Set("find = ?, replacement = ?").Where("wfid = ?").Prepare(), update: acc.Update(wf).Set("find = ?, replacement = ?").Where("wfid = ?").Prepare(),
count: acc.Count("word_filters").Prepare(), count: acc.Count(wf).Prepare(),
} }
// TODO: Should we initialise this elsewhere? // TODO: Should we initialise this elsewhere?
if acc.FirstError() == nil { if acc.FirstError() == nil {

View File

@ -869,10 +869,6 @@ function mainInit(){
}); });
// The time range selector for the time graphs in the Control Panel // The time range selector for the time graphs in the Control Panel
/*$(".timeRangeSelector").change(function(){
console.log("Changed the time range to " + this.options[this.selectedIndex].getAttribute("val"));
window.location = this.form.getAttribute("action")+"?timeRange=" + this.options[this.selectedIndex].getAttribute("val"); // Do a redirect as a form submission refuses to work properly
});*/
$(".autoSubmitRedirect").change(function(){ $(".autoSubmitRedirect").change(function(){
let elems = this.form.elements; let elems = this.form.elements;
let s = ""; let s = "";