Topic and user edits should now update the caches. Ditto for topic deletions.

The tests and benchmarks now run again.
gloinit() is always called prior to the tests and benchmarks now.
The tests and benchmarks no longer use hard-coded session strings for admin route tests.
Added some new route tests.
We now pull the database version into a variable.
Fixed an issue with guest perms not applying properly.
Tweaked the router to make it a little more efficient.
Moved more topic / user parsing logic into CascadeGet
Profiles now use the user cache.
Added the Set method to the caches. Set is used when you don't know if an item exists in a cache or not.
Added the Load method to the caches. Load is used to forcefully reload an item in a cache from the database.
This commit is contained in:
Azareal 2017-02-15 10:49:30 +00:00
parent 399128c208
commit 6fdf615cf5
28 changed files with 563 additions and 1032 deletions

View File

@ -11,9 +11,11 @@ var users UserStore
var topics TopicStore var topics TopicStore
type DataStore interface { type DataStore interface {
Load(id int) error
Get(id int) (interface{}, error) Get(id int) (interface{}, error)
GetUnsafe(id int) (interface{}, error) GetUnsafe(id int) (interface{}, error)
CascadeGet(id int) (interface{}, error) CascadeGet(id int) (interface{}, error)
Set(item interface{}) error
Add(item interface{}) error Add(item interface{}) error
AddUnsafe(item interface{}) error AddUnsafe(item interface{}) error
Remove(id int) error Remove(id int) error

View File

@ -4,9 +4,9 @@ import "log"
import "bytes" import "bytes"
import "strings" import "strings"
import "mime" import "mime"
import "errors" //import "errors"
import "os" import "os"
import "io" //import "io"
import "io/ioutil" import "io/ioutil"
import "path/filepath" import "path/filepath"
import "net/http" import "net/http"
@ -23,7 +23,7 @@ type SFile struct
FormattedModTime string FormattedModTime string
} }
func (r SFile) Read(b []byte) (n int, err error) { /*func (r SFile) Read(b []byte) (n int, err error) {
n = 0 n = 0
if r.Pos > r.Length { if r.Pos > r.Length {
return n, io.EOF return n, io.EOF
@ -58,7 +58,7 @@ func (r SFile) Seek(offset int64, whence int) (int64, error) {
return 0, errors.New("invalid whence") return 0, errors.New("invalid whence")
} }
return r.Pos, nil return r.Pos, nil
} }*/
func add_static_file(path string, prefix string) error { func add_static_file(path string, prefix string) error {
data, err := ioutil.ReadFile(path) data, err := ioutil.ReadFile(path)

View File

@ -1,5 +1,6 @@
package main package main
import "os" import "os"
import "fmt"
import "log" import "log"
import "bytes" import "bytes"
import "strconv" import "strconv"
@ -8,7 +9,6 @@ import "testing"
import "net/http" import "net/http"
import "net/http/httptest" import "net/http/httptest"
import "io/ioutil" import "io/ioutil"
import "html/template"
import "database/sql" import "database/sql"
import _ "github.com/go-sql-driver/mysql" import _ "github.com/go-sql-driver/mysql"
//import "github.com/husobee/vestigo" //import "github.com/husobee/vestigo"
@ -23,9 +23,25 @@ func gloinit() {
//discard := ioutil.Discard //discard := ioutil.Discard
//log.SetOutput(discard) //log.SetOutput(discard)
init_themes()
var err error var err error
init_database(err) init_database(err)
init_templates()
db.SetMaxOpenConns(64) db.SetMaxOpenConns(64)
err = init_errors()
if err != nil {
log.Fatal(err)
}
if cache_topicuser == CACHE_STATIC {
users = NewStaticUserStore(user_cache_capacity)
topics = NewStaticTopicStore(topic_cache_capacity)
} else {
users = NewSqlUserStore()
topics = NewSqlTopicStore()
}
init_static_files()
external_sites["YT"] = "https://www.youtube.com/" external_sites["YT"] = "https://www.youtube.com/"
hooks["trow_assign"] = nil hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil hooks["rrow_assign"] = nil
@ -33,26 +49,30 @@ func gloinit() {
gloinited = true gloinited = true
} }
func BenchmarkTopicTemplate(b *testing.B) { func init() {
gloinit()
}
func BenchmarkTopicTemplateSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"} user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"} admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"}
noticeList := []string{"test"} noticeList := []string{"test"}
topic := TopicUser{Title: "Lol",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"} topic := TopicUser{Title: "Lol",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}
var replyList []Reply var replyList []Reply
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) replyList = append(replyList, Reply{0,0,"Hey everyone!","Hey everyone!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1})
tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,1,1,false} tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,1,1,false}
tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,1,1,false} tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,1,1,false}
@ -113,24 +133,24 @@ func BenchmarkTopicTemplate(b *testing.B) {
defer pprof.StopCPUProfile()*/ defer pprof.StopCPUProfile()*/
} }
func BenchmarkTopicsTemplate(b *testing.B) { func BenchmarkTopicsTemplateSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"} user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"127.0.0.1"}
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"} admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58,"127.0.0.1"}
noticeList := []string{"test"} noticeList := []string{"test"}
var topicList []TopicUser var topicList []TopicsRow
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"}) topicList = append(topicList, TopicsRow{Title: "Hey everyone!",Content: "Hey everyone!",CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58, IpAddress: "127.0.0.1"})
w := ioutil.Discard w := ioutil.Discard
tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,nil} tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,nil}
@ -163,23 +183,6 @@ func BenchmarkStaticRouteParallel(b *testing.B) {
if !gloinited { if !gloinited {
gloinit() gloinit()
} }
b.RunParallel(func(pb *testing.PB) {
static_w := httptest.NewRecorder()
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
static_handler := http.HandlerFunc(route_static)
for pb.Next() {
static_w.Body.Reset()
static_handler.ServeHTTP(static_w,static_req)
}
})
}
/*func BenchmarkStaticRouteParallelWithPlugins(b *testing.B) {
b.ReportAllocs()
if !gloinited {
gloinit()
}
if !plugins_inited { if !plugins_inited {
init_plugins() init_plugins()
} }
@ -189,11 +192,16 @@ func BenchmarkStaticRouteParallel(b *testing.B) {
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil)) static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
static_handler := http.HandlerFunc(route_static) static_handler := http.HandlerFunc(route_static)
for pb.Next() { for pb.Next() {
//static_w.Code = 200
static_w.Body.Reset() static_w.Body.Reset()
static_handler.ServeHTTP(static_w,static_req) static_handler.ServeHTTP(static_w,static_req)
//if static_w.Code != 200 {
// fmt.Println(static_w.Body)
// panic("HTTP Error!")
//}
} }
}) })
}*/ }
func BenchmarkTopicAdminRouteParallel(b *testing.B) { func BenchmarkTopicAdminRouteParallel(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
@ -202,9 +210,15 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
} }
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year} admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
// TO-DO: Stop hard-coding this value. Seriously. admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
topic_w := httptest.NewRecorder() topic_w := httptest.NewRecorder()
topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil)) topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil))
@ -214,7 +228,7 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
topic_handler := http.HandlerFunc(route_topic_id) topic_handler := http.HandlerFunc(route_topic_id)
for pb.Next() { for pb.Next() {
//topic_w.Body.Reset() topic_w.Body.Reset()
topic_handler.ServeHTTP(topic_w,topic_req_admin) topic_handler.ServeHTTP(topic_w,topic_req_admin)
} }
}) })
@ -245,9 +259,15 @@ func BenchmarkForumsAdminRouteParallel(b *testing.B) {
} }
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year} admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
// TO-DO: Stop hard-coding this value. Seriously. admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
forums_w := httptest.NewRecorder() forums_w := httptest.NewRecorder()
forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil)) forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil))
@ -270,9 +290,15 @@ func BenchmarkForumsAdminRouteParallelProf(b *testing.B) {
} }
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year} admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
// TO-DO: Stop hard-coding this value. Seriously. admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path: "/",MaxAge: year}
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
forums_w := httptest.NewRecorder() forums_w := httptest.NewRecorder()
forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil)) forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil))
@ -313,10 +339,16 @@ func BenchmarkForumsGuestRouteParallel(b *testing.B) {
func BenchmarkRoutesSerial(b *testing.B) { func BenchmarkRoutesSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year} admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
// TO-DO: Stop hard-coding this value. Seriously. admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path: "/",MaxAge: year}
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
if plugins_inited { if plugins_inited {
b.Log("Plugins have already been initialised, they can't be deinitialised so these tests will run with plugins on") b.Log("Plugins have already been initialised, they can't be deinitialised so these tests will run with plugins on")
@ -367,8 +399,13 @@ func BenchmarkRoutesSerial(b *testing.B) {
b.Run("static_recorder", func(b *testing.B) { b.Run("static_recorder", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
//static_w.Code = 200
static_w.Body.Reset() static_w.Body.Reset()
static_handler.ServeHTTP(static_w,static_req) static_handler.ServeHTTP(static_w,static_req)
//if static_w.Code != 200 {
// fmt.Println(static_w.Body)
// panic("HTTP Error!")
//}
} }
}) })
@ -542,12 +579,9 @@ func BenchmarkQueryTopicParallel(b *testing.B) {
} }
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
topic := TopicUser{Css: no_css_tmpl} tu := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
for pb.Next() { for pb.Next() {
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, users.name, users.avatar, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, topics.ipaddress from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.CreatedByName, &topic.Avatar, &is_super_admin, &group, &topic.URLPrefix, &topic.URLName, &topic.Level, &topic.IpAddress) err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Fatal("No rows found!") log.Fatal("No rows found!")
return return
@ -566,12 +600,9 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
} }
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
topic := TopicUser{Css: no_css_tmpl} tu := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
for pb.Next() { for pb.Next() {
err := get_topic_user_stmt.QueryRow(1).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.CreatedByName, &topic.Avatar, &is_super_admin, &group, &topic.URLPrefix, &topic.URLName, &topic.Level, &topic.IpAddress) err := get_topic_user_stmt.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Fatal("No rows found!") log.Fatal("No rows found!")
return return
@ -585,13 +616,10 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
func BenchmarkQueriesSerial(b *testing.B) { func BenchmarkQueriesSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
topic := TopicUser{Css: no_css_tmpl} tu := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
b.Run("topic", func(b *testing.B) { b.Run("topic", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, users.name, users.avatar, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, topics.ipaddress from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.CreatedByName, &topic.Avatar, &is_super_admin, &group, &topic.URLPrefix, &topic.URLName, &topic.Level, &topic.IpAddress) err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.Is_Closed, &tu.Sticky, &tu.ParentID, &tu.IpAddress, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Fatal("No rows found!") log.Fatal("No rows found!")
return return
@ -617,7 +645,10 @@ func BenchmarkQueriesSerial(b *testing.B) {
defer rows.Close() defer rows.Close()
} }
}) })
replyItem := Reply{Css: no_css_tmpl} replyItem := Reply{Css: no_css_tmpl}
var is_super_admin bool
var group int
b.Run("topic_replies_scan", func(b *testing.B) { b.Run("topic_replies_scan", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1) rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1)
@ -648,7 +679,7 @@ func addEmptyRoutesToMux(routes []string, serveMux *http.ServeMux) {
} }
} }
func BenchmarkDefaultGoRouter(b *testing.B) { func BenchmarkDefaultGoRouterSerial(b *testing.B) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil)) req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
routes := make([]string, 0) routes := make([]string, 0)
@ -805,176 +836,13 @@ func BenchmarkDefaultGoRouter(b *testing.B) {
}) })
} }
/*func addEmptyRoutesToVestigo(routes []string, router *vestigo.Router) {
for _, route := range routes {
router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){})
}
}
func BenchmarkVestigoRouter(b *testing.B) {
w := httptest.NewRecorder()
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
routes := make([]string, 0)
routes = append(routes,"/test/")
router := vestigo.NewRouter()
router.HandleFunc("/test/", func(_ http.ResponseWriter,_ *http.Request){})
b.Run("one-route", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
routes = append(routes,"/topic/")
routes = append(routes,"/forums/")
routes = append(routes,"/forum/")
routes = append(routes,"/panel/")
router = vestigo.NewRouter()
addEmptyRoutesToVestigo(routes, router)
b.Run("five-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/panel/plugins/")
routes = append(routes,"/panel/groups/")
routes = append(routes,"/panel/settings/")
routes = append(routes,"/panel/users/")
routes = append(routes,"/panel/forums/")
addEmptyRoutesToVestigo(routes, router)
b.Run("ten-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/panel/forums/create/submit/")
routes = append(routes,"/panel/forums/delete/")
routes = append(routes,"/users/ban/")
routes = append(routes,"/panel/users/edit/")
routes = append(routes,"/panel/forums/create/")
routes = append(routes,"/users/unban/")
routes = append(routes,"/pages/")
routes = append(routes,"/users/activate/")
routes = append(routes,"/panel/forums/edit/submit/")
routes = append(routes,"/panel/plugins/activate/")
addEmptyRoutesToVestigo(routes, router)
b.Run("twenty-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/panel/plugins/deactivate/")
routes = append(routes,"/panel/plugins/install/")
routes = append(routes,"/panel/plugins/uninstall/")
routes = append(routes,"/panel/templates/")
routes = append(routes,"/panel/templates/edit/")
routes = append(routes,"/panel/templates/create/")
routes = append(routes,"/panel/templates/delete/")
routes = append(routes,"/panel/templates/edit/submit/")
routes = append(routes,"/panel/themes/")
routes = append(routes,"/panel/themes/edit/")
addEmptyRoutesToVestigo(routes, router)
b.Run("thirty-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/panel/themes/create/")
routes = append(routes,"/panel/themes/delete/")
routes = append(routes,"/panel/themes/delete/submit/")
routes = append(routes,"/panel/templates/create/submit/")
routes = append(routes,"/panel/templates/delete/submit/")
routes = append(routes,"/panel/widgets/")
routes = append(routes,"/panel/widgets/edit/")
routes = append(routes,"/panel/widgets/activate/")
routes = append(routes,"/panel/widgets/deactivate/")
routes = append(routes,"/panel/magical/wombat/path")
addEmptyRoutesToVestigo(routes, router)
b.Run("forty-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/report/")
routes = append(routes,"/report/submit/")
routes = append(routes,"/topic/create/submit/")
routes = append(routes,"/topics/create/")
routes = append(routes,"/overview/")
routes = append(routes,"/uploads/")
routes = append(routes,"/static/")
routes = append(routes,"/reply/edit/submit/")
routes = append(routes,"/reply/delete/submit/")
routes = append(routes,"/topic/edit/submit/")
addEmptyRoutesToVestigo(routes, router)
b.Run("fifty-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/topic/delete/submit/")
routes = append(routes,"/topic/stick/submit/")
routes = append(routes,"/topic/unstick/submit/")
routes = append(routes,"/accounts/login/")
routes = append(routes,"/accounts/create/")
routes = append(routes,"/accounts/logout/")
routes = append(routes,"/accounts/login/submit/")
routes = append(routes,"/accounts/create/submit/")
routes = append(routes,"/user/edit/critical/")
routes = append(routes,"/user/edit/critical/submit/")
addEmptyRoutesToVestigo(routes, router)
b.Run("sixty-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
router = vestigo.NewRouter()
routes = append(routes,"/user/edit/avatar/")
routes = append(routes,"/user/edit/avatar/submit/")
routes = append(routes,"/user/edit/username/")
routes = append(routes,"/user/edit/username/submit/")
routes = append(routes,"/profile/reply/create/")
routes = append(routes,"/profile/reply/edit/submit/")
routes = append(routes,"/profile/reply/delete/submit/")
routes = append(routes,"/arcane/tower/")
routes = append(routes,"/magical/kingdom/")
routes = append(routes,"/insert/name/here/")
addEmptyRoutesToVestigo(routes, router)
b.Run("seventy-routes", func(b *testing.B) {
for i := 0; i < b.N; i++ {
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
router.ServeHTTP(w,req)
}
})
}*/
func addEmptyRoutesToCustom(routes []string, router *Router) { func addEmptyRoutesToCustom(routes []string, router *Router) {
for _, route := range routes { for _, route := range routes {
router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){}) router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){})
} }
} }
func BenchmarkCustomRouter(b *testing.B) { func BenchmarkCustomRouterSerial(b *testing.B) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil)) req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
routes := make([]string, 0) routes := make([]string, 0)
@ -1131,7 +999,7 @@ func BenchmarkCustomRouter(b *testing.B) {
}) })
} }
func BenchmarkParser(b *testing.B) { func BenchmarkParserSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -1165,7 +1033,7 @@ func BenchmarkParser(b *testing.B) {
}) })
} }
func BenchmarkBBCodePluginWithRegexp(b *testing.B) { func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -1214,7 +1082,7 @@ func BenchmarkBBCodePluginWithRegexp(b *testing.B) {
}) })
} }
func BenchmarkBBCodePluginWithoutCodeTag(b *testing.B) { func BenchmarkBBCodePluginWithoutCodeTagSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -1263,7 +1131,7 @@ func BenchmarkBBCodePluginWithoutCodeTag(b *testing.B) {
}) })
} }
func BenchmarkBBCodePluginWithFullParser(b *testing.B) { func BenchmarkBBCodePluginWithFullParserSerial(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) { b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -1320,6 +1188,186 @@ func TestLevels(t *testing.T) {
} }
} }
func TestStaticRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
static_w := httptest.NewRecorder()
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
static_handler := http.HandlerFunc(route_static)
static_handler.ServeHTTP(static_w,static_req)
if static_w.Code != 200 {
fmt.Println(static_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the static route!")
}
func TestTopicAdminRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
topic_w := httptest.NewRecorder()
topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil))
topic_req_admin := topic_req
topic_req_admin.AddCookie(&admin_uid_cookie)
topic_req_admin.AddCookie(&admin_session_cookie)
topic_handler := http.HandlerFunc(route_topic_id)
topic_handler.ServeHTTP(topic_w,topic_req_admin)
if topic_w.Code != 200 {
fmt.Println(topic_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the topic-admin route!")
}
func TestTopicGuestRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
topic_w := httptest.NewRecorder()
topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil))
topic_handler := http.HandlerFunc(route_topic_id)
topic_handler.ServeHTTP(topic_w,topic_req)
if topic_w.Code != 200 {
fmt.Println(topic_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the topic-guest route!")
}
func TestForumsAdminRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
forums_w := httptest.NewRecorder()
forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil))
forums_req_admin := forums_req
forums_req_admin.AddCookie(&admin_uid_cookie)
forums_req_admin.AddCookie(&admin_session_cookie)
forums_handler := http.HandlerFunc(route_forums)
forums_handler.ServeHTTP(forums_w,forums_req_admin)
if forums_w.Code != 200 {
fmt.Println(forums_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the forums-admin route!")
}
func TestForumsGuestRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
forums_w := httptest.NewRecorder()
forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil))
forums_handler := http.HandlerFunc(route_forums)
forums_handler.ServeHTTP(forums_w,forums_req)
if forums_w.Code != 200 {
fmt.Println(forums_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the forums-guest route!")
}
func TestForumAdminRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
admin, err := users.CascadeGet(1)
if err != nil {
panic(err)
}
if !admin.Is_Admin {
panic("UID1 is not an admin")
}
admin_uid_cookie := http.Cookie{Name:"uid",Value:"1",Path:"/",MaxAge: year}
admin_session_cookie := http.Cookie{Name:"session",Value: admin.Session,Path:"/",MaxAge: year}
forum_w := httptest.NewRecorder()
forum_req := httptest.NewRequest("get","/forum/2",bytes.NewReader(nil))
forum_req_admin := forum_req
forum_req_admin.AddCookie(&admin_uid_cookie)
forum_req_admin.AddCookie(&admin_session_cookie)
forum_handler := http.HandlerFunc(route_forum)
forum_handler.ServeHTTP(forum_w,forum_req_admin)
if forum_w.Code != 200 {
fmt.Println(forum_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the forum-admin route!")
}
func TestForumGuestRoute(t *testing.T) {
if !gloinited {
gloinit()
}
if !plugins_inited {
init_plugins()
}
forum_w := httptest.NewRecorder()
forum_req := httptest.NewRequest("get","/forum/2",bytes.NewReader(nil))
forum_handler := http.HandlerFunc(route_forum)
forum_handler.ServeHTTP(forum_w,forum_req)
if forum_w.Code != 200 {
fmt.Println(forum_w.Body)
panic("HTTP Error!")
}
fmt.Println("No problems found in the forum-guest route!")
}
/*func TestRoute(t *testing.T) { /*func TestRoute(t *testing.T) {
}*/ }*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

45
main.go
View File

@ -123,6 +123,29 @@ func init_templates() {
template.Must(templates.ParseGlob("pages/*")) template.Must(templates.ParseGlob("pages/*"))
} }
func init_static_files() {
log.Print("Loading the static files.")
err := filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
if f.IsDir() {
return nil
}
path = strings.Replace(path,"\\","/",-1)
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
path = strings.TrimPrefix(path,"public/")
log.Print("Added the '" + path + "' static file.")
static_files["/static/" + path] = SFile{data,compress_bytes_gzip(data),0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/public/" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)}
return nil
})
if err != nil {
log.Fatal(err)
}
}
func main(){ func main(){
//if profiling { //if profiling {
// f, err := os.Create("startup_cpu.prof") // f, err := os.Create("startup_cpu.prof")
@ -151,27 +174,7 @@ func main(){
topics = NewSqlTopicStore() topics = NewSqlTopicStore()
} }
log.Print("Loading the static files.") init_static_files()
err = filepath.Walk("./public", func(path string, f os.FileInfo, err error) error {
if f.IsDir() {
return nil
}
path = strings.Replace(path,"\\","/",-1)
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
path = strings.TrimPrefix(path,"public/")
log.Print("Added the '" + path + "' static file.")
static_files["/static/" + path] = SFile{data,compress_bytes_gzip(data),0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/public/" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)}
return nil
})
if err != nil {
log.Fatal(err)
}
external_sites["YT"] = "https://www.youtube.com/" external_sites["YT"] = "https://www.youtube.com/"
hooks["trow_assign"] = nil hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil hooks["rrow_assign"] = nil

View File

@ -57,6 +57,12 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
err = topics.Load(tid)
if err != nil {
LocalError("This topic no longer exists!",w,r,user)
return
}
if is_js == "0" { if is_js == "0" {
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
} else { } else {
@ -114,6 +120,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
} }
forums[fid].TopicCount -= 1 forums[fid].TopicCount -= 1
topics.Remove(tid)
} }
func route_stick_topic(w http.ResponseWriter, r *http.Request) { func route_stick_topic(w http.ResponseWriter, r *http.Request) {
@ -123,8 +130,7 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
var fid int topic, err := topics.CascadeGet(tid)
err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
PreError("The topic you tried to pin doesn't exist.",w,r) PreError("The topic you tried to pin doesn't exist.",w,r)
return return
@ -133,7 +139,7 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
user, ok := SimpleForumSessionCheck(w,r,fid) user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
if !ok { if !ok {
return return
} }
@ -147,6 +153,8 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
topic.Sticky = true
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
} }
@ -157,8 +165,7 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
var fid int topic, err := topics.CascadeGet(tid)
err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
PreError("The topic you tried to unpin doesn't exist.",w,r) PreError("The topic you tried to unpin doesn't exist.",w,r)
return return
@ -167,7 +174,7 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
user, ok := SimpleForumSessionCheck(w,r,fid) user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
if !ok { if !ok {
return return
} }
@ -181,6 +188,8 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
topic.Sticky = false
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
} }
@ -312,6 +321,12 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
InternalErrorJSQ(err,w,r,is_js) InternalErrorJSQ(err,w,r,is_js)
} }
err = topics.Load(tid)
if err != nil {
LocalError("This topic no longer exists!",w,r,user)
return
}
} }
func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
@ -374,7 +389,6 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
LocalError("Bad Form",w,r,user) LocalError("Bad Form",w,r,user)
return return
} }
is_js := r.PostFormValue("is_js") is_js := r.PostFormValue("is_js")
if is_js == "" { if is_js == "" {
is_js = "0" is_js = "0"
@ -387,7 +401,7 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
} }
var uid int var uid int
err = db.QueryRow("SELECT uid from users_replies where rid = ?", rid).Scan(&uid) err = db.QueryRow("select uid from users_replies where rid = ?", rid).Scan(&uid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalErrorJSQ("The reply you tried to delete doesn't exist.",w,r,user,is_js) LocalErrorJSQ("The reply you tried to delete doesn't exist.",w,r,user,is_js)
return return
@ -502,6 +516,12 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
err = users.Load(uid)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther) http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther)
} }
@ -546,6 +566,12 @@ func route_unban(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
err = users.Load(uid)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther) http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther)
} }
@ -595,6 +621,12 @@ func route_activate(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
err = users.Load(uid)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther) http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther)
} }
@ -973,7 +1005,7 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) {
sname := r.URL.Path[len("/panel/settings/edit/submit/"):] sname := r.URL.Path[len("/panel/settings/edit/submit/"):]
scontent := r.PostFormValue("setting-value") scontent := r.PostFormValue("setting-value")
err = db.QueryRow("SELECT name, type, constraints from settings where name = ?", sname).Scan(&sname, &stype, &sconstraints) err = db.QueryRow("select name, type, constraints from settings where name = ?", sname).Scan(&sname, &stype, &sconstraints)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalError("The setting you want to edit doesn't exist.",w,r,user) LocalError("The setting you want to edit doesn't exist.",w,r,user)
return return
@ -1208,15 +1240,13 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request){
return return
} }
var err error uid, err := strconv.Atoi(r.URL.Path[len("/panel/users/edit/"):])
targetUser := User{ID: 0,}
targetUser.ID, err = strconv.Atoi(r.URL.Path[len("/panel/users/edit/"):])
if err != nil { if err != nil {
LocalError("The provided User ID is not a valid number.",w,r,user) LocalError("The provided User ID is not a valid number.",w,r,user)
return return
} }
err = db.QueryRow("select `name`,`email`,`group` from `users` where `uid` = ?", targetUser.ID).Scan(&targetUser.Name,&targetUser.Email,&targetUser.Group) targetUser, err := users.Get(uid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalError("The user you're trying to edit doesn't exist.",w,r,user) LocalError("The user you're trying to edit doesn't exist.",w,r,user)
return return
@ -1225,8 +1255,6 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request){
return return
} }
targetUser.Is_Admin = targetUser.Is_Super_Admin || groups[targetUser.Group].Is_Admin
targetUser.Is_Super_Mod = groups[targetUser.Group].Is_Mod || targetUser.Is_Admin
if targetUser.Is_Admin && !user.Is_Admin { if targetUser.Is_Admin && !user.Is_Admin {
LocalError("Only administrators can edit the account of an administrator.",w,r,user) LocalError("Only administrators can edit the account of an administrator.",w,r,user)
return return
@ -1264,15 +1292,13 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request){
return return
} }
var err error tid, err := strconv.Atoi(r.URL.Path[len("/panel/users/edit/submit/"):])
targetUser := User{ID: 0,}
targetUser.ID, err = strconv.Atoi(r.URL.Path[len("/panel/users/edit/submit/"):])
if err != nil { if err != nil {
LocalError("The provided User ID is not a valid number.",w,r,user) LocalError("The provided User ID is not a valid number.",w,r,user)
return return
} }
err = db.QueryRow("select `name`,`email`,`group` from `users` where `uid` = ?", targetUser.ID).Scan(&targetUser.Name, &targetUser.Email, &targetUser.Group) targetUser, err := users.Get(tid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalError("The user you're trying to edit doesn't exist.",w,r,user) LocalError("The user you're trying to edit doesn't exist.",w,r,user)
return return
@ -1281,8 +1307,6 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request){
return return
} }
targetUser.Is_Admin = targetUser.Is_Super_Admin || groups[targetUser.Group].Is_Admin
targetUser.Is_Super_Mod = groups[targetUser.Group].Is_Mod || targetUser.Is_Admin
if targetUser.Is_Admin && !user.Is_Admin { if targetUser.Is_Admin && !user.Is_Admin {
LocalError("Only administrators can edit the account of an administrator.",w,r,user) LocalError("Only administrators can edit the account of an administrator.",w,r,user)
return return
@ -1340,6 +1364,12 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request){
SetPassword(targetUser.ID, newpassword) SetPassword(targetUser.ID, newpassword)
} }
err = users.Load(targetUser.ID)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
http.Redirect(w,r,"/panel/users/edit/" + strconv.Itoa(targetUser.ID),http.StatusSeeOther) http.Redirect(w,r,"/panel/users/edit/" + strconv.Itoa(targetUser.ID),http.StatusSeeOther)
} }

