diff --git a/README.md b/README.md index bca745cf..2c1da133 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Add a plugin system. Tweak the CSS to make it responsive. -Nest the moderation routes to possibly speed routing up a little...? +Implement a faster router. Add a friend system. diff --git a/data.sql b/data.sql index ef692c39..577cef3f 100644 --- a/data.sql +++ b/data.sql @@ -102,14 +102,20 @@ CREATE TABLE `plugins`( INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool'); INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3',); -INSERT INTO users(`name`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`) -VALUES ('Admin',1,1,NOW(),NOW(),''); +INSERT INTO users(`name`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`) +VALUES ('Admin','admin@localhost',1,1,NOW(),NOW(),''); /* The Permissions: BanUsers ActivateUsers +EditUser +EditUserEmail +EditUserPassword +EditUserGroup +EditUserGroupSuperMod +EditUserGroupAdmin ManageForums EditSettings ManagePlugins @@ -126,11 +132,11 @@ PinTopic CloseTopic */ -INSERT INTO users_groups(`name`,`permissions`,`active`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"ManageForums":true,"EditSettings":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,1,"Admin"); -INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod"); -INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"BanUsers":false,"ActivateUsers":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":true,"EditTopic":false,"DeleteTopic":false,"CreateReply":true,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); -INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"BanUsers":false,"ActivateUsers":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}',1); -INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Awaiting Activation','{"BanUsers":false,"ActivateUsers":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); +INSERT INTO users_groups(`name`,`permissions`,`active`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,1,1,"Admin"); +INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":true,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',1,"Mod"); +INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":true,"EditTopic":false,"DeleteTopic":false,"CreateReply":true,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); +INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}',1); +INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Awaiting Activation','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManagePlugins":false,"ViewIPs":false,"ViewTopic":true,"CreateTopic":false,"EditTopic":false,"DeleteTopic":false,"CreateReply":false,"EditReply":false,"DeleteReply":false,"PinTopic":false,"CloseTopic":false}'); INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',NOW()); INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`createdBy`,`parentID`) diff --git a/general_test.go b/general_test.go index bef30b46..b4fa2eb9 100644 --- a/general_test.go +++ b/general_test.go @@ -1,17 +1,24 @@ package main +//import "fmt" +import "log" +import "bytes" import "testing" +import "net/http" +import "net/http/httptest" import "io/ioutil" import "html/template" -func BenchmarkTemplates(b *testing.B) { - user := User{0,"Bob",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} - admin := User{1,"Admin",0,true,true,true,true,true,false,AllPerms,"",false,"","","","",""} +func BenchmarkTopicTemplate(b *testing.B) { + b.ReportAllocs() + + user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} + admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","",""} var noticeList map[int]string = make(map[int]string) noticeList[0] = "test" topic := TopicUser{0,"Lol",template.HTML("Hey everyone!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} - var replyList []interface{} + var replyList []Reply replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) @@ -23,65 +30,203 @@ func BenchmarkTemplates(b *testing.B) { replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - - var replyList2 []Reply - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - replyList2 = append(replyList2, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - - pi := Page{"Topic Blah","topic",user,noticeList,replyList,topic} - pi2 := Page{"Topic Blah","topic",admin,noticeList,replyList,topic} - tpage := TopicPage{"Topic Blah","topic",user,noticeList,replyList2,topic,false} - tpage2 := TopicPage{"Topic Blah","topic",admin,noticeList,replyList2,topic,false} + tpage := TopicPage{"Topic Blah","topic",user,noticeList,replyList,topic,false} + tpage2 := TopicPage{"Topic Blah","topic",admin,noticeList,replyList,topic,false} w := ioutil.Discard b.Run("compiled_useradmin", func(b *testing.B) { - for i := 0; i < b.N; i++ { - template_topic_2(pi2,w) - } - }) - /*b.Run("interpreted_useradmin", func(b *testing.B) { - for i := 0; i < b.N; i++ { - templates.ExecuteTemplate(w,"topic.html", pi2) - } - })*/ - b.Run("compiled_userguest", func(b *testing.B) { - for i := 0; i < b.N; i++ { - template_topic_2(pi,w) - } - }) - /*b.Run("interpreted_userguest", func(b *testing.B) { - for i := 0; i < b.N; i++ { - templates.ExecuteTemplate(w,"topic.html", pi) - } - })*/ - - - b.Run("compiled_customstruct_useradmin", func(b *testing.B) { for i := 0; i < b.N; i++ { template_topic(tpage2,w) } }) - b.Run("interpreted_customstruct_useradmin", func(b *testing.B) { + b.Run("interpreted_useradmin", func(b *testing.B) { for i := 0; i < b.N; i++ { templates.ExecuteTemplate(w,"topic.html", tpage2) } }) - b.Run("compiled_customstruct_userguest", func(b *testing.B) { + b.Run("compiled_userguest", func(b *testing.B) { for i := 0; i < b.N; i++ { template_topic(tpage,w) } }) - b.Run("interpreted_customstruct_userguest", func(b *testing.B) { + b.Run("interpreted_userguest", func(b *testing.B) { for i := 0; i < b.N; i++ { templates.ExecuteTemplate(w,"topic.html", tpage) } }) } + +func BenchmarkTopicsTemplate(b *testing.B) { + b.ReportAllocs() + + user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} + admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","",""} + var noticeList map[int]string = make(map[int]string) + noticeList[0] = "test" + + var topicList []interface{} + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) + + tpage := Page{"Topic Blah","topic",user,noticeList,topicList,0} + tpage2 := Page{"Topic Blah","topic",admin,noticeList,topicList,0} + w := ioutil.Discard + + 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) { + for i := 0; i < b.N; i++ { + templates.ExecuteTemplate(w,"topics.html", tpage2) + } + }) + 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) { + for i := 0; i < b.N; i++ { + templates.ExecuteTemplate(w,"topics.html", tpage) + } + }) +} + +func BenchmarkRoute(b *testing.B) { + b.ReportAllocs() + + admin_uid_cookie := http.Cookie{Name: "uid",Value: "1",Path: "/",MaxAge: year} + // TO-DO: Stop hard-coding this value + 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) + + topics_w := httptest.NewRecorder() + topics_req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil)) + topics_req_admin := topics_req + topics_req_admin.AddCookie(&admin_uid_cookie) + topics_req_admin.AddCookie(&admin_session_cookie) + topics_handler := http.HandlerFunc(route_topics) + + forum_w := httptest.NewRecorder() + forum_req := httptest.NewRequest("get","/forum/1",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) + + 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) + + 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); + external_sites["YT"] = "https://www.youtube.com/" + hooks["trow_assign"] = nil + hooks["rrow_assign"] = nil + + for name, body := range plugins { + if body.Active { + plugins[name].Init() + } + } + + b.Run("topic_admin", func(b *testing.B) { + 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!") + //} + } + }) + b.Run("topic_guest", func(b *testing.B) { + for i := 0; i < b.N; i++ { + //topic_w.Code = 200 + topic_w.Body.Reset() + topic_handler.ServeHTTP(topic_w,topic_req) + } + }) + b.Run("topics_admin", 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) { + 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) { + 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) { + 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) { + 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) { + for i := 0; i < b.N; i++ { + //forums_w.Code = 200 + forums_w.Body.Reset() + forums_handler.ServeHTTP(forums_w,forums_req) + } + }) + + serveMux := http.NewServeMux() + serveMux.HandleFunc("/topics/", route_topics) + b.Run("topics_guest_plus_router", func(b *testing.B) { + for i := 0; i < b.N; i++ { + topics_w.Body.Reset() + serveMux.ServeHTTP(topics_w,topics_req) + } + }) +} + +/*func TestRoute(b *testing.T) { + +}*/ \ No newline at end of file diff --git a/gosora.exe b/gosora.exe index 1388b30e..21ab5452 100644 Binary files a/gosora.exe and b/gosora.exe differ diff --git a/group.go b/group.go index d7a9d5d8..155f39e7 100644 --- a/group.go +++ b/group.go @@ -16,11 +16,18 @@ type Group struct Tag string } +// Permission Structure: ActionComponent[Subcomponent]Flag type Perms struct { // Global Permissions BanUsers bool ActivateUsers bool + EditUser bool + EditUserEmail bool + EditUserPassword bool + EditUserGroup bool + EditUserGroupSuperMod bool + EditUserGroupAdmin bool ManageForums bool // This could be local, albeit limited for per-forum managers EditSettings bool ManagePlugins bool @@ -71,6 +78,12 @@ func init() { AllPerms = Perms{ BanUsers: true, ActivateUsers: true, + EditUser: true, + EditUserEmail: true, + EditUserPassword: true, + EditUserGroup: true, + EditUserGroupSuperMod: true, + EditUserGroupAdmin: true, ManageForums: true, EditSettings: true, ManagePlugins: true, diff --git a/images/bench_round1.PNG b/images/bench_round1.PNG new file mode 100644 index 00000000..f7e4c0a8 Binary files /dev/null and b/images/bench_round1.PNG differ diff --git a/images/bench_round1_with_memory_allocs.PNG b/images/bench_round1_with_memory_allocs.PNG new file mode 100644 index 00000000..be57685d Binary files /dev/null and b/images/bench_round1_with_memory_allocs.PNG differ diff --git a/images/bench_round1_with_router_bench.PNG b/images/bench_round1_with_router_bench.PNG new file mode 100644 index 00000000..89661c04 Binary files /dev/null and b/images/bench_round1_with_router_bench.PNG differ diff --git a/images/bench_topic_route.PNG b/images/bench_topic_route.PNG new file mode 100644 index 00000000..7aa8851c Binary files /dev/null and b/images/bench_topic_route.PNG differ diff --git a/main.go b/main.go index 7968224a..e4d1e7c7 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ const kilobyte int = 1024 const megabyte int = 1024 * 1024 const saltLength int = 32 const sessionLength int = 80 +var nogrouplog bool = false // This is mainly for benchmarks, as we don't want a lot of information getting in the way of the results var templates = template.Must(template.ParseGlob("templates/*")) var no_css_tmpl = template.CSS("") @@ -39,7 +40,7 @@ var template_profile_handle func(Page,io.Writer) = nil func compile_templates() { var c CTemplateSet - user := User{0,"",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} + user := User{0,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} var noticeList map[int]string = make(map[int]string) noticeList[0] = "test" @@ -206,6 +207,7 @@ func main(){ http.HandleFunc("/panel/plugins/deactivate/", route_panel_plugins_deactivate) http.HandleFunc("/panel/users/", route_panel_users) http.HandleFunc("/panel/users/edit/", route_panel_users_edit) + http.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit) http.HandleFunc("/", default_route) diff --git a/mod_routes.go b/mod_routes.go index adabbacb..09a5bf21 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -446,6 +446,11 @@ func route_unban(w http.ResponseWriter, r *http.Request) { return } + if r.FormValue("session") != user.Session { + SecurityError(w,r,user) + return + } + uid, err := strconv.Atoi(r.URL.Path[len("/users/unban/"):]) if err != nil { LocalError("The provided User ID is not a valid number.",w,r,user) @@ -486,6 +491,11 @@ func route_activate(w http.ResponseWriter, r *http.Request) { return } + if r.FormValue("session") != user.Session { + SecurityError(w,r,user) + return + } + uid, err := strconv.Atoi(r.URL.Path[len("/users/activate/"):]) if err != nil { LocalError("The provided User ID is not a valid number.",w,r,user) @@ -678,7 +688,6 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request) { } forum_name := r.PostFormValue("edit_item") - forum, ok := forums[fid]; if !ok { LocalError("The forum you're trying to edit doesn't exist.",w,r,user) @@ -790,7 +799,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request){ labels := strings.Split(llist,",") for index, label := range labels { - itemList = append(itemList, SettingLabel{ + itemList = append(itemList, OptionLabel{ Label: label, Value: index + 1, Selected: conv == (index + 1), @@ -887,6 +896,11 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){ return } + if r.FormValue("session") != user.Session { + SecurityError(w,r,user) + return + } + uname := r.URL.Path[len("/panel/plugins/activate/"):] plugin, ok := plugins[uname] if !ok { @@ -945,6 +959,11 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request){ return } + if r.FormValue("session") != user.Session { + SecurityError(w,r,user) + return + } + uname := r.URL.Path[len("/panel/plugins/deactivate/"):] plugin, ok := plugins[uname] if !ok { @@ -990,7 +1009,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ } var userList []interface{} - rows, err := db.Query("SELECT `uid`, `name`, `group`, `active`, `is_super_admin`, `avatar` FROM users") + rows, err := db.Query("SELECT `uid`,`name`,`group`,`active`,`is_super_admin`,`avatar` FROM users") if err != nil { InternalError(err,w,r,user) return @@ -1043,5 +1062,150 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ } func route_panel_users_edit(w http.ResponseWriter, r *http.Request){ + user, noticeList, ok := SessionCheck(w,r) + if !ok { + return + } + // Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with + if !user.Is_Super_Mod || !user.Perms.EditUser { + NoPermissions(w,r,user) + return + } + + var err error + targetUser := User{ID: 0,} + targetUser.ID, 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) + if err == sql.ErrNoRows { + LocalError("The user you're trying to edit doesn't exist.",w,r,user) + return + } else if err != nil { + InternalError(err,w,r,user) + 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 + } + + var groupList []interface{} + for _, group := range groups { + if !user.Perms.EditUserGroupAdmin && group.Is_Admin { + continue + } + if !user.Perms.EditUserGroupSuperMod && group.Is_Mod { + continue + } + groupList = append(groupList, group) + } + + pi := Page{"User Editor","panel-user-edit",user,noticeList,groupList,targetUser} + err = templates.ExecuteTemplate(w,"panel-user-edit.html", pi) + if err != nil { + InternalError(err, w, r, user) + } } + +func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request){ + user, ok := SimpleSessionCheck(w,r) + if !ok { + return + } + if !user.Is_Super_Mod || !user.Perms.EditUser { + NoPermissions(w,r,user) + return + } + + if r.FormValue("session") != user.Session { + SecurityError(w,r,user) + return + } + + var err error + targetUser := User{ID: 0,} + targetUser.ID, 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) + if err == sql.ErrNoRows { + LocalError("The user you're trying to edit doesn't exist.",w,r,user) + return + } else if err != nil { + InternalError(err,w,r,user) + 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 + } + + newname := html.EscapeString(r.PostFormValue("user-name")) + if newname == "" { + LocalError("You didn't put in a username.", w, r, user) + return + } + + newemail := html.EscapeString(r.PostFormValue("user-email")) + if newemail == "" { + LocalError("You didn't put in an email address.", w, r, user) + return + } + if (newemail != targetUser.Email) && !user.Perms.EditUserEmail { + LocalError("You need the EditUserEmail permission to edit the email address of a user.", w, r, user) + return + } + + newpassword := r.PostFormValue("user-password") + if newpassword != "" && !user.Perms.EditUserPassword { + LocalError("You need the EditUserPassword permission to edit the password of a user.", w, r, user) + return + } + + newgroup, err := strconv.Atoi(r.PostFormValue("user-group")) + if err != nil { + LocalError("The provided GroupID is not a valid number.",w,r,user) + return + } + + _, ok = groups[newgroup] + if !ok { + LocalError("The group you're trying to place this user in doesn't exist.",w,r,user) + return + } + + if !user.Perms.EditUserGroupAdmin && groups[newgroup].Is_Admin { + LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.",w,r,user) + return + } + if !user.Perms.EditUserGroupSuperMod && groups[newgroup].Is_Mod { + LocalError("You need the EditUserGroupAdmin permission to assign someone to a super mod group.",w,r,user) + return + } + + _, err = update_user_stmt.Exec(newname,newemail,newgroup,targetUser.ID) + if err != nil { + InternalError(err,w,r,user) + return + } + + if newpassword != "" { + SetPassword(targetUser.ID, newpassword) + } + + http.Redirect(w,r,"/panel/users/edit/" + strconv.Itoa(targetUser.ID),http.StatusSeeOther) +} \ No newline at end of file diff --git a/mysql.go b/mysql.go index f821537b..b0e98394 100644 --- a/mysql.go +++ b/mysql.go @@ -9,6 +9,7 @@ import "encoding/json" var db *sql.DB var get_session_stmt *sql.Stmt +var get_topic_list_stmt *sql.Stmt var create_topic_stmt *sql.Stmt var create_report_stmt *sql.Stmt var create_reply_stmt *sql.Stmt @@ -40,6 +41,7 @@ var update_forum_stmt *sql.Stmt var update_setting_stmt *sql.Stmt var add_plugin_stmt *sql.Stmt var update_plugin_stmt *sql.Stmt +var update_user_stmt *sql.Stmt func init_database(err error) { if(dbpassword != ""){ @@ -57,13 +59,19 @@ 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`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''") + get_session_stmt, err = db.Prepare("select `uid`, `name`, `group`, `is_super_admin`, `session`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''") + if err != nil { + log.Fatal(err) + } + + log.Print("Preparing get_topic_list statement.") + get_topic_list_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 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,createdBy) VALUES(?,?,?,NOW(),?)") if err != nil { log.Fatal(err) } @@ -245,6 +253,12 @@ func init_database(err error) { log.Fatal(err) } + log.Print("Preparing update_user statement.") + update_user_stmt, err = db.Prepare("UPDATE `users` SET `name` = ?, `email` = ?, `group` = ? WHERE `uid` = ?") + if err != nil { + log.Fatal(err) + } + log.Print("Loading the usergroups.") rows, err := db.Query("SELECT gid,name,permissions,is_mod,is_admin,is_banned,tag FROM users_groups") if err != nil { @@ -264,8 +278,10 @@ func init_database(err error) { log.Fatal(err) } - fmt.Println(group.Name + ": ") - fmt.Printf("%+v\n", group.Perms) + if !nogrouplog { + fmt.Println(group.Name + ": ") + fmt.Printf("%+v\n", group.Perms) + } group.Perms.ExtData = make(map[string]bool) groups[group.ID] = group diff --git a/images/test_compiled_vs_interpreted.PNG b/old-images/test_compiled_vs_interpreted.PNG similarity index 100% rename from images/test_compiled_vs_interpreted.PNG rename to old-images/test_compiled_vs_interpreted.PNG diff --git a/images/test_maps_vs_slices.PNG b/old-images/test_maps_vs_slices.PNG similarity index 100% rename from images/test_maps_vs_slices.PNG rename to old-images/test_maps_vs_slices.PNG diff --git a/images/test_typedstruct_vs_interfacestruct.PNG b/old-images/test_typedstruct_vs_interfacestruct.PNG similarity index 100% rename from images/test_typedstruct_vs_interfacestruct.PNG rename to old-images/test_typedstruct_vs_interfacestruct.PNG diff --git a/router.go b/router.go new file mode 100644 index 00000000..36d956bb --- /dev/null +++ b/router.go @@ -0,0 +1,31 @@ +package main +/*import "sync" +import "net/http" + +type Router struct { + mu sync.RWMutex + routes map[string]http.Handler +} + +func (route *Router) ServeHTTP() { + route.mu.RLock() + defer route.mu.RUnlock() + + if path[0] != "/" { + return route.routes["/"] + } + + // Do something on the path to turn slashes facing the wrong way "\" into "/" slashes. If it's bytes, then alter the bytes in place for the maximum speed + + handle := route.routes[path] + if !ok { + if path[-1] != "/" { + handle = route.routes[path + "/"] + if !ok { + return route.routes["/"] + } + return handle + } + } + return handle +}*/ \ No newline at end of file diff --git a/routes.go b/routes.go index 0b34c298..8168190e 100644 --- a/routes.go +++ b/routes.go @@ -98,7 +98,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){ avatar string ) - 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 order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC") + rows, err := get_topic_list_stmt.Query() if err != nil { InternalError(err,w,r,user) return @@ -287,14 +287,16 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ replyList []Reply ) - topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} + topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):]) if err != nil { LocalError("The provided TopicID is not a valid number.",w,r,user) return } if !user.Perms.ViewTopic { + //fmt.Printf("%+v\n", user) + //fmt.Printf("%+v\n", user.Perms) NoPermissions(w,r,user) return } diff --git a/setting.go b/setting.go index 63fa461b..7ce7211a 100644 --- a/setting.go +++ b/setting.go @@ -4,7 +4,7 @@ import "strings" var settingLabels map[string]string -type SettingLabel struct +type OptionLabel struct { Label string Value int diff --git a/template_topic_old.go b/template_topic_old.go deleted file mode 100644 index affc9d1c..00000000 --- a/template_topic_old.go +++ /dev/null @@ -1,186 +0,0 @@ -package main -import "io" -import "strconv" -import "html/template" - -/*func init() { -ctemplates["topic"] = template_topic -}*/ - -func template_topic_2(tmpl_topic_vars Page, w io.Writer) { -var extra_data TopicUser = tmpl_topic_vars.Something.(TopicUser) -w.Write([]byte(` - -
-