diff --git a/.gitignore b/.gitignore index c24d07cc..1fb213a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ +tmp/* +tmp2/* uploads/avatar_* bin/* gosora.exe +gosora.test.exe install.exe +*.prof + diff --git a/build.bat b/build.bat index 3964dded..4fe85921 100644 --- a/build.bat +++ b/build.bat @@ -1,9 +1,19 @@ @echo off +echo Generating the dynamic code +go generate +if %errorlevel% neq 0 ( + pause + exit /b %errorlevel% +) + +echo Building the executable go build if %errorlevel% neq 0 ( pause exit /b %errorlevel% ) + +echo Building the installer go build ./install if %errorlevel% neq 0 ( pause diff --git a/config.go b/config.go index 0d1559fc..b60f9451 100644 --- a/config.go +++ b/config.go @@ -32,3 +32,4 @@ var ssl_fullchain = "" // Developer flag var debug = false +var profiling = false diff --git a/data.sql b/data.sql index 59d8fbb0..dd8a258b 100644 --- a/data.sql +++ b/data.sql @@ -130,8 +130,8 @@ INSERT INTO settings(`name`,`content`,`type`) VALUES ('bigpost_min_chars','250', INSERT INTO settings(`name`,`content`,`type`) VALUES ('megapost_min_chars','1000','int'); INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1); -INSERT INTO users(`name`,`password`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`) -VALUES ('Admin','password','admin@localhost',1,1,NOW(),NOW(),''); +INSERT INTO users(`name`,`password`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`,`last_ip`) +VALUES ('Admin','password','admin@localhost',1,1,NOW(),NOW(),'','127.0.0.1'); INSERT INTO emails(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1); /* diff --git a/errors.go b/errors.go index 354d29af..fe25aaab 100644 --- a/errors.go +++ b/errors.go @@ -4,160 +4,153 @@ import "log" import "bytes" import "net/http" -func InternalError(err error, w http.ResponseWriter, r *http.Request, user User) { - log.Fatal(err) - pi := Page{"Internal Server Error","error",user,nList,tList,"A problem has occured in the system."} +var error_internal []byte +var error_notfound []byte +func init_errors() error { var b bytes.Buffer - templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(500) - fmt.Fprintln(w,errpage) + user := User{0,"Guest","",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"0.0.0.0.0"} + pi := Page{"Internal Server Error",user,nList,tList,"A problem has occurred in the system."} + err := templates.ExecuteTemplate(&b,"error.html", pi) + if err != nil { + return err + } + error_internal = b.Bytes() + + b.Reset() + pi = Page{"Not Found",user,nList,tList,"The requested page doesn't exist."} + err = templates.ExecuteTemplate(&b,"error.html", pi) + if err != nil { + return err + } + error_notfound = b.Bytes() + return nil +} + +func InternalError(err error, w http.ResponseWriter, r *http.Request, user User) { + w.Write(error_internal) + log.Fatal(err) } func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, user User, is_js string) { - log.Fatal(err) - errmsg := "A problem has occured in the system." + w.WriteHeader(500) if is_js == "0" { - pi := Page{"Internal Server Error","error",user,nList,tList,errmsg} - var b bytes.Buffer - templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(500) - fmt.Fprintln(w,errpage) + w.Write(error_internal) } else { - http.Error(w,"{'errmsg': '" + errmsg + "'}",500) + w.Write([]byte(`{'errmsg': 'A problem has occured in the system.'}`)) } + log.Fatal(err) } func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) { - pi := Page{"Local Error","error",user,nList,tList,errmsg} + w.WriteHeader(500) + pi := Page{"Local Error",user,nList,tList,errmsg} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(500) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } func LoginRequired(w http.ResponseWriter, r *http.Request, user User) { - pi := Page{"Local Error","error",user,nList,tList,"You need to login to do that."} - + w.WriteHeader(401) + pi := Page{"Local Error",user,nList,tList,"You need to login to do that."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(401) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, is_js string) { + w.WriteHeader(500) if is_js == "0" { - pi := Page{"Local Error","error",user,nList,tList,errmsg} + pi := Page{"Local Error",user,nList,tList,errmsg} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(500) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } else { - http.Error(w,"{'errmsg': '" + errmsg + "'}",500) + w.Write([]byte(`{'errmsg': '` + errmsg + `'}`)) } } func NoPermissions(w http.ResponseWriter, r *http.Request, user User) { - errmsg := "You don't have permission to do that." - pi := Page{"Local Error","error",user,nList,tList,errmsg} + w.WriteHeader(403) + pi := Page{"Local Error",user,nList,tList,"You don't have permission to do that."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) errpage := b.String() - w.WriteHeader(403) fmt.Fprintln(w,errpage) } func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) { - errmsg := "You don't have permission to do that." + w.WriteHeader(403) if is_js == "0" { - pi := Page{"Local Error","error",user,nList,tList,errmsg} + pi := Page{"Local Error",user,nList,tList,"You don't have permission to do that."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(403) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } else { - http.Error(w,"{'errmsg': '" + errmsg + "'}",403) + w.Write([]byte("{'errmsg': 'You don't have permission to do that.'}")) } } func Banned(w http.ResponseWriter, r *http.Request, user User) { - pi := Page{"Banned","error",user,nList,tList,"You have been banned from this site."} + w.WriteHeader(403) + pi := Page{"Banned",user,nList,tList,"You have been banned from this site."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(403) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) { + w.WriteHeader(403) if is_js == "0" { - pi := Page{"Banned","error",user,nList,tList,"You have been banned from this site."} + pi := Page{"Banned",user,nList,tList,"You have been banned from this site."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(403) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } else { - http.Error(w,"{'errmsg': 'You have been banned from this site.'}",403) + w.Write([]byte("{'errmsg': 'You have been banned from this site.'}")) } } func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) { + w.WriteHeader(401) if is_js == "0" { - pi := Page{"Local Error","error",user,nList,tList,"You need to login to do that."} + pi := Page{"Local Error",user,nList,tList,"You need to login to do that."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(401) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } else { - http.Error(w,"{'errmsg': 'You need to login to do that.'}",401) + w.Write([]byte("{'errmsg': 'You need to login to do that.'}")) } } func SecurityError(w http.ResponseWriter, r *http.Request, user User) { - errmsg := "There was a security issue with your request." - pi := Page{"Security Error","error",user,nList,tList,errmsg} + w.WriteHeader(403) + pi := Page{"Security Error",user,nList,tList,"There was a security issue with your request."} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(403) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } func NotFound(w http.ResponseWriter, r *http.Request, user User) { - errmsg := "The requested page doesn't exist." - pi := Page{"Not Found","error",user,nList,tList,errmsg} - var b bytes.Buffer - templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() w.WriteHeader(404) - fmt.Fprintln(w,errpage) + w.Write(error_notfound) } func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) { - pi := Page{errtitle,"error",user,nList,tList,errmsg} + w.WriteHeader(errcode) + pi := Page{errtitle,user,nList,tList,errmsg} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(errcode) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, is_js string) { + w.WriteHeader(errcode) if is_js == "0" { - pi := Page{errtitle,"error",user,nList,tList,errmsg} + pi := Page{errtitle,user,nList,tList,errmsg} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) - errpage := b.String() - w.WriteHeader(errcode) - fmt.Fprintln(w,errpage) + fmt.Fprintln(w,b.String()) } else { - http.Error(w,"{'errmsg': '" + errmsg + "'}",errcode) + w.Write([]byte(`{'errmsg': '` + errmsg + `'}`)) } } diff --git a/extend.go b/extend.go index f0442bef..9c10f52b 100644 --- a/extend.go +++ b/extend.go @@ -78,6 +78,7 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) { delete(plugin.Hooks, name) } +var plugins_inited bool = false func init_plugins() { for name, body := range plugins { log.Print("Added plugin " + name) @@ -86,6 +87,7 @@ func init_plugins() { plugins[name].Init() } } + plugins_inited = true } func run_hook(name string, data interface{}) interface{} { diff --git a/general_test.go b/general_test.go index 239812f3..672d5a75 100644 --- a/general_test.go +++ b/general_test.go @@ -1,4 +1,5 @@ package main +import "os" import "log" import "bytes" import "strconv" @@ -8,29 +9,50 @@ 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" +import "runtime/pprof" + +var gloinited bool = false +func gloinit() { + debug = false + nogrouplog = true + + // init_database is a little noisy for a benchmark + //discard := ioutil.Discard + //log.SetOutput(discard) + + var err error + init_database(err) + db.SetMaxOpenConns(64) + external_sites["YT"] = "https://www.youtube.com/" + hooks["trow_assign"] = nil + hooks["rrow_assign"] = nil + //log.SetOutput(os.Stdout) + gloinited = true +} func BenchmarkTopicTemplate(b *testing.B) { b.ReportAllocs() - user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0} - admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58} - var noticeList map[int]string = make(map[int]string) - noticeList[0] = "test" + 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} + 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"} var replyList []Reply - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) - replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) + 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"}) tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,false} tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,false} @@ -56,61 +78,253 @@ func BenchmarkTopicTemplate(b *testing.B) { templates.ExecuteTemplate(w,"topic.html", tpage) } }) + + w2 := httptest.NewRecorder() + b.Run("compiled_useradmin_recorder", func(b *testing.B) { + for i := 0; i < b.N; i++ { + w2.Body.Reset() + template_topic(tpage2,w2) + } + }) + b.Run("interpreted_useradmin_recorder", func(b *testing.B) { + for i := 0; i < b.N; i++ { + w2.Body.Reset() + templates.ExecuteTemplate(w2,"topic.html", tpage2) + } + }) + b.Run("compiled_userguest_recorder", func(b *testing.B) { + for i := 0; i < b.N; i++ { + w2.Body.Reset() + template_topic(tpage,w2) + } + }) + b.Run("interpreted_userguest_recorder", func(b *testing.B) { + for i := 0; i < b.N; i++ { + w2.Body.Reset() + templates.ExecuteTemplate(w2,"topic.html", tpage) + } + }) + + /*f, err := os.Create("topic_bench.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f) + defer pprof.StopCPUProfile()*/ } func BenchmarkTopicsTemplate(b *testing.B) { b.ReportAllocs() - user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0} - admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58} - var noticeList map[int]string = make(map[int]string) - noticeList[0] = "test" + 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}) - 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}) - 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}) - 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}) - 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}) - 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}) - 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}) - 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}) - 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}) - 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}) + 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"}) - tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,0} - tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,0} w := ioutil.Discard + tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,nil} + tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,nil} b.Run("compiled_useradmin", func(b *testing.B) { for i := 0; i < b.N; i++ { template_topics(tpage2,w) } }) - b.Run("interpreted_useradmin", func(b *testing.B) { + b.Run("interpreted_useradmin",func(b *testing.B) { for i := 0; i < b.N; i++ { templates.ExecuteTemplate(w,"topics.html", tpage2) } }) - b.Run("compiled_userguest", func(b *testing.B) { + b.Run("compiled_userguest",func(b *testing.B) { for i := 0; i < b.N; i++ { template_topics(tpage,w) } }) - b.Run("interpreted_userguest", func(b *testing.B) { + b.Run("interpreted_userguest",func(b *testing.B) { for i := 0; i < b.N; i++ { templates.ExecuteTemplate(w,"topics.html", tpage) } }) } -func BenchmarkRoute(b *testing.B) { +func BenchmarkStaticRouteParallel(b *testing.B) { + b.ReportAllocs() + 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() + } + + 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 BenchmarkTopicAdminRouteParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + 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} + + 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) + + for pb.Next() { + //topic_w.Body.Reset() + topic_handler.ServeHTTP(topic_w,topic_req_admin) + } + }) +} + +func BenchmarkTopicGuestRouteParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + b.RunParallel(func(pb *testing.PB) { + topic_w := httptest.NewRecorder() + topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil)) + topic_handler := http.HandlerFunc(route_topic_id) + for pb.Next() { + topic_w.Body.Reset() + topic_handler.ServeHTTP(topic_w,topic_req) + } + }) +} + + +func BenchmarkForumsAdminRouteParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + 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} + + 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) + + for pb.Next() { + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req_admin) + } + }) +} + +func BenchmarkForumsAdminRouteParallelProf(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + 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} + + 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) + f, err := os.Create("cpu_forums_admin_parallel.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f) + for pb.Next() { + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req_admin) + } + pprof.StopCPUProfile() + }) +} + +func BenchmarkForumsGuestRouteParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + b.RunParallel(func(pb *testing.PB) { + forums_w := httptest.NewRecorder() + forums_req := httptest.NewRequest("get","/forums/",bytes.NewReader(nil)) + forums_handler := http.HandlerFunc(route_forums) + for pb.Next() { + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req) + } + }) +} + + +func BenchmarkRoutesSerial(b *testing.B) { b.ReportAllocs() 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} + if plugins_inited { + b.Log("Plugins have already been initialised, they can't be deinitialised so these tests will run with plugins on") + } + static_w := httptest.NewRecorder() + static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil)) + static_handler := http.HandlerFunc(route_static) + topic_w := httptest.NewRecorder() topic_req := httptest.NewRequest("get","/topic/1",bytes.NewReader(nil)) topic_req_admin := topic_req @@ -139,32 +353,31 @@ func BenchmarkRoute(b *testing.B) { forums_req_admin.AddCookie(&admin_session_cookie) forums_handler := http.HandlerFunc(route_forums) - static_w := httptest.NewRecorder() - static_req := httptest.NewRequest("get","/static/global.js",bytes.NewReader(nil)) - static_handler := http.HandlerFunc(route_static) + if !gloinited { + gloinit() + } - debug = false - nogrouplog = true + /*f, err := os.Create("routes_bench_cpu.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f)*/ + //defer pprof.StopCPUProfile() + //pprof.StopCPUProfile() - // init_database is a little noisy for a benchmark - discard := ioutil.Discard - log.SetOutput(discard) - - var err error - init_database(err) - external_sites["YT"] = "https://www.youtube.com/" - hooks["trow_assign"] = nil - hooks["rrow_assign"] = nil - init_plugins() - - b.Run("static_files", func(b *testing.B) { + b.Run("static_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { static_w.Body.Reset() static_handler.ServeHTTP(static_w,static_req) } }) - b.Run("topic_admin", func(b *testing.B) { + b.Run("topic_admin_recorder", func(b *testing.B) { + //f, err := os.Create("routes_bench_topic_cpu.prof") + //if err != nil { + // log.Fatal(err) + //} + //pprof.StartCPUProfile(f) for i := 0; i < b.N; i++ { //topic_w.Code = 200 topic_w.Body.Reset() @@ -174,55 +387,258 @@ func BenchmarkRoute(b *testing.B) { // panic("HTTP Error!") //} } + //pprof.StopCPUProfile() }) - b.Run("topic_guest", func(b *testing.B) { + b.Run("topic_guest_recorder", func(b *testing.B) { + f, err := os.Create("routes_bench_topic_cpu_2.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f) for i := 0; i < b.N; i++ { //topic_w.Code = 200 topic_w.Body.Reset() topic_handler.ServeHTTP(topic_w,topic_req) } + pprof.StopCPUProfile() }) - b.Run("topics_admin", func(b *testing.B) { + b.Run("topics_admin_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { //topics_w.Code = 200 topics_w.Body.Reset() topics_handler.ServeHTTP(topics_w,topics_req_admin) } }) - b.Run("topics_guest", func(b *testing.B) { + b.Run("topics_guest_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { //topics_w.Code = 200 topics_w.Body.Reset() topics_handler.ServeHTTP(topics_w,topics_req) } }) - b.Run("forum_admin", func(b *testing.B) { + b.Run("forum_admin_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { //forum_w.Code = 200 forum_w.Body.Reset() forum_handler.ServeHTTP(forum_w,forum_req_admin) } }) - b.Run("forum_guest", func(b *testing.B) { + b.Run("forum_guest_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { //forum_w.Code = 200 forum_w.Body.Reset() forum_handler.ServeHTTP(forum_w,forum_req) } }) - b.Run("forums_admin", func(b *testing.B) { + b.Run("forums_admin_recorder", func(b *testing.B) { for i := 0; i < b.N; i++ { //forums_w.Code = 200 forums_w.Body.Reset() forums_handler.ServeHTTP(forums_w,forums_req_admin) } }) - b.Run("forums_guest", func(b *testing.B) { + b.Run("forums_guest_recorder", func(b *testing.B) { + /*f, err := os.Create("routes_bench_forums_cpu_2.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f)*/ for i := 0; i < b.N; i++ { //forums_w.Code = 200 forums_w.Body.Reset() forums_handler.ServeHTTP(forums_w,forums_req) } + //pprof.StopCPUProfile() + }) + + if !plugins_inited { + init_plugins() + } + + b.Run("topic_admin_recorder_with_plugins", func(b *testing.B) { + /*f, err := os.Create("routes_bench_topic_cpu.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f)*/ + for i := 0; i < b.N; i++ { + //topic_w.Code = 200 + topic_w.Body.Reset() + topic_handler.ServeHTTP(topic_w,topic_req_admin) + //if topic_w.Code != 200 { + // fmt.Println(topic_w.Body) + // panic("HTTP Error!") + //} + } + //pprof.StopCPUProfile() + }) + b.Run("topic_guest_recorder_with_plugins", func(b *testing.B) { + /*f, err := os.Create("routes_bench_topic_cpu_2.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f)*/ + for i := 0; i < b.N; i++ { + //topic_w.Code = 200 + topic_w.Body.Reset() + topic_handler.ServeHTTP(topic_w,topic_req) + } + //pprof.StopCPUProfile() + }) + b.Run("topics_admin_recorder_with_plugins", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //topics_w.Code = 200 + topics_w.Body.Reset() + topics_handler.ServeHTTP(topics_w,topics_req_admin) + } + }) + b.Run("topics_guest_recorder_with_plugins", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //topics_w.Code = 200 + topics_w.Body.Reset() + topics_handler.ServeHTTP(topics_w,topics_req) + } + }) + b.Run("forum_admin_recorder_with_plugins", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //forum_w.Code = 200 + forum_w.Body.Reset() + forum_handler.ServeHTTP(forum_w,forum_req_admin) + } + }) + b.Run("forum_guest_recorder_with_plugins", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //forum_w.Code = 200 + forum_w.Body.Reset() + forum_handler.ServeHTTP(forum_w,forum_req) + } + }) + b.Run("forums_admin_recorder_with_plugins", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //forums_w.Code = 200 + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req_admin) + } + }) + b.Run("forums_guest_recorder_with_plugins", func(b *testing.B) { + /*f, err := os.Create("routes_bench_forums_cpu_2.prof") + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f)*/ + for i := 0; i < b.N; i++ { + //forums_w.Code = 200 + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req) + } + //pprof.StopCPUProfile() + }) +} + +func BenchmarkQueryTopicParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + b.RunParallel(func(pb *testing.PB) { + topic := TopicUser{Css: no_css_tmpl} + var content string + var is_super_admin bool + var group int + 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) + if err == sql.ErrNoRows { + log.Fatal("No rows found!") + return + } else if err != nil { + log.Fatal(err) + return + } + } + }) +} + +func BenchmarkQueryPreparedTopicParallel(b *testing.B) { + b.ReportAllocs() + if !gloinited { + gloinit() + } + + b.RunParallel(func(pb *testing.PB) { + topic := TopicUser{Css: no_css_tmpl} + var content string + var is_super_admin bool + var group int + 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) + if err == sql.ErrNoRows { + log.Fatal("No rows found!") + return + } else if err != nil { + log.Fatal(err) + return + } + } + }) +} + +func BenchmarkQueriesSerial(b *testing.B) { + b.ReportAllocs() + topic := TopicUser{Css: no_css_tmpl} + var content string + var is_super_admin bool + var group int + 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) + if err == sql.ErrNoRows { + log.Fatal("No rows found!") + return + } else if err != nil { + log.Fatal(err) + return + } + } + }) + b.Run("topic_replies", 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) + if err != nil { + log.Fatal(err) + return + } + for rows.Next() {} + err = rows.Err() + if err != nil { + log.Fatal(err) + return + } + defer rows.Close() + } + }) + replyItem := Reply{Css: no_css_tmpl} + 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) + if err != nil { + log.Fatal(err) + return + } + for rows.Next() { + err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &is_super_admin, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress) + if err != nil { + log.Fatal(err) + return + } + } + err = rows.Err() + if err != nil { + log.Fatal(err) + return + } + defer rows.Close() + } }) } diff --git a/images/tempra-simple.png b/images/tempra-simple.png index b689106c..0a88c0e8 100644 Binary files a/images/tempra-simple.png and b/images/tempra-simple.png differ diff --git a/main.go b/main.go index dda9cc3d..625ed635 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "os" "html/template" + //"runtime/pprof" ) const hour int = 60 * 60 @@ -41,15 +42,14 @@ var template_profile_handle func(ProfilePage,io.Writer) = nil func compile_templates() { var c CTemplateSet - user := User{62,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0} - var noticeList map[int]string = make(map[int]string) - noticeList[0] = "test" + user := User{62,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0,"0.0.0.0.0"} + noticeList := []string{"test"} log.Print("Compiling the templates") - topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","","",58} + topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","","",58,"127.0.0.1"} var replyList []Reply - replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0}) + replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) var varList map[string]VarItem = make(map[string]VarItem) tpage := TopicPage{"Title",user,noticeList,replyList,topic,false} @@ -71,7 +71,7 @@ func compile_templates() { forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage", forums_page, varList) var topicList []TopicUser - topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","","",58}) + topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","","",58,"127.0.0.1"}) topics_page := TopicsPage{"Topic List",user,noticeList,topicList,""} topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList) @@ -79,12 +79,13 @@ func compile_templates() { forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList) log.Print("Writing the templates") - write_template("topic", topic_id_tmpl) - write_template("topic_alt", topic_id_alt_tmpl) - write_template("profile", profile_tmpl) - write_template("forums", forums_tmpl) - write_template("topics", topics_tmpl) - write_template("forum", forum_tmpl) + go write_template("topic", topic_id_tmpl) + go write_template("topic_alt", topic_id_alt_tmpl) + go write_template("profile", profile_tmpl) + go write_template("forums", forums_tmpl) + go write_template("topics", topics_tmpl) + go write_template("forum", forum_tmpl) + go write_file("./template_list.go", "package main\n\n" + c.FragOut) } func write_template(name string, content string) { @@ -92,10 +93,24 @@ func write_template(name string, content string) { } func main(){ + //if profiling { + // f, err := os.Create("startup_cpu.prof") + // if err != nil { + // log.Fatal(err) + // } + // pprof.StartCPUProfile(f) + //} + init_themes() var err error init_database(err) compile_templates() + db.SetMaxOpenConns(64) + + err = init_errors() + if err != nil { + log.Fatal(err) + } log.Print("Loading the static files.") err = filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { @@ -122,7 +137,6 @@ func main(){ hooks["trow_assign"] = nil hooks["rrow_assign"] = nil templates.ParseGlob("pages/*") - init_plugins() router := NewRouter() @@ -199,10 +213,15 @@ func main(){ router.HandleFunc("/panel/users/edit/", route_panel_users_edit) router.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit) router.HandleFunc("/panel/groups/", route_panel_groups) + //router.HandleFunc("/exit/", route_exit) router.HandleFunc("/", default_route) - defer db.Close() + + //if profiling { + // pprof.StopCPUProfile() + //} + if !enable_ssl { if server_port == "" { server_port = "80" diff --git a/mod_routes.go b/mod_routes.go index 740acf00..d995500f 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -383,7 +383,7 @@ func route_ban(w http.ResponseWriter, r *http.Request) { confirm_msg := "Are you sure you want to ban '" + uname + "'?" yousure := AreYouSure{"/users/ban/submit/" + strconv.Itoa(uid),confirm_msg} - pi := Page{"Ban User","ban-user",user,noticeList,tList,yousure} + pi := Page{"Ban User",user,noticeList,tList,yousure} templates.ExecuteTemplate(w,"areyousure.html", pi) } @@ -550,7 +550,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){ return } - pi := Page{"Control Panel Dashboard","panel",user,noticeList,tList,0} + pi := Page{"Control Panel Dashboard",user,noticeList,tList,0} templates.ExecuteTemplate(w,"panel-dashboard.html", pi) } @@ -571,7 +571,7 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){ } } - pi := Page{"Forum Manager","panel-forums",user,noticeList,forumList,0} + pi := Page{"Forum Manager",user,noticeList,forumList,0} templates.ExecuteTemplate(w,"panel-forums.html", pi) } @@ -641,7 +641,7 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request){ confirm_msg := "Are you sure you want to delete the '" + forums[fid].Name + "' forum?" yousure := AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid),confirm_msg} - pi := Page{"Delete Forum","panel-forums-delete",user,noticeList,tList,yousure} + pi := Page{"Delete Forum",user,noticeList,tList,yousure} templates.ExecuteTemplate(w,"areyousure.html", pi) } @@ -779,7 +779,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){ return } - pi := Page{"Setting Manager","panel-settings",user, noticeList,tList,settingList} + pi := Page{"Setting Manager",user, noticeList,tList,settingList} templates.ExecuteTemplate(w,"panel-settings.html", pi) } @@ -829,7 +829,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request){ } } - pi := Page{"Edit Setting","panel-setting",user,noticeList,itemList,setting} + pi := Page{"Edit Setting",user,noticeList,itemList,setting} templates.ExecuteTemplate(w,"panel-setting.html", pi) } @@ -904,7 +904,7 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request){ pluginList = append(pluginList, plugin) } - pi := Page{"Plugin Manager","panel-plugins",user,noticeList,pluginList,0} + pi := Page{"Plugin Manager",user,noticeList,pluginList,0} templates.ExecuteTemplate(w,"panel-plugins.html", pi) } @@ -1075,7 +1075,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ return } - pi := Page{"User Manager","panel-users",user,noticeList,userList,0} + pi := Page{"User Manager",user,noticeList,userList,0} err = templates.ExecuteTemplate(w,"panel-users.html", pi) if err != nil { InternalError(err, w, r, user) @@ -1129,7 +1129,7 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request){ groupList = append(groupList, group) } - pi := Page{"User Editor","panel-user-edit",user,noticeList,groupList,targetUser} + pi := Page{"User Editor",user,noticeList,groupList,targetUser} err = templates.ExecuteTemplate(w,"panel-user-edit.html", pi) if err != nil { InternalError(err, w, r, user) @@ -1246,7 +1246,7 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){ groupList = append(groupList, group) } - pi := Page{"Group Manager","panel-groups",user,noticeList,groupList,0} + pi := Page{"Group Manager",user,noticeList,groupList,0} templates.ExecuteTemplate(w,"panel-groups.html", pi) } @@ -1265,7 +1265,7 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){ themeList = append(themeList, theme) } - pi := Page{"Theme Manager","panel-themes",user,noticeList,themeList,0} + pi := Page{"Theme Manager",user,noticeList,themeList,0} err := templates.ExecuteTemplate(w,"panel-themes.html", pi) if err != nil { log.Print(err) diff --git a/mysql.go b/mysql.go index 58913bc0..dcd63fbe 100644 --- a/mysql.go +++ b/mysql.go @@ -10,6 +10,9 @@ import "encoding/json" var db *sql.DB var get_session_stmt *sql.Stmt var get_topic_list_stmt *sql.Stmt +var get_topic_user_stmt *sql.Stmt +var get_topic_replies_stmt *sql.Stmt +var get_forum_topics_stmt *sql.Stmt var create_topic_stmt *sql.Stmt var create_report_stmt *sql.Stmt var create_reply_stmt *sql.Stmt @@ -20,6 +23,7 @@ var delete_reply_stmt *sql.Stmt var delete_topic_stmt *sql.Stmt var stick_topic_stmt *sql.Stmt var unstick_topic_stmt *sql.Stmt +var update_last_ip_stmt *sql.Stmt var login_stmt *sql.Stmt var update_session_stmt *sql.Stmt var logout_stmt *sql.Stmt @@ -70,7 +74,7 @@ func init_database(err error) { } 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` 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 { log.Fatal(err) } @@ -81,8 +85,26 @@ func init_database(err error) { log.Fatal(err) } + log.Print("Preparing get_topic_user statement.") + get_topic_user_stmt, err = db.Prepare("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 = ?") + if err != nil { + log.Fatal(err) + } + + log.Print("Preparing get_topic_replies statement.") + get_topic_replies_stmt, err = db.Prepare("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 = ?") + if err != nil { + log.Fatal(err) + } + + log.Print("Preparing get_forum_topics statement.") + get_forum_topics_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid WHERE topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC") + if err != nil { + log.Fatal(err) + } + log.Print("Preparing create_topic statement.") - create_topic_stmt, err = db.Prepare("insert into topics(title,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)") + create_topic_stmt, err = db.Prepare("insert into topics(title,content,parsed_content,createdAt,ipaddress,createdBy) VALUES(?,?,?,NOW(),?,?)") if err != nil { log.Fatal(err) } @@ -94,7 +116,7 @@ func init_database(err error) { } log.Print("Preparing create_reply statement.") - create_reply_stmt, err = db.Prepare("INSERT INTO replies(tid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)") + create_reply_stmt, err = db.Prepare("INSERT INTO replies(tid,content,parsed_content,createdAt,ipaddress,createdBy) VALUES(?,?,?,NOW(),?,?)") if err != nil { log.Fatal(err) } @@ -141,6 +163,12 @@ func init_database(err error) { log.Fatal(err) } + log.Print("Preparing update_last_ip statement.") + update_last_ip_stmt, err = db.Prepare("UPDATE users SET last_ip = ? WHERE uid = ?") + if err != nil { + log.Fatal(err) + } + log.Print("Preparing login statement.") login_stmt, err = db.Prepare("SELECT `uid`, `name`, `password`, `salt` FROM `users` WHERE `name` = ?") if err != nil { diff --git a/pages.go b/pages.go index 5b6ef72c..8bda78c0 100644 --- a/pages.go +++ b/pages.go @@ -5,9 +5,8 @@ import "regexp" type Page struct { Title string - Name string // Deprecated. Marked for removal. CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []interface{} Something interface{} } @@ -16,7 +15,7 @@ type TopicPage struct { Title string CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []Reply Topic TopicUser ExtData interface{} @@ -26,7 +25,7 @@ type TopicsPage struct { Title string CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []TopicUser ExtData interface{} } @@ -35,7 +34,7 @@ type ForumPage struct { Title string CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []TopicUser ExtData interface{} } @@ -44,7 +43,7 @@ type ForumsPage struct { Title string CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []Forum ExtData interface{} } @@ -53,7 +52,7 @@ type ProfilePage struct { Title string CurrentUser User - NoticeList map[int]string + NoticeList []string ItemList []Reply ProfileOwner User ExtData interface{} diff --git a/plugin_bbcode.go b/plugin_bbcode.go index 973699aa..0a1ab4a2 100644 --- a/plugin_bbcode.go +++ b/plugin_bbcode.go @@ -3,9 +3,15 @@ package main //import "fmt" import "bytes" //import "strings" +import "strconv" import "regexp" +import "time" +import "math/rand" +var random *rand.Rand var bbcode_invalid_url []byte +var bbcode_invalid_number []byte +var bbcode_missing_tag []byte var bbcode_url_open []byte var bbcode_url_open2 []byte var bbcode_url_close []byte @@ -25,6 +31,8 @@ func init_bbcode() { plugins["bbcode"].AddHook("parse_assign", bbcode_full_parse) bbcode_invalid_url = []byte("[Invalid URL]") + bbcode_invalid_number = []byte("[Invalid Number]") + bbcode_missing_tag = []byte("[Missing Tag]") bbcode_url_open = []byte("") bbcode_url_close = []byte("") @@ -36,6 +44,8 @@ func init_bbcode() { urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)` bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`) bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`) + + random = rand.New(rand.NewSource(time.Now().UnixNano())) } func deactivate_bbcode() { @@ -62,7 +72,7 @@ func bbcode_simple_parse(data interface{}) interface{} { has_b := false has_i := false has_s := false - for i := 0; i < len(msgbytes); i++ { + for i := 0; (i + 2) < len(msgbytes); i++ { if msgbytes[i] == '[' && msgbytes[i + 2] == ']' { if msgbytes[i + 1] == 'b' { msgbytes[i] = '<' @@ -102,7 +112,7 @@ func bbcode_parse_without_code(data interface{}) interface{} { has_i := false has_s := false complex_bbc := false - for i := 0; i < len(msgbytes); i++ { + for i := 0; (i + 2) < len(msgbytes); i++ { if msgbytes[i] == '[' { if msgbytes[i + 2] != ']' { if msgbytes[i + 1] == '/' { @@ -177,7 +187,7 @@ func bbcode_full_parse(data interface{}) interface{} { has_s := false has_c := false complex_bbc := false - for i := 0; i < len(msgbytes); i++ { + for i := 0; (i + 2) < len(msgbytes); i++ { if msgbytes[i] == '[' { if msgbytes[i + 2] != ']' { if msgbytes[i + 1] == '/' { @@ -249,20 +259,21 @@ func bbcode_full_parse(data interface{}) interface{} { var start int var lastTag int outbytes := make([]byte, len(msgbytes)) + //fmt.Println(string(msgbytes)) for i := 0; i < len(msgbytes); i++ { MainLoop: if msgbytes[i] == '[' { OuterComplex: if msgbytes[i + 1] == 'u' { - if msgbytes[i + 2] == 'r' && msgbytes[i + 3] == 'l' && msgbytes[i + 4] == ']' { + if msgbytes[i+2] == 'r' && msgbytes[i+3] == 'l' && msgbytes[i+4] == ']' { outbytes = append(outbytes, msgbytes[lastTag:i]...) start = i + 5 i = start if msgbytes[i] == 'h' { - if msgbytes[i + 1] == 't' && msgbytes[i + 2] == 't' && msgbytes[i + 3] == 'p' { + if msgbytes[i+1] == 't' && msgbytes[i+2] == 't' && msgbytes[i+3] == 'p' { if bytes.Equal(msgbytes[i + 4:i + 7],[]byte("s://")) { i += 7 - } else if msgbytes[i + 4] == ':' && msgbytes[i + 5] == '/' && msgbytes[i + 6] == '/' { + } else if msgbytes[i+4] == ':' && msgbytes[i+5] == '/' && msgbytes[i+6] == '/' { i += 6 } else { outbytes = append(outbytes, bbcode_invalid_url...) @@ -270,16 +281,17 @@ func bbcode_full_parse(data interface{}) interface{} { } } } else if msgbytes[i] == 'f' { - if bytes.Equal(msgbytes[i + 1:i + 5],[]byte("tp://")) { + if bytes.Equal(msgbytes[i+1:i+5],[]byte("tp://")) { i += 5 } } for ;; i++ { if msgbytes[i] == '[' { - if !bytes.Equal(msgbytes[i + 1:i + 6],[]byte("/url]")) { + if !bytes.Equal(msgbytes[i+1:i+6],[]byte("/url]")) { //log.Print("Not the URL closing tag!") //fmt.Println(msgbytes[i + 1:i + 6]) + outbytes = append(outbytes, bbcode_missing_tag...) goto OuterComplex } break @@ -288,6 +300,9 @@ func bbcode_full_parse(data interface{}) interface{} { //log.Print("Weird character") //fmt.Println(msgbytes[i]) goto MainLoop + } else if (len(msgbytes) - 1) < (i + 6) { + outbytes = append(outbytes, bbcode_missing_tag...) + goto OuterComplex } } outbytes = append(outbytes, bbcode_url_open...) @@ -298,9 +313,41 @@ func bbcode_full_parse(data interface{}) interface{} { i += 6 lastTag = i } + } else if msgbytes[i + 1] == 'r' { + if bytes.Equal(msgbytes[i+2:i+6],[]byte("and]")) { + outbytes = append(outbytes, msgbytes[lastTag:i]...) + start = i + 6 + i = start + for ;; i++ { + if msgbytes[i] == '[' { + if !bytes.Equal(msgbytes[i+1:i+7],[]byte("/rand]")) { + outbytes = append(outbytes, bbcode_missing_tag...) + goto OuterComplex + } + break + } else if (len(msgbytes) - 1) < (i + 7) { + outbytes = append(outbytes, bbcode_missing_tag...) + goto OuterComplex + } + } + + number, err := strconv.ParseInt(string(msgbytes[start:i]),10,64) + if err != nil { + outbytes = append(outbytes, bbcode_invalid_number...) + goto MainLoop + } + + dat := []byte(strconv.FormatInt((random.Int63n(number)),10)) + outbytes = append(outbytes, dat...) + //log.Print("Outputted the random number") + i += 6 + lastTag = i + } } } } + //fmt.Println(outbytes) + //fmt.Println(string(outbytes)) if len(outbytes) != 0 { return string(outbytes) } @@ -313,4 +360,4 @@ func bbcode_full_parse(data interface{}) interface{} { msg = string(msgbytes) } return msg -} \ No newline at end of file +} diff --git a/public/global.js b/public/global.js index c8a9d234..923087c9 100644 --- a/public/global.js +++ b/public/global.js @@ -15,7 +15,6 @@ $(document).ready(function(){ $(".open_edit").click(function(event){ console.log("Clicked on edit"); event.preventDefault(); - $(".hide_on_edit").hide(); $(".show_on_edit").show(); }); @@ -109,4 +108,17 @@ $(document).ready(function(){ }); }); }); + + $(this).find(".ip_item").each(function(){ + var ip = $(this).text(); + //var ip_width = $(this).width(); + console.log("IP: " + ip); + if(ip.length > 10){ + $(this).html("Show IP"); + $(this).click(function(event){ + event.preventDefault(); + $(this).text(ip);/*.animate({width: ip.width},{duration: 1000, easing: 'easeOutBounce'});*/ + }); + } + }); }); \ No newline at end of file diff --git a/reply.go b/reply.go index 47c9bfa3..0a1e8533 100644 --- a/reply.go +++ b/reply.go @@ -21,4 +21,5 @@ type Reply struct URLPrefix string URLName string Level int + IpAddress string } diff --git a/router.go b/router.go index d7834c60..cd6c0edc 100644 --- a/router.go +++ b/router.go @@ -43,7 +43,7 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { if req.URL.Path[len(req.URL.Path) - 1] == '/' { w.WriteHeader(404) - w.Write([]byte("")) + w.Write(error_notfound) return } @@ -61,6 +61,6 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { } w.WriteHeader(404) - w.Write([]byte("")) + w.Write(error_notfound) return } \ No newline at end of file diff --git a/routes.go b/routes.go index e5b167ac..13611e21 100644 --- a/routes.go +++ b/routes.go @@ -10,6 +10,7 @@ import "strings" import "time" import "io" import "os" +import "net" import "net/http" import "html" import "html/template" @@ -19,7 +20,7 @@ import "golang.org/x/crypto/bcrypt" // A blank list to fill out that parameter in Page for routes which don't use it var tList []interface{} -var nList map[int]string +var nList []string // GET functions func route_static(w http.ResponseWriter, r *http.Request){ @@ -47,6 +48,11 @@ func route_static(w http.ResponseWriter, r *http.Request){ //io.CopyN(w, bytes.NewReader(file.Data), static_files[r.URL.Path].Length) } +/*func route_exit(w http.ResponseWriter, r *http.Request){ + db.Close() + os.Exit(0) +}*/ + func route_fstatic(w http.ResponseWriter, r *http.Request){ http.ServeFile(w, r, r.URL.Path) } @@ -56,8 +62,7 @@ func route_overview(w http.ResponseWriter, r *http.Request){ if !ok { return } - - pi := Page{"Overview","overview",user,noticeList,tList,0} + pi := Page{"Overview",user,noticeList,tList,nil} err := templates.ExecuteTemplate(w,"overview.html", pi) if err != nil { InternalError(err, w, r, user) @@ -73,8 +78,9 @@ func route_custom_page(w http.ResponseWriter, r *http.Request){ name := r.URL.Path[len("/pages/"):] if templates.Lookup("page_" + name) == nil { NotFound(w,r,user) + return } - pi := Page{"Page","page",user,noticeList,tList,0} + pi := Page{"Page",user,noticeList,tList,0} err := templates.ExecuteTemplate(w,"page_" + name,pi) if err != nil { InternalError(err, w, r, user) @@ -98,7 +104,6 @@ func route_topics(w http.ResponseWriter, r *http.Request){ InternalError(err,w,r,user) return } - defer rows.Close() topicItem := TopicUser{ID: 0,} for rows.Next() { @@ -126,8 +131,9 @@ func route_topics(w http.ResponseWriter, r *http.Request){ InternalError(err,w,r,user) return } + rows.Close() - pi := TopicsPage{"Topic List",user,noticeList,topicList,0} + pi := TopicsPage{"Topic List",user,noticeList,topicList,nil} if template_topics_handle != nil { template_topics_handle(pi,w) } else { @@ -145,7 +151,6 @@ func route_forum(w http.ResponseWriter, r *http.Request){ } var topicList []TopicUser - fid, err := strconv.Atoi(r.URL.Path[len("/forum/"):]) if err != nil { LocalError("The provided ForumID is not a valid number.",w,r,user) @@ -162,12 +167,11 @@ func route_forum(w http.ResponseWriter, r *http.Request){ return } - rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid WHERE topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC", fid) + rows, err := get_forum_topics_stmt.Query(fid) if err != nil { InternalError(err,w,r,user) return } - defer rows.Close() topicItem := TopicUser{ID: 0} for rows.Next() { @@ -195,8 +199,9 @@ func route_forum(w http.ResponseWriter, r *http.Request){ InternalError(err,w,r,user) return } + rows.Close() - pi := ForumPage{forums[fid].Name,user,noticeList,topicList,0} + pi := ForumPage{forums[fid].Name,user,noticeList,topicList,nil} if template_forum_handle != nil { template_forum_handle(pi,w) } else { @@ -220,13 +225,13 @@ func route_forums(w http.ResponseWriter, r *http.Request){ } } - pi := ForumsPage{"Forum List",user,noticeList,forumList,0} + pi := ForumsPage{"Forum List",user,noticeList,forumList,nil} if template_forums_handle != nil { template_forums_handle(pi,w) } else { - err := templates.ExecuteTemplate(w,"forums.html", pi) + err := templates.ExecuteTemplate(w,"forums.html",pi) if err != nil { - InternalError(err, w, r, user) + InternalError(err,w,r,user) } } } @@ -238,25 +243,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ } var( err error - rid int content string - replyContent string - replyCreatedBy int - replyCreatedByName string - replyCreatedAt string - replyLastEdit int - replyLastEditBy int - replyAvatar string - replyCss template.CSS - replyLines int - replyTag string - replyURL string - replyURLPrefix string - replyURLName string - replyLevel int is_super_admin bool group int - replyList []Reply ) @@ -274,7 +263,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ } // Get the topic.. - 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 from topics left join users ON topics.createdBy = users.uid where tid = ?", topic.ID).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) + err = get_topic_user_stmt.QueryRow(topic.ID).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) if err == sql.ErrNoRows { NotFound(w,r,user) return @@ -302,11 +291,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ topic.Css = staff_css_tmpl topic.Level = -1 } - //if groups[group].Tag != "" { - topic.Tag = groups[group].Tag - //} else { - // topic.Tag = "" - //} + + topic.Tag = groups[group].Tag + if settings["url_tags"] == false { topic.URLName = "" } else { @@ -314,56 +301,54 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ if !ok { topic.URL = topic.URLName } else { - topic.URL = replyURL + topic.URLName + topic.URL = topic.URL + topic.URLName } } // Get the replies.. - 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 from replies left join users ON replies.createdBy = users.uid where tid = ?", topic.ID) + rows, err := get_topic_replies_stmt.Query(topic.ID) if err != nil { InternalError(err,w,r,user) return } - defer rows.Close() + replyItem := Reply{Css: no_css_tmpl} for rows.Next() { - err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group, &replyURLPrefix, &replyURLName, &replyLevel) + err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &is_super_admin, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress) if err != nil { InternalError(err,w,r,user) return } - replyLines = strings.Count(replyContent,"\n") + replyItem.ParentID = topic.ID + replyItem.ContentHtml = template.HTML(parse_message(replyItem.Content)) + replyItem.ContentLines = strings.Count(replyItem.Content,"\n") if is_super_admin || groups[group].Is_Mod || groups[group].Is_Admin { - replyCss = staff_css_tmpl - replyLevel = -1 + replyItem.Css = staff_css_tmpl + replyItem.Level = -1 } else { - replyCss = no_css_tmpl + replyItem.Css = no_css_tmpl } - if replyAvatar != "" { - if replyAvatar[0] == '.' { - replyAvatar = "/uploads/avatar_" + strconv.Itoa(replyCreatedBy) + replyAvatar + if replyItem.Avatar != "" { + if replyItem.Avatar[0] == '.' { + replyItem.Avatar = "/uploads/avatar_" + strconv.Itoa(replyItem.CreatedBy) + replyItem.Avatar } } else { - replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1) - } - //if groups[group].Tag != "" { - replyTag = groups[group].Tag - //} else { - // replyTag = "" - //} - if settings["url_tags"] == false { - replyURLName = "" - } else { - replyURL, ok = external_sites[replyURLPrefix] - if !ok { - replyURL = replyURLName - } else { - replyURL = replyURL + replyURLName - } + replyItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyItem.CreatedBy),1) } - replyItem := Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,replyURL,replyURLPrefix,replyURLName,replyLevel} + replyItem.Tag = groups[group].Tag + + if settings["url_tags"] == false { + replyItem.URLName = "" + } else { + replyItem.URL, ok = external_sites[replyItem.URLPrefix] + if !ok { + replyItem.URL = replyItem.URLName + } else { + replyItem.URL = replyItem.URL + replyItem.URLName + } + } if hooks["rrow_assign"] != nil { replyItem = run_hook("rrow_assign", replyItem).(Reply) @@ -375,8 +360,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ InternalError(err,w,r,user) return } + rows.Close() - tpage := TopicPage{topic.Title,user,noticeList,replyList,topic,0} + tpage := TopicPage{topic.Title,user,noticeList,replyList,topic,nil} if template_topic_handle != nil { template_topic_handle(tpage,w) } else { @@ -424,7 +410,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){ puser = user } else { // Fetch the user data - err = db.QueryRow("SELECT `name`, `group`, `is_super_admin`, `avatar`, `message`, `url_prefix`, `url_name`, `level` FROM `users` WHERE `uid` = ?", puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level) + err = db.QueryRow("select `name`,`group`,`is_super_admin`,`avatar`,`message`,`url_prefix`,`url_name`,`level` from `users` where `uid` = ?", puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level) if err == sql.ErrNoRows { NotFound(w,r,user) return @@ -442,11 +428,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){ } } - //if groups[puser.Group].Tag != "" { - puser.Tag = groups[puser.Group].Tag - //} else { - // puser.Tag = "" - //} + puser.Tag = groups[puser.Group].Tag if puser.Avatar != "" { if puser.Avatar[0] == '.' { @@ -492,7 +474,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){ replyTag = "" } - replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0}) + replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0,""}) } err = rows.Err() if err != nil { @@ -520,7 +502,7 @@ func route_topic_create(w http.ResponseWriter, r *http.Request){ NoPermissions(w,r,user) return } - pi := Page{"Create Topic","create-topic",user,noticeList,tList,0} + pi := Page{"Create Topic",user,noticeList,tList,0} templates.ExecuteTemplate(w,"create-topic.html", pi) } @@ -542,8 +524,13 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) { } topic_name := html.EscapeString(r.PostFormValue("topic-name")) content := html.EscapeString(preparse_message(r.PostFormValue("topic-content"))) + ipaddress, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + LocalError("Bad IP",w,r,user) + return + } - res, err := create_topic_stmt.Exec(topic_name,content,parse_message(content),user.ID) + res, err := create_topic_stmt.Exec(topic_name,content,parse_message(content),ipaddress,user.ID) if err != nil { InternalError(err,w,r,user) return @@ -591,8 +578,13 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { } content := preparse_message(html.EscapeString(r.PostFormValue("reply-content"))) - //log.Print(content) - _, err = create_reply_stmt.Exec(tid,content,parse_message(content),user.ID) + ipaddress, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + LocalError("Bad IP",w,r,user) + return + } + + _, err = create_reply_stmt.Exec(tid,content,parse_message(content),ipaddress,user.ID) if err != nil { InternalError(err,w,r,user) return @@ -799,7 +791,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) { if success != 1 { errmsg := "Unable to create the report" - pi := Page{"Error","error",user,nList,tList,errmsg} + pi := Page{"Error",user,nList,tList,errmsg} var b bytes.Buffer templates.ExecuteTemplate(&b,"error.html", pi) @@ -820,7 +812,7 @@ func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request) { LocalError("You need to login to edit your account.",w,r,user) return } - pi := Page{"Edit Password","account-own-edit",user,noticeList,tList,0} + pi := Page{"Edit Password",user,noticeList,tList,0} templates.ExecuteTemplate(w,"account-own-edit.html", pi) } @@ -878,7 +870,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque } noticeList[len(noticeList)] = "Your password was successfully updated" - pi := Page{"Edit Password","account-own-edit",user,noticeList,tList,0} + pi := Page{"Edit Password",user,noticeList,tList,0} templates.ExecuteTemplate(w,"account-own-edit.html", pi) } @@ -891,7 +883,7 @@ func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request) { LocalError("You need to login to edit your account.",w,r,user) return } - pi := Page{"Edit Avatar","account-own-edit-avatar",user,noticeList,tList,0} + pi := Page{"Edit Avatar",user,noticeList,tList,0} templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi) } @@ -977,9 +969,9 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request return } user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext - noticeList[len(noticeList)] = "Your avatar was successfully updated" + noticeList = append(noticeList, "Your avatar was successfully updated") - pi := Page{"Edit Avatar","account-own-edit-avatar",user,noticeList,tList,0} + pi := Page{"Edit Avatar",user,noticeList,tList,0} templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi) } @@ -993,7 +985,7 @@ func route_account_own_edit_username(w http.ResponseWriter, r *http.Request) { return } - pi := Page{"Edit Username","account-own-edit-username",user,noticeList,tList,user.Name} + pi := Page{"Edit Username",user,noticeList,tList,user.Name} templates.ExecuteTemplate(w,"account-own-edit-username.html", pi) } @@ -1020,8 +1012,8 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque } user.Name = new_username - noticeList[len(noticeList)] = "Your username was successfully updated" - pi := Page{"Edit Username","account-own-edit-username",user,noticeList,tList,0} + noticeList = append(noticeList,"Your username was successfully updated") + pi := Page{"Edit Username",user,noticeList,tList,0} templates.ExecuteTemplate(w,"account-own-edit-username.html", pi) } @@ -1037,7 +1029,7 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) { email := Email{UserID: user.ID} var emailList []interface{} - rows, err := db.Query("SELECT email, validated FROM emails WHERE uid = ?", user.ID) + rows, err := db.Query("select email, validated from emails where uid = ?", user.ID) if err != nil { log.Fatal(err) } @@ -1068,9 +1060,9 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) { } if !enable_emails { - noticeList[len(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","account-own-edit-email",user,noticeList,emailList,0} + pi := Page{"Email Manager",user,noticeList,emailList,0} templates.ExecuteTemplate(w,"account-own-edit-email.html", pi) } @@ -1088,7 +1080,7 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re email := Email{UserID: user.ID} targetEmail := Email{UserID: user.ID} var emailList []interface{} - rows, err := db.Query("SELECT email, validated, token FROM emails WHERE uid = ?", user.ID) + rows, err := db.Query("select email, validated, token from emails where uid = ?", user.ID) if err != nil { log.Fatal(err) } @@ -1138,10 +1130,10 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re } if !enable_emails { - noticeList[len(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[len(noticeList)] = "Your email was successfully verified" - pi := Page{"Email Manager","account-own-edit-email",user,noticeList,emailList,0} + noticeList = append(noticeList,"Your email was successfully verified") + pi := Page{"Email Manager",user,noticeList,emailList,0} templates.ExecuteTemplate(w,"account-own-edit-email.html", pi) } @@ -1172,7 +1164,7 @@ func route_login(w http.ResponseWriter, r *http.Request) { LocalError("You're already logged in.",w,r,user) return } - pi := Page{"Login","login",user,noticeList,tList,0} + pi := Page{"Login",user,noticeList,tList,0} templates.ExecuteTemplate(w,"login.html", pi) } @@ -1262,7 +1254,7 @@ func route_register(w http.ResponseWriter, r *http.Request) { LocalError("You're already logged in.",w,r,user) return } - pi := Page{"Registration","register",user,noticeList,tList,0} + pi := Page{"Registration",user,noticeList,tList,0} templates.ExecuteTemplate(w,"register.html", pi) } diff --git a/run.bat b/run.bat index 359bc72d..90be3557 100644 --- a/run.bat +++ b/run.bat @@ -1,8 +1,18 @@ @echo off +echo Generating the dynamic code +go generate +if %errorlevel% neq 0 ( + pause + exit /b %errorlevel% +) + +echo Building the executable go build if %errorlevel% neq 0 ( pause exit /b %errorlevel% ) + +echo Running Gosora gosora.exe pause \ No newline at end of file diff --git a/template_forum.go b/template_forum.go index 9758c3aa..089a934f 100644 --- a/template_forum.go +++ b/template_forum.go @@ -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_forum_handle = template_forum @@ -12,93 +12,65 @@ func init() { } func template_forum(tmpl_forum_vars ForumPage, w io.Writer) { -w.Write([]byte(` - -
-` + string(tmpl_topic_vars.Topic.Content.(template.HTML)) + `
-{{.Topic.Content}}