View File

@ -9,6 +9,8 @@ import "strconv"
import "encoding/json" import "encoding/json"
var db *sql.DB var db *sql.DB
var db_version string
var get_user_stmt *sql.Stmt var get_user_stmt *sql.Stmt
var get_full_user_stmt *sql.Stmt var get_full_user_stmt *sql.Stmt
var get_topic_list_stmt *sql.Stmt var get_topic_list_stmt *sql.Stmt
@ -92,6 +94,9 @@ func init_database(err error) {
log.Fatal(err) log.Fatal(err)
} }
// Getting the database version..
db.QueryRow("SELECT VERSION()").Scan(&db_version)
/*log.Print("Preparing get_session statement.") /*log.Print("Preparing get_session statement.")
get_session_stmt, err = db.Prepare("select `uid`,`name`,`group`,`is_super_admin`,`session`,`email`,`avatar`,`message`,`url_prefix`,`url_name`,`level`,`score`,`last_ip` from `users` where `uid` = ? and `session` = ? AND `session` <> ''") get_session_stmt, err = db.Prepare("select `uid`,`name`,`group`,`is_super_admin`,`session`,`email`,`avatar`,`message`,`url_prefix`,`url_name`,`level`,`score`,`last_ip` from `users` where `uid` = ? and `session` = ? AND `session` <> ''")
if err != nil { if err != nil {

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -153,6 +153,8 @@ func init() {
ExtData: make(map[string]bool), ExtData: make(map[string]bool),
} }
guest_user.Perms = GuestPerms
if debug { if debug {
fmt.Printf("Guest Perms: ") fmt.Printf("Guest Perms: ")
fmt.Printf("%+v\n", GuestPerms) fmt.Printf("%+v\n", GuestPerms)

View File

@ -28,17 +28,13 @@ func (router *Router) HandleFunc(pattern string, handle func(http.ResponseWriter
} }
func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
router.mu.RLock()
if req.URL.Path[0] != '/' { if req.URL.Path[0] != '/' {
router.mu.RUnlock()
w.WriteHeader(405) w.WriteHeader(405)
w.Write([]byte("")) w.Write([]byte(""))
return return
} }
// Do something on the path to turn slashes facing the wrong way "\" into "/" slashes. Like what? Wouldn't that be slow? Might need to move to fasthttp for this router.mu.RLock()
handle, ok := router.routes[req.URL.Path] handle, ok := router.routes[req.URL.Path]
if ok { if ok {
router.mu.RUnlock() router.mu.RUnlock()

View File

@ -113,7 +113,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
return return
} }
topicItem := TopicsRow{ID: 0,} topicItem := TopicsRow{ID: 0}
for rows.Next() { for rows.Next() {
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.LikeCount, &topicItem.CreatedByName, &topicItem.Avatar) err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.LikeCount, &topicItem.CreatedByName, &topicItem.Avatar)
if err != nil { if err != nil {
@ -316,33 +316,25 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return return
} }
if !user.Perms.ViewTopic { if !user.Perms.ViewTopic {
//fmt.Printf("%+v\n", user.Perms)
NoPermissions(w,r,user) NoPermissions(w,r,user)
return return
} }
topic.ContentLines = strings.Count(topic.Content,"\n")
topic.Content = parse_message(topic.Content) topic.Content = parse_message(topic.Content)
topic.ContentLines = strings.Count(topic.Content,"\n")
// We don't want users posting in locked topics... // We don't want users posting in locked topics...
if topic.Is_Closed && !user.Is_Mod { if topic.Is_Closed && !user.Is_Mod {
user.Perms.CreateReply = false user.Perms.CreateReply = false
} }
if topic.Avatar != "" { if groups[topic.Group].Is_Mod {
if topic.Avatar[0] == '.' {
topic.Avatar = "/uploads/avatar_" + strconv.Itoa(topic.CreatedBy) + topic.Avatar
}
} else {
topic.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topic.CreatedBy),1)
}
if groups[topic.Group].Is_Mod || groups[topic.Group].Is_Admin {
topic.Css = staff_css_tmpl topic.Css = staff_css_tmpl
topic.Level = -1 topic.Level = -1
} }
topic.Tag = groups[topic.Group].Tag /*if settings["url_tags"] == false {
if settings["url_tags"] == false {
topic.URLName = "" topic.URLName = ""
} else { } else {
topic.URL, ok = external_sites[topic.URLPrefix] topic.URL, ok = external_sites[topic.URLPrefix]
@ -351,7 +343,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else { } else {
topic.URL = topic.URL + topic.URLName topic.URL = topic.URL + topic.URLName
} }
} }*/
// Calculate the offset // Calculate the offset
last_page := int(topic.PostCount / items_per_page) + 1 last_page := int(topic.PostCount / items_per_page) + 1
@ -415,7 +407,6 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
replyItem.URL = replyItem.URL + replyItem.URLName replyItem.URL = replyItem.URL + replyItem.URLName
} }
}*/ }*/
replyItem.Liked = false replyItem.Liked = false
if hooks["rrow_assign"] != nil { if hooks["rrow_assign"] != nil {
@ -465,19 +456,19 @@ func route_profile(w http.ResponseWriter, r *http.Request){
replyList []Reply replyList []Reply
) )
puser := User{ID: 0,} pid, err := strconv.Atoi(r.URL.Path[len("/user/"):])
puser.ID, err = strconv.Atoi(r.URL.Path[len("/user/"):])
if err != nil { if err != nil {
LocalError("The provided TopicID is not a valid number.",w,r,user) LocalError("The provided User ID is not a valid number.",w,r,user)
return return
} }
if puser.ID == user.ID { var puser *User
if pid == user.ID {
user.Is_Mod = true user.Is_Mod = true
puser = user puser = &user
} else { } else {
// Fetch the user data // Fetch the user data
err = get_user_stmt.QueryRow(puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level) puser, err = users.CascadeGet(pid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
NotFound(w,r) NotFound(w,r)
return return
@ -485,24 +476,6 @@ func route_profile(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
puser.Is_Admin = puser.Is_Super_Admin || groups[puser.Group].Is_Admin
puser.Is_Super_Mod = puser.Is_Admin || groups[puser.Group].Is_Mod
puser.Is_Mod = puser.Is_Super_Mod
puser.Is_Banned = groups[puser.Group].Is_Banned
if puser.Is_Banned && puser.Is_Super_Mod {
puser.Is_Banned = false
}
}
puser.Tag = groups[puser.Group].Tag
if puser.Avatar != "" {
if puser.Avatar[0] == '.' {
puser.Avatar = "/uploads/avatar_" + strconv.Itoa(puser.ID) + puser.Avatar
}
} else {
puser.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(puser.ID),1)
} }
// Get the replies.. // Get the replies..
@ -553,7 +526,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
return return
} }
ppage := ProfilePage{puser.Name + "'s Profile",user,noticeList,replyList,puser,false} ppage := ProfilePage{puser.Name + "'s Profile",user,noticeList,replyList,*puser,false}
if template_profile_handle != nil { if template_profile_handle != nil {
template_profile_handle(ppage,w) template_profile_handle(ppage,w)
} else { } else {
@ -1213,6 +1186,11 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return return
} }
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext
err = users.Load(user.ID)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
noticeList = append(noticeList, "Your avatar was successfully updated") noticeList = append(noticeList, "Your avatar was successfully updated")
pi := Page{"Edit Avatar",user,noticeList,tList,nil} pi := Page{"Edit Avatar",user,noticeList,tList,nil}
@ -1253,7 +1231,13 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
LocalError("Unable to change the username. Does someone else already have this name?",w,r,user) LocalError("Unable to change the username. Does someone else already have this name?",w,r,user)
return return
} }
user.Name = new_username user.Name = new_username
err = users.Load(user.ID)
if err != nil {
LocalError("Your account doesn't exist!",w,r,user)
return
}
noticeList = append(noticeList,"Your username was successfully updated") noticeList = append(noticeList,"Your username was successfully updated")
pi := Page{"Edit Username",user,noticeList,tList,nil} pi := Page{"Edit Username",user,noticeList,tList,nil}
@ -1305,7 +1289,7 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
if !enable_emails { if !enable_emails {
noticeList = append(noticeList, "The email system has been turned off. All features involving sending emails have been disabled.") noticeList = append(noticeList, "The email system has been turned off. All features involving sending emails have been disabled.")
} }
pi := Page{"Email Manager",user,noticeList,emailList,0} pi := Page{"Email Manager",user,noticeList,emailList,nil}
templates.ExecuteTemplate(w,"account-own-edit-email.html", pi) templates.ExecuteTemplate(w,"account-own-edit-email.html", pi)
} }
@ -1376,7 +1360,7 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
noticeList = append(noticeList,"The email system has been turned off. All features involving sending emails have been disabled.") noticeList = append(noticeList,"The email system has been turned off. All features involving sending emails have been disabled.")
} }
noticeList = append(noticeList,"Your email was successfully verified") noticeList = append(noticeList,"Your email was successfully verified")
pi := Page{"Email Manager",user,noticeList,emailList,0} pi := Page{"Email Manager",user,noticeList,emailList,nil}
templates.ExecuteTemplate(w,"account-own-edit-email.html", pi) templates.ExecuteTemplate(w,"account-own-edit-email.html", pi)
} }
@ -1395,6 +1379,12 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r) InternalError(err,w,r)
return return
} }
err = users.Load(user.ID)
if err != nil {
LocalError("Your account doesn't exist!",w,r,user)
return
}
http.Redirect(w,r, "/", http.StatusSeeOther) http.Redirect(w,r, "/", http.StatusSeeOther)
} }

