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
type DataStore interface {
Load(id int) error
Get(id int) (interface{}, error)
GetUnsafe(id int) (interface{}, error)
CascadeGet(id int) (interface{}, error)
Set(item interface{}) error
Add(item interface{}) error
AddUnsafe(item interface{}) error
Remove(id int) error

View File

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

View File

@ -1,5 +1,6 @@
package main
import "os"
import "fmt"
import "log"
import "bytes"
import "strconv"
@ -8,7 +9,6 @@ import "testing"
import "net/http"
import "net/http/httptest"
import "io/ioutil"
import "html/template"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
//import "github.com/husobee/vestigo"
@ -23,9 +23,25 @@ func gloinit() {
//discard := ioutil.Discard
//log.SetOutput(discard)
init_themes()
var err error
init_database(err)
init_templates()
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/"
hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil
@ -33,26 +49,30 @@ func gloinit() {
gloinited = true
}
func BenchmarkTopicTemplate(b *testing.B) {
func init() {
gloinit()
}
func BenchmarkTopicTemplateSerial(b *testing.B) {
b.ReportAllocs()
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"}
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
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!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.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!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.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!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.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!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.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!",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!","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!","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!","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!","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!","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!","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!","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!","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!","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}
tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,1,1,false}
@ -113,24 +133,24 @@ func BenchmarkTopicTemplate(b *testing.B) {
defer pprof.StopCPUProfile()*/
}
func BenchmarkTopicsTemplate(b *testing.B) {
func BenchmarkTopicsTemplateSerial(b *testing.B) {
b.ReportAllocs()
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"}
noticeList := []string{"test"}
var topicList []TopicUser
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, 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, 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, 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, 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, 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, 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, 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, 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, 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"})
var topicList []TopicsRow
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, 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, 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, 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, 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, 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, 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, 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, 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, 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
tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,nil}
@ -163,23 +183,6 @@ func BenchmarkStaticRouteParallel(b *testing.B) {
if !gloinited {
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 {
init_plugins()
}
@ -189,11 +192,16 @@ func BenchmarkStaticRouteParallel(b *testing.B) {
static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil))
static_handler := http.HandlerFunc(route_static)
for pb.Next() {
//static_w.Code = 200
static_w.Body.Reset()
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) {
b.ReportAllocs()
@ -202,9 +210,15 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
}
b.RunParallel(func(pb *testing.PB) {
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: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
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))
@ -214,7 +228,7 @@ func BenchmarkTopicAdminRouteParallel(b *testing.B) {
topic_handler := http.HandlerFunc(route_topic_id)
for pb.Next() {
//topic_w.Body.Reset()
topic_w.Body.Reset()
topic_handler.ServeHTTP(topic_w,topic_req_admin)
}
})
@ -245,9 +259,15 @@ func BenchmarkForumsAdminRouteParallel(b *testing.B) {
}
b.RunParallel(func(pb *testing.PB) {
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: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
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))
@ -270,9 +290,15 @@ func BenchmarkForumsAdminRouteParallelProf(b *testing.B) {
}
b.RunParallel(func(pb *testing.PB) {
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: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
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))
@ -313,10 +339,16 @@ func BenchmarkForumsGuestRouteParallel(b *testing.B) {
func BenchmarkRoutesSerial(b *testing.B) {
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}
// TO-DO: Stop hard-coding this value. Seriously.
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
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}
if plugins_inited {
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) {
for i := 0; i < b.N; i++ {
//static_w.Code = 200
static_w.Body.Reset()
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) {
topic := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
tu := TopicUser{Css: no_css_tmpl}
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 {
log.Fatal("No rows found!")
return
@ -566,12 +600,9 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
}
b.RunParallel(func(pb *testing.PB) {
topic := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
tu := TopicUser{Css: no_css_tmpl}
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 {
log.Fatal("No rows found!")
return
@ -585,13 +616,10 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
func BenchmarkQueriesSerial(b *testing.B) {
b.ReportAllocs()
topic := TopicUser{Css: no_css_tmpl}
var content string
var is_super_admin bool
var group int
tu := TopicUser{Css: no_css_tmpl}
b.Run("topic", func(b *testing.B) {
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 {
log.Fatal("No rows found!")
return
@ -617,7 +645,10 @@ func BenchmarkQueriesSerial(b *testing.B) {
defer rows.Close()
}
})
replyItem := Reply{Css: no_css_tmpl}
var is_super_admin bool
var group int
b.Run("topic_replies_scan", func(b *testing.B) {
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)
@ -648,7 +679,7 @@ func addEmptyRoutesToMux(routes []string, serveMux *http.ServeMux) {
}
}
func BenchmarkDefaultGoRouter(b *testing.B) {
func BenchmarkDefaultGoRouterSerial(b *testing.B) {
w := httptest.NewRecorder()
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
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) {
for _, route := range routes {
router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){})
}
}
func BenchmarkCustomRouter(b *testing.B) {
func BenchmarkCustomRouterSerial(b *testing.B) {
w := httptest.NewRecorder()
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
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.Run("empty_post", func(b *testing.B) {
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.Run("empty_post", func(b *testing.B) {
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.Run("empty_post", func(b *testing.B) {
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.Run("empty_post", func(b *testing.B) {
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) {
}*/

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/*"))
}
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(){
//if profiling {
// f, err := os.Create("startup_cpu.prof")
@ -151,27 +174,7 @@ func main(){
topics = NewSqlTopicStore()
}
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)
}
init_static_files()
external_sites["YT"] = "https://www.youtube.com/"
hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil

View File

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

View File

@ -9,6 +9,8 @@ import "strconv"
import "encoding/json"
var db *sql.DB
var db_version string
var get_user_stmt *sql.Stmt
var get_full_user_stmt *sql.Stmt
var get_topic_list_stmt *sql.Stmt
@ -92,6 +94,9 @@ func init_database(err error) {
log.Fatal(err)
}
// Getting the database version..
db.QueryRow("SELECT VERSION()").Scan(&db_version)
/*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` <> ''")
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),
}
guest_user.Perms = GuestPerms
if debug {
fmt.Printf("Guest Perms: ")
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) {
router.mu.RLock()
if req.URL.Path[0] != '/' {
router.mu.RUnlock()
w.WriteHeader(405)
w.Write([]byte(""))
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]
if ok {
router.mu.RUnlock()

View File

@ -113,7 +113,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
return
}
topicItem := TopicsRow{ID: 0,}
topicItem := TopicsRow{ID: 0}
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)
if err != nil {
@ -316,33 +316,25 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return
}
if !user.Perms.ViewTopic {
//fmt.Printf("%+v\n", user.Perms)
NoPermissions(w,r,user)
return
}
topic.ContentLines = strings.Count(topic.Content,"\n")
topic.Content = parse_message(topic.Content)
topic.ContentLines = strings.Count(topic.Content,"\n")
// We don't want users posting in locked topics...
if topic.Is_Closed && !user.Is_Mod {
user.Perms.CreateReply = false
}
if topic.Avatar != "" {
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 {
if groups[topic.Group].Is_Mod {
topic.Css = staff_css_tmpl
topic.Level = -1
}
topic.Tag = groups[topic.Group].Tag
if settings["url_tags"] == false {
/*if settings["url_tags"] == false {
topic.URLName = ""
} else {
topic.URL, ok = external_sites[topic.URLPrefix]
@ -351,7 +343,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else {
topic.URL = topic.URL + topic.URLName
}
}
}*/
// Calculate the offset
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.Liked = false
if hooks["rrow_assign"] != nil {
@ -465,19 +456,19 @@ func route_profile(w http.ResponseWriter, r *http.Request){
replyList []Reply
)
puser := User{ID: 0,}
puser.ID, err = strconv.Atoi(r.URL.Path[len("/user/"):])
pid, err := strconv.Atoi(r.URL.Path[len("/user/"):])
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
}
if puser.ID == user.ID {
var puser *User
if pid == user.ID {
user.Is_Mod = true
puser = user
puser = &user
} else {
// 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 {
NotFound(w,r)
return
@ -485,24 +476,6 @@ func route_profile(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
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..
@ -553,7 +526,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
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 {
template_profile_handle(ppage,w)
} else {
@ -922,7 +895,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
LocalError("Bad Form",w,r,user)
return
}
if r.FormValue("session") != user.Session {
@ -1213,6 +1186,11 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return
}
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")
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)
return
}
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")
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 {
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)
}
@ -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,"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)
}
@ -1395,6 +1379,12 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
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)
}
@ -1408,7 +1398,7 @@ func route_login(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Login",user,noticeList,tList,nil}
templates.ExecuteTemplate(w,"login.html", pi)
templates.ExecuteTemplate(w,"login.html",pi)
}
func route_login_submit(w http.ResponseWriter, r *http.Request) {

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. */
package main
import "io"
import "strconv"
import "io"
func init() {
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. */
package main
import "strconv"
import "io"
import "strconv"
func init() {
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. */
package main
import "strconv"
import "io"
import "strconv"
func init() {
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) {
panic("Uh oh! Something went wrong!")
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 {
Load(id int) error
Get(id int) (*Topic, error)
GetUnsafe(id int) (*Topic, error)
CascadeGet(id int) (*Topic, error)
Set(item *Topic) error
Add(item *Topic) error
AddUnsafe(item *Topic) error
Remove(id int) error
@ -137,6 +139,31 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
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 {
if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow
@ -218,7 +245,16 @@ func (sus *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
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
func (sus *SqlTopicStore) Set(item *Topic) error {
return nil
}
func (sus *SqlTopicStore) Add(item *Topic) error {
return nil
}
@ -252,6 +288,7 @@ func get_topicuser(tid int) (TopicUser,error) {
if err != nil {
return TopicUser{ID:tid}, err
}
init_user_perms(user)
// We might be better off just passing seperate topic and user structs to the caller?
return copy_topic_to_topicuser(topic, user), nil
@ -264,13 +301,8 @@ func get_topicuser(tid int) (TopicUser,error) {
if err != nil {
return TopicUser{ID:tid}, err
}
init_user_perms(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
}
}
@ -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}
//fmt.Printf("%+v\n", the_topic)
tu.Tag = groups[tu.Group].Tag
topics.Add(&the_topic)
//err = errors.Error("Loaded data via query")
return tu, err
}

139
user.go
View File

@ -9,6 +9,8 @@ import "golang.org/x/crypto/bcrypt"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
var guest_user User = User{ID:0,Group:6,Perms:GuestPerms}
type User struct
{
ID int
@ -44,9 +46,11 @@ type Email struct
}
type UserStore interface {
Load(id int) error
Get(id int) (*User, error)
GetUnsafe(id int) (*User, error)
CascadeGet(id int) (*User, error)
Set(item *User) error
Add(item *User) error
AddUnsafe(item *User) error
Remove(id int) error
@ -94,12 +98,58 @@ func (sts *StaticUserStore) CascadeGet(id int) (*User, 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 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 {
sts.Add(user)
}
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 {
if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow
@ -161,22 +211,62 @@ func NewSqlUserStore() *SqlUserStore {
func (sus *SqlUserStore) Get(id int) (*User, 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 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
}
func (sus *SqlUserStore) GetUnsafe(id int) (*User, 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 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
}
func (sus *SqlUserStore) CascadeGet(id int) (*User, 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 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
}
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
func (sus *SqlUserStore) Set(item *User) error {
return nil
}
func (sus *SqlUserStore) Add(item *User) error {
return nil
}
@ -258,6 +348,8 @@ func ForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user Us
}
user, success = SimpleSessionCheck(w,r)
fperms := groups[user.Group].Forums[fid]
//fmt.Printf("%+v\n", user.Perms)
//fmt.Printf("%+v\n", fperms)
if fperms.Overrides && !user.Is_Super_Admin {
user.Perms.ViewTopic = fperms.ViewTopic
user.Perms.LikeItem = fperms.LikeItem
@ -288,45 +380,28 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) {
// Are there any session cookies..?
cookie, err := r.Cookie("uid")
if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true
return guest_user, true
}
uid, err := strconv.Atoi(cookie.Value)
if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true
return guest_user, true
}
cookie, err = r.Cookie("session")
if err != nil {
return User{ID:0,Group:6,Perms:GuestPerms}, true
return guest_user, true
}
// Is this session valid..?
user, err := users.CascadeGet(uid)
if err == sql.ErrNoRows {
user.ID = 0
user.Session = ""
user.Group = 6
user.Perms = GuestPerms
return *user, true
return guest_user, true
} else if err != nil {
InternalError(err,w,r)
return *user, false
return guest_user, false
}
if user.Session == "" || cookie.Value != user.Session {
user.ID = 0
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
return guest_user, true
}
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
}
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)
if err != nil {
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)
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
}
}