View File

@ -1,7 +1,7 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io"
import "strconv" import "strconv"
import "io"
func init() { func init() {
template_forum_handle = template_forum template_forum_handle = template_forum

View File

@ -1,7 +1,7 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "strconv"
import "io" import "io"
import "strconv"
func init() { func init() {
template_forums_handle = template_forums template_forums_handle = template_forums

View File

@ -1,7 +1,7 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "strconv"
import "io" import "io"
import "strconv"
func init() { func init() {
template_topic_handle = template_topic template_topic_handle = template_topic

View File

@ -871,6 +871,7 @@ func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect refle
} }
func (c *CTemplateSet) compile_command(*parse.CommandNode) (out string) { func (c *CTemplateSet) compile_command(*parse.CommandNode) (out string) {
panic("Uh oh! Something went wrong!")
return "" return ""
} }

View File

@ -1,657 +0,0 @@
package main
import "log"
import "fmt"
import "strings"
import "reflect"
import "path/filepath"
import "io/ioutil"
import "text/template/parse"
/* Keeping this so I can benchmark against it */
type CTemplateSet2 struct
{
tlist map[string]*parse.Tree
dir string
funcMap map[string]interface{}
importMap map[string]string
varList map[string]VarItem
localVars map[string]map[string]VarItemReflect
//tempVars map[string]string
doImports bool
expectsInt interface{}
}
func (c *CTemplateSet2) compile_template_2(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string) {
c.dir = dir
c.doImports = true
c.funcMap = make(map[string]interface{})
c.funcMap["and"] = "&&"
c.funcMap["not"] = "!"
c.funcMap["or"] = "||"
c.funcMap["eq"] = true
c.funcMap["ge"] = true
c.funcMap["gt"] = true
c.funcMap["le"] = true
c.funcMap["lt"] = true
c.funcMap["ne"] = true
c.importMap = make(map[string]string)
c.importMap["strconv"] = "strconv"
c.varList = varList
c.expectsInt = expectsInt
holdreflect := reflect.ValueOf(expectsInt)
res, err := ioutil.ReadFile(dir + name)
if err != nil {
log.Fatal(err)
}
content := string(res)
tree := parse.New(name, c.funcMap)
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
tree, err = tree.Parse(content,"{{","}}", treeSet, c.funcMap)
if err != nil {
log.Fatal(err)
}
if debug {
fmt.Println(name)
}
out = ""
fname := strings.TrimSuffix(name, filepath.Ext(name))
c.tlist = make(map[string]*parse.Tree)
c.tlist[fname] = tree
varholder := "tmpl_" + fname + "_vars"
if debug {
fmt.Println(c.tlist)
}
c.localVars = make(map[string]map[string]VarItemReflect)
c.localVars[fname] = make(map[string]VarItemReflect)
c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect}
subtree := c.tlist[fname]
if debug {
fmt.Println(subtree.Root)
}
for _, node := range subtree.Root.Nodes {
if debug {
fmt.Println("Node: " + node.String())
}
out += c.compile_switch(varholder, holdreflect, fname, node)
}
var importList string
if c.doImports {
for _, item := range c.importMap {
importList += "import \"" + item + "\"\n"
}
}
var varString string
for _, varItem := range c.varList {
varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
}
out = "package main\n" + importList + "\nfunc init() {\nctemplates[\"" + fname + "\"] = template_" + fname + "\n}\n\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ") (tmpl string) {\n" + varString + out + "return tmpl\n}\n"
if debug {
fmt.Println("Output!")
fmt.Println(out)
}
return out
}
func (c *CTemplateSet2) compile_switch(varholder string, holdreflect reflect.Value, template_name string, node interface{}) (out string) {
switch node := node.(type) {
case *parse.ActionNode:
if debug {
fmt.Println("Action Node")
}
if node.Pipe == nil {
break
}
for _, cmd := range node.Pipe.Cmds {
out += c.compile_subswitch(varholder, holdreflect, template_name, cmd)
}
return out
case *parse.IfNode:
if debug {
fmt.Println("If Node: ")
fmt.Println(node.Pipe)
}
var expr string
for _, cmd := range node.Pipe.Cmds {
if debug {
fmt.Println("If Node Bit: ")
fmt.Println(cmd)
fmt.Println(reflect.ValueOf(cmd).Type().Name())
}
expr += c.compile_varswitch(varholder, holdreflect, template_name, cmd)
}
if node.ElseList == nil {
if debug {
fmt.Println("Branch 1")
}
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "}\n"
} else {
if debug {
fmt.Println("Branch 2")
}
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "} else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
}
case *parse.ListNode:
if debug {
fmt.Println("List Node")
}
for _, subnode := range node.Nodes {
out += c.compile_switch(varholder, holdreflect, template_name, subnode)
}
return out
case *parse.RangeNode:
if debug {
fmt.Println("Range Node!")
fmt.Println(node.Pipe)
}
var outVal reflect.Value
for _, cmd := range node.Pipe.Cmds {
if debug {
fmt.Println("Range Bit: ")
fmt.Println(cmd)
}
out, outVal = c.compile_reflectswitch(varholder, holdreflect, template_name, cmd)
}
if debug {
fmt.Println("Returned: ")
fmt.Println(out)
fmt.Println("Range Kind Switch!")
}
switch outVal.Kind() {
case reflect.Map:
var item reflect.Value
for _, key := range outVal.MapKeys() {
item = outVal.MapIndex(key)
}
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compile_switch("item", item, template_name, node.List) + "}\n}"
case reflect.Invalid:
return ""
}
if node.ElseList != nil {
out += " else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
} else {
out += "\n"
}
return out
case *parse.TemplateNode:
if debug {
fmt.Println("Template Node")
}
return c.compile_subtemplate(varholder, holdreflect, node)
case *parse.TextNode:
return "tmpl += `" + string(node.Text) + "`\n"
default:
panic("Unknown Node in main switch")
}
return ""
}
func (c *CTemplateSet2) compile_subswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
cur := holdreflect
var varbit string
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
varbit += ".(" + cur.Type().Name() + ")"
}
for _, id := range n.Ident {
if debug {
fmt.Println("Data Kind: ")
fmt.Println(cur.Kind().String())
fmt.Println("Field Bit: ")
fmt.Println(id)
}
cur = cur.FieldByName(id)
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
/*if cur.Kind() == reflect.String && cur.Type().Name() != "string" {
varbit = "string(" + varbit + "." + id + ")"*/
//if cur.Kind() == reflect.String && cur.Type().Name() != "string" {
if cur.Type().PkgPath() != "main" {
c.importMap["html/template"] = "html/template"
varbit += "." + id + ".(" + strings.TrimPrefix(cur.Type().PkgPath(),"html/") + "." + cur.Type().Name() + ")"
} else {
varbit += "." + id + ".(" + cur.Type().Name() + ")"
}
} else {
varbit += "." + id
}
if debug {
fmt.Println("End Cycle")
}
}
out = c.compile_varsub(varholder + varbit, cur)
for _, varItem := range c.varList {
if strings.HasPrefix(out, varItem.Destination) {
out = strings.Replace(out, varItem.Destination, varItem.Name, 1)
}
}
return out
case *parse.DotNode:
if debug {
fmt.Println("Dot Node")
fmt.Println(node.String())
}
return c.compile_varsub(varholder, holdreflect)
case *parse.NilNode:
panic("Nil is not a command x.x")
case *parse.VariableNode:
if debug {
fmt.Println("Variable Node")
fmt.Println(n.String())
fmt.Println(n.Ident)
}
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
return "tmpl += " + out + "\n"
case *parse.StringNode:
return n.Quoted
default:
fmt.Println("Unknown Kind: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Kind())
fmt.Println("Unknown Type: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Type().Name())
panic("I don't know what node this is")
}
return ""
}
func (c *CTemplateSet2) compile_varswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
for _, id := range n.Ident {
fmt.Println("Field Bit: ")
fmt.Println(id)
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c.compile_boolsub(n.String(), varholder, template_name, holdreflect)
case *parse.ChainNode:
if debug {
fmt.Println("Chain Node: ")
fmt.Println(n.Node)
fmt.Println(node.Args)
}
break
case *parse.IdentifierNode:
if debug {
fmt.Println("Identifier Node: ")
fmt.Println(node)
fmt.Println(node.Args)
}
return c.compile_identswitch(varholder, holdreflect, template_name, node)
case *parse.DotNode:
return varholder
case *parse.VariableNode:
if debug {
fmt.Println("Variable Node")
fmt.Println(n.String())
fmt.Println(n.Ident)
}
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
return out
case *parse.NilNode:
panic("Nil is not a command x.x")
case *parse.PipeNode:
if debug {
fmt.Println("Pipe Node!")
fmt.Println(n)
}
/*for _, cmd := range n.Cmds {
if debug {
fmt.Println("Pipe Bit: ")
fmt.Println(cmd)
}
out += c.compile_if_varsub_n(n.String(), varholder, template_name, holdreflect)
}*/
if debug {
fmt.Println("Args: ")
fmt.Println(node.Args)
}
/*argcopy := node.Args[1:]
for _, arg := range argcopy {
if debug {
fmt.Println("Pipe Arg: ")
fmt.Println(arg)
fmt.Println(reflect.ValueOf(arg).Elem().Type().Name())
fmt.Println(reflect.ValueOf(arg).Kind())
}
switch arg.(type) {
case *parse.IdentifierNode:
out += c.compile_identswitch(varholder, holdreflect, template_name, node)
break
case *parse.PipeNode:
break
//out += c.compile_if_varsub_n(a.String(), varholder, template_name, holdreflect)
default:
panic("Unknown Pipe Arg type! Did Mario get stuck in the pipes again?")
}
//out += c.compile_varswitch(arg.String(), holdreflect, template_name, arg)
}*/
out += c.compile_identswitch(varholder, holdreflect, template_name, node)
if debug {
fmt.Println("Out: ")
fmt.Println(out)
}
return out
default:
fmt.Println("Unknown Kind: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Kind())
fmt.Println("Unknown Type: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Type().Name())
panic("I don't know what node this is! Grr...")
}
return ""
}
func (c *CTemplateSet2) compile_identswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
ArgLoop:
for pos, id := range node.Args {
if debug {
fmt.Println(id)
}
switch id.String() {
case "not":
out += "!"
case "or":
out += " || "
case "and":
out += " && "
case "le":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
default:
if debug {
fmt.Println("Variable!")
}
out += c.compile_if_varsub_n(id.String(), varholder, template_name, holdreflect)
}
}
return out
}
func (c *CTemplateSet2) compile_reflectswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string, outVal reflect.Value) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
for _, id := range n.Ident {
fmt.Println("Field Bit: ")
fmt.Println(id)
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
case *parse.ChainNode:
if debug {
fmt.Println("Chain Node: ")
fmt.Println(n.Node)
fmt.Println(node.Args)
}
return "", outVal
/*case *parse.IdentifierNode:
fmt.Println("Identifier Node: ")
fmt.Println(node)
fmt.Println(node.Args)
ArgLoop:
for pos, id := range node.Args {
fmt.Println(id)
switch id.String() {
case "not":
out += "!"
case "or":
out += " || "
case "and":
out += " && "
case "le":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, holdreflect)
break ArgLoop
default:
fmt.Println("Variable!")
out += c.compile_if_varsub_n(id.String(), varholder, holdreflect)
}
}
return out*/
case *parse.DotNode:
return varholder, holdreflect
case *parse.NilNode:
panic("Nil is not a command x.x")
default:
//panic("I don't know what node this is")
}
return "", outVal
}
func (c *CTemplateSet2) compile_if_varsub_n(varname string, varholder string, template_name string, cur reflect.Value) (out string) {
out, _ = c.compile_if_varsub(varname, varholder, template_name, cur)
return out
}
func (c *CTemplateSet2) compile_if_varsub(varname string, varholder string, template_name string, cur reflect.Value) (out string, val reflect.Value) {
if varname[0] != '.' && varname[0] != '$' {
return varname, cur
}
bits := strings.Split(varname,".")
if varname[0] == '$' {
var res VarItemReflect
if varname[1] == '.' {
res = c.localVars[template_name]["."]
} else {
res = c.localVars[template_name][strings.TrimPrefix(bits[0],"$")]
}
out += res.Destination
cur = res.Value
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
}
} else {
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
out += varholder + ".(" + cur.Type().Name() + ")"
} else {
out += varholder
}
}
bits[0] = strings.TrimPrefix(bits[0],"$")
if debug {
fmt.Println("Cur Kind: ")
fmt.Println(cur.Kind())
fmt.Println("Cur Type: ")
fmt.Println(cur.Type().Name())
}
for _, bit := range bits {
if debug {
fmt.Println("Variable Field!")
fmt.Println(bit)
}
if bit == "" {
continue
}
cur = cur.FieldByName(bit)
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
out += "." + bit + ".(" + cur.Type().Name() + ")"
} else {
out += "." + bit
}
if debug {
fmt.Println("Data Kind: ")
fmt.Println(cur.Kind())
fmt.Println("Data Type: ")
fmt.Println(cur.Type().Name())
}
}
for _, varItem := range c.varList {
if strings.HasPrefix(out, varItem.Destination) {
out = strings.Replace(out, varItem.Destination, varItem.Name, 1)
}
}
return out, cur
}
func (c *CTemplateSet2) compile_boolsub(varname string, varholder string, template_name string, val reflect.Value) string {
out, val := c.compile_if_varsub(varname, varholder, template_name, val)
switch val.Kind() {
case reflect.Int:
out += " > 0"
case reflect.Bool:
// Do nothing
case reflect.String:
out += " != \"\""
case reflect.Int64:
out += " > 0"
default:
panic("I don't know what this variable's type is o.o\n")
}
return out
}
func (c *CTemplateSet2) compile_varsub(varname string, val reflect.Value) string {
for _, varItem := range c.varList {
if strings.HasPrefix(varname, varItem.Destination) {
varname = strings.Replace(varname, varItem.Destination, varItem.Name, 1)
}
}
if val.Kind() == reflect.Interface {
val = val.Elem()
}
switch val.Kind() {
case reflect.Int:
return "tmpl += strconv.Itoa(" + varname + ")\n"
case reflect.Bool:
return "if " + varname + " {\ntmpl += \"true\"} else {\ntmpl += \"false\"\n}\n"
case reflect.String:
if val.Type().Name() != "string" && !strings.HasPrefix(varname,"string(") {
return "tmpl += string(" + varname + ")\n"
} else {
return "tmpl += " + varname + "\n"
}
case reflect.Int64:
return "tmpl += strconv.FormatInt(" + varname + ", 10)"
default:
fmt.Println("Unknown Kind: ")
fmt.Println(val.Kind())
fmt.Println("Unknown Type: ")
fmt.Println(val.Type().Name())
panic("// I don't know what this variable's type is o.o\n")
}
}
func (c *CTemplateSet2) compile_subtemplate(pvarholder string, pholdreflect reflect.Value, node *parse.TemplateNode) (out string) {
if debug {
fmt.Println("Template Node: " + node.Name)
}
fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name))
varholder := "tmpl_" + fname + "_vars"
var holdreflect reflect.Value
if node.Pipe != nil {
for _, cmd := range node.Pipe.Cmds {
firstWord := cmd.Args[0]
switch firstWord.(type) {
case *parse.DotNode:
varholder = pvarholder
holdreflect = pholdreflect
break
case *parse.NilNode:
panic("Nil is not a command x.x")
default:
out = "var " + varholder + " := false\n"
out += c.compile_command(cmd)
}
}
}
res, err := ioutil.ReadFile(c.dir + node.Name)
if err != nil {
log.Fatal(err)
}
content := string(res)
tree := parse.New(node.Name, c.funcMap)
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
tree, err = tree.Parse(content,"{{","}}", treeSet, c.funcMap)
if err != nil {
log.Fatal(err)
}
c.tlist[fname] = tree
subtree := c.tlist[fname]
if debug {
fmt.Println(subtree.Root)
}
c.localVars[fname] = make(map[string]VarItemReflect)
c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect}
for _, node := range subtree.Root.Nodes {
if debug {
fmt.Println("Node: " + node.String())
}
out += c.compile_switch(varholder, holdreflect, fname, node)
}
return out
}
func (c *CTemplateSet2) compile_command(*parse.CommandNode) (out string) {
return ""
}

View File

@ -80,9 +80,11 @@ type TopicsRow struct
} }
type TopicStore interface { type TopicStore interface {
Load(id int) error
Get(id int) (*Topic, error) Get(id int) (*Topic, error)
GetUnsafe(id int) (*Topic, error) GetUnsafe(id int) (*Topic, error)
CascadeGet(id int) (*Topic, error) CascadeGet(id int) (*Topic, error)
Set(item *Topic) error
Add(item *Topic) error Add(item *Topic) error
AddUnsafe(item *Topic) error AddUnsafe(item *Topic) error
Remove(id int) error Remove(id int) error
@ -137,6 +139,31 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
return topic, err return topic, err
} }
func (sts *StaticTopicStore) Load(id int) error {
topic := &Topic{ID:id}
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
if err == nil {
sts.Set(topic)
}
return err
}
func (sts *StaticTopicStore) Set(item *Topic) error {
sts.mu.Lock()
item, ok := sts.items[item.ID]
if ok {
sts.items[item.ID] = item
} else if sts.length >= sts.capacity {
sts.mu.Unlock()
return ErrStoreCapacityOverflow
} else {
sts.items[item.ID] = item
}
sts.mu.Unlock()
sts.length++
return nil
}
func (sts *StaticTopicStore) Add(item *Topic) error { func (sts *StaticTopicStore) Add(item *Topic) error {
if sts.length >= sts.capacity { if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
@ -218,7 +245,16 @@ func (sus *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
return &topic, err return &topic, err
} }
func (sus *SqlTopicStore) Load(id int) error {
topic := Topic{ID:id}
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
return err
}
// Placeholder methods, the actual queries are done elsewhere // Placeholder methods, the actual queries are done elsewhere
func (sus *SqlTopicStore) Set(item *Topic) error {
return nil
}
func (sus *SqlTopicStore) Add(item *Topic) error { func (sus *SqlTopicStore) Add(item *Topic) error {
return nil return nil
} }
@ -252,6 +288,7 @@ func get_topicuser(tid int) (TopicUser,error) {
if err != nil { if err != nil {
return TopicUser{ID:tid}, err return TopicUser{ID:tid}, err
} }
init_user_perms(user)
// We might be better off just passing seperate topic and user structs to the caller? // We might be better off just passing seperate topic and user structs to the caller?
return copy_topic_to_topicuser(topic, user), nil return copy_topic_to_topicuser(topic, user), nil
@ -264,13 +301,8 @@ func get_topicuser(tid int) (TopicUser,error) {
if err != nil { if err != nil {
return TopicUser{ID:tid}, err return TopicUser{ID:tid}, err
} }
init_user_perms(user)
tu := copy_topic_to_topicuser(topic, user) tu := copy_topic_to_topicuser(topic, user)
//fmt.Printf("%+v\n", topic)
//fmt.Println("")
//fmt.Printf("%+v\n", user)
//fmt.Println("")
//fmt.Printf("%+v\n", tu)
//fmt.Println("")
return tu, nil return tu, nil
} }
} }
@ -280,7 +312,9 @@ func get_topicuser(tid int) (TopicUser,error) {
the_topic := Topic{ID:tu.ID, Title:tu.Title, Content:tu.Content, CreatedBy:tu.CreatedBy, Is_Closed:tu.Is_Closed, Sticky:tu.Sticky, CreatedAt:tu.CreatedAt, LastReplyAt:tu.LastReplyAt, ParentID:tu.ParentID, IpAddress:tu.IpAddress, PostCount:tu.PostCount, LikeCount:tu.LikeCount} the_topic := Topic{ID:tu.ID, Title:tu.Title, Content:tu.Content, CreatedBy:tu.CreatedBy, Is_Closed:tu.Is_Closed, Sticky:tu.Sticky, CreatedAt:tu.CreatedAt, LastReplyAt:tu.LastReplyAt, ParentID:tu.ParentID, IpAddress:tu.IpAddress, PostCount:tu.PostCount, LikeCount:tu.LikeCount}
//fmt.Printf("%+v\n", the_topic) //fmt.Printf("%+v\n", the_topic)
tu.Tag = groups[tu.Group].Tag
topics.Add(&the_topic) topics.Add(&the_topic)
//err = errors.Error("Loaded data via query")
return tu, err return tu, err
} }

139
user.go
View File

@ -9,6 +9,8 @@ import "golang.org/x/crypto/bcrypt"
import "database/sql" import "database/sql"
import _ "github.com/go-sql-driver/mysql" import _ "github.com/go-sql-driver/mysql"
var guest_user User = User{ID:0,Group:6,Perms:GuestPerms}
type User struct type User struct
{ {
ID int ID int
@ -44,9 +46,11 @@ type Email struct
} }
type UserStore interface { type UserStore interface {
Load(id int) error
Get(id int) (*User, error) Get(id int) (*User, error)
GetUnsafe(id int) (*User, error) GetUnsafe(id int) (*User, error)
CascadeGet(id int) (*User, error) CascadeGet(id int) (*User, error)
Set(item *User) error
Add(item *User) error Add(item *User) error
AddUnsafe(item *User) error AddUnsafe(item *User) error
Remove(id int) error Remove(id int) error
@ -94,12 +98,58 @@ func (sts *StaticUserStore) CascadeGet(id int) (*User, error) {
user = &User{ID:id} user = &User{ID:id}
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Tag = groups[user.Group].Tag
init_user_perms(user)
if err == nil { if err == nil {
sts.Add(user) sts.Add(user)
} }
return user, err return user, err
} }
func (sts *StaticUserStore) Load(id int) error {
user := &User{ID:id}
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if err != nil {
return err
}
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Tag = groups[user.Group].Tag
init_user_perms(user)
sts.Set(user)
return nil
}
func (sts *StaticUserStore) Set(item *User) error {
sts.mu.Lock()
item, ok := sts.items[item.ID]
if ok {
sts.items[item.ID] = item
} else if sts.length >= sts.capacity {
sts.mu.Unlock()
return ErrStoreCapacityOverflow
} else {
sts.items[item.ID] = item
}
sts.mu.Unlock()
sts.length++
return nil
}
func (sts *StaticUserStore) Add(item *User) error { func (sts *StaticUserStore) Add(item *User) error {
if sts.length >= sts.capacity { if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
@ -161,22 +211,62 @@ func NewSqlUserStore() *SqlUserStore {
func (sus *SqlUserStore) Get(id int) (*User, error) { func (sus *SqlUserStore) Get(id int) (*User, error) {
user := User{ID:id} user := User{ID:id}
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Tag = groups[user.Group].Tag
init_user_perms(&user)
return &user, err return &user, err
} }
func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) { func (sus *SqlUserStore) GetUnsafe(id int) (*User, error) {
user := User{ID:id} user := User{ID:id}
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Tag = groups[user.Group].Tag
init_user_perms(&user)
return &user, err return &user, err
} }
func (sus *SqlUserStore) CascadeGet(id int) (*User, error) { func (sus *SqlUserStore) CascadeGet(id int) (*User, error) {
user := User{ID:id} user := User{ID:id}
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP) err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Tag = groups[user.Group].Tag
init_user_perms(&user)
return &user, err return &user, err
} }
func (sus *SqlUserStore) Load(id int) error {
user := &User{ID:id}
// Simplify this into a quick check whether the user exists
err := get_full_user_stmt.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
return err
}
// Placeholder methods, the actual queries are done elsewhere // Placeholder methods, the actual queries are done elsewhere
func (sus *SqlUserStore) Set(item *User) error {
return nil
}
func (sus *SqlUserStore) Add(item *User) error { func (sus *SqlUserStore) Add(item *User) error {
return nil return nil
} }
@ -258,6 +348,8 @@ func ForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user Us
} }
user, success = SimpleSessionCheck(w,r) user, success = SimpleSessionCheck(w,r)
fperms := groups[user.Group].Forums[fid] fperms := groups[user.Group].Forums[fid]
//fmt.Printf("%+v\n", user.Perms)
//fmt.Printf("%+v\n", fperms)
if fperms.Overrides && !user.Is_Super_Admin { if fperms.Overrides && !user.Is_Super_Admin {
user.Perms.ViewTopic = fperms.ViewTopic user.Perms.ViewTopic = fperms.ViewTopic
user.Perms.LikeItem = fperms.LikeItem user.Perms.LikeItem = fperms.LikeItem
@ -288,45 +380,28 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) {
// Are there any session cookies..? // Are there any session cookies..?
cookie, err := r.Cookie("uid") cookie, err := r.Cookie("uid")
if err != nil { if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true return guest_user, true
} }
uid, err := strconv.Atoi(cookie.Value) uid, err := strconv.Atoi(cookie.Value)
if err != nil { if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true return guest_user, true
} }
cookie, err = r.Cookie("session") cookie, err = r.Cookie("session")
if err != nil { if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true return guest_user, true
} }
// Is this session valid..? // Is this session valid..?
user, err := users.CascadeGet(uid) user, err := users.CascadeGet(uid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
user.ID = 0 return guest_user, true
user.Session = ""
user.Group = 6
user.Perms = GuestPerms
return *user, true
} else if err != nil { } else if err != nil {
InternalError(err,w,r) InternalError(err,w,r)
return *user, false return guest_user, false
} }
if user.Session == "" || cookie.Value != user.Session { if user.Session == "" || cookie.Value != user.Session {
user.ID = 0 return guest_user, true
user.Session = ""
user.Group = 6
user.Perms = GuestPerms
return *user, true
}
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
user.Is_Super_Mod = groups[user.Group].Is_Mod || user.Is_Admin
user.Is_Mod = user.Is_Super_Mod
user.Is_Banned = groups[user.Group].Is_Banned
user.Loggedin = !user.Is_Banned || user.Is_Super_Mod
if user.Is_Banned && user.Is_Super_Mod {
user.Is_Banned = false
} }
if user.Is_Super_Admin { if user.Is_Super_Admin {
@ -335,14 +410,6 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) {
user.Perms = groups[user.Group].Perms user.Perms = groups[user.Group].Perms
} }
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
host, _, err := net.SplitHostPort(r.RemoteAddr) host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil { if err != nil {
PreError("Bad IP",w,r) PreError("Bad IP",w,r)
@ -448,3 +515,13 @@ func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error
_, err = update_user_level_stmt.Exec(getLevel(user.Score - base_score - mod), uid) _, err = update_user_level_stmt.Exec(getLevel(user.Score - base_score - mod), uid)
return err return err
} }
func init_user_perms(user *User) {
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
user.Is_Super_Mod = user.Is_Admin || groups[user.Group].Is_Mod
user.Is_Mod = user.Is_Super_Mod
user.Is_Banned = groups[user.Group].Is_Banned
if user.Is_Banned && user.Is_Super_Mod {
user.Is_Banned = false
}
}