diff --git a/config.go b/config.go index ef9ebec7..d82fbf06 100644 --- a/config.go +++ b/config.go @@ -13,6 +13,7 @@ var max_request_size = 5 * megabyte // Misc var default_route = route_topics var default_group = 3 +var activation_group = 5 var staff_css = " background-color: #ffeaff;" var uncategorised_forum_visible = true var enable_emails = false diff --git a/data.sql b/data.sql index ddf955c3..ef692c39 100644 --- a/data.sql +++ b/data.sql @@ -100,14 +100,37 @@ 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_groups(`name`,`permissions`,`active`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{}',1,1,1,"Admin"); -INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{}',1,"Mod"); -INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{}'); -INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{}',1); +/* +The Permissions: + +BanUsers +ActivateUsers +ManageForums +EditSettings +ManagePlugins +ViewIPs + +ViewTopic +CreateTopic +EditTopic +DeleteTopic +CreateReply +EditReply +DeleteReply +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 forums(`name`,`lastTopicTime`) VALUES ('General',NOW()); INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`createdBy`,`parentID`) diff --git a/extend.go b/extend.go index 546ff1c1..6d3f6030 100644 --- a/extend.go +++ b/extend.go @@ -35,7 +35,7 @@ func add_hook(name string, handler interface{}) { } } -func remove_hook(name string) { +func remove_hook(name string/*, plugin string */) { delete(hooks, name) } diff --git a/general_test.go b/general_test.go index 758feccc..bef30b46 100644 --- a/general_test.go +++ b/general_test.go @@ -4,26 +4,27 @@ import "io/ioutil" import "html/template" func BenchmarkTemplates(b *testing.B) { - user := User{0,"Bob",0,false,false,false,false,false,false,"",false,"","","","",""} - admin := User{1,"Admin",0,true,true,true,true,true,false,"",false,"","","","",""} + 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,"","","","",""} 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 map[int]interface{} = make(map[int]interface{}) - replyList[0] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[1] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[2] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[3] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[4] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[5] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[6] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[7] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[8] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} - replyList[9] = Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""} + var replyList []interface{} + 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,"","","",""}) + 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,"","","",""}) + 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,"","","",""}) + replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - var replyList2 []interface{} + + 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,"","","",""}) @@ -35,41 +36,52 @@ func BenchmarkTemplates(b *testing.B) { 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 := Page2{"Topic Blah","topic",user,noticeList,replyList,topic} - pi2 := Page2{"Topic Blah","topic",admin,noticeList,replyList,topic} - pi3 := Page{"Topic Blah","topic",user,noticeList,replyList2,topic} - pi4 := Page{"Topic Blah","topic",admin,noticeList,replyList2,topic} + 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} w := ioutil.Discard - b.Run("compiled_sliceloop_useradmin", func(b *testing.B) { + b.Run("compiled_useradmin", func(b *testing.B) { for i := 0; i < b.N; i++ { - template_topic(pi4,w) + template_topic_2(pi2,w) } }) - b.Run("compiled_maploop_useradmin", func(b *testing.B) { - for i := 0; i < b.N; i++ { - template_topic_maploop(pi2,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,"topic.html", pi2) } - }) - - b.Run("compiled_sliceloop_userguest", func(b *testing.B) { + })*/ + b.Run("compiled_userguest", func(b *testing.B) { for i := 0; i < b.N; i++ { - template_topic(pi3,w) + template_topic_2(pi,w) } }) - b.Run("compiled_maploop_userguest", func(b *testing.B) { - for i := 0; i < b.N; i++ { - template_topic_maploop(pi,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,"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) { + for i := 0; i < b.N; i++ { + templates.ExecuteTemplate(w,"topic.html", tpage2) + } + }) + b.Run("compiled_customstruct_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) { + for i := 0; i < b.N; i++ { + templates.ExecuteTemplate(w,"topic.html", tpage) + } }) } diff --git a/gosora.exe b/gosora.exe index d0a4f659..1388b30e 100644 Binary files a/gosora.exe and b/gosora.exe differ diff --git a/gosora.exe~ b/gosora.exe~ deleted file mode 100644 index e693a454..00000000 Binary files a/gosora.exe~ and /dev/null differ diff --git a/group.go b/group.go index 97ab14ed..d7a9d5d8 100644 --- a/group.go +++ b/group.go @@ -1,12 +1,98 @@ package main +import "fmt" + +var GuestPerms Perms +var AllPerms Perms type Group struct { ID int Name string - Permissions string + Perms Perms + PermissionsText []byte Is_Mod bool Is_Admin bool Is_Banned bool Tag string } + +type Perms struct +{ + // Global Permissions + BanUsers bool + ActivateUsers bool + ManageForums bool // This could be local, albeit limited for per-forum managers + EditSettings bool + ManagePlugins bool + ViewIPs bool + + // Forum permissions + ViewTopic bool + CreateTopic bool + EditTopic bool + DeleteTopic bool + CreateReply bool + //CreateReplyToOwn bool + EditReply bool + //EditOwnReply bool + DeleteReply bool + PinTopic bool + CloseTopic bool + //CloseOwnTopic bool + + ExtData interface{} +} + +/* Inherit from group permissions for ones we don't have */ +type ForumPerms struct +{ + ViewTopic bool + CreateTopic bool + EditTopic bool + DeleteTopic bool + CreateReply bool + //CreateReplyToOwn bool + EditReply bool + //EditOwnReply bool + DeleteReply bool + PinTopic bool + CloseTopic bool + //CloseOwnTopic bool + + ExtData map[string]bool +} + +func init() { + GuestPerms = Perms{ + ViewTopic: true, + ExtData: make(map[string]bool), + } + + AllPerms = Perms{ + 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, + + ExtData: make(map[string]bool), + } + + if debug { + fmt.Printf("Guest Perms: ") + fmt.Printf("%+v\n", GuestPerms) + fmt.Printf("All Perms: ") + fmt.Printf("%+v\n", AllPerms) + } +} \ No newline at end of file diff --git a/images/settings.PNG b/images/settings.PNG index 3559947e..68034d8d 100644 Binary files a/images/settings.PNG and b/images/settings.PNG differ diff --git a/images/test_typedstruct_vs_interfacestruct.PNG b/images/test_typedstruct_vs_interfacestruct.PNG new file mode 100644 index 00000000..c7625378 Binary files /dev/null and b/images/test_typedstruct_vs_interfacestruct.PNG differ diff --git a/main.go b/main.go index df6d14e2..7968224a 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ package main import ( "net/http" "log" - //"fmt" "mime" "strings" "path/filepath" @@ -24,7 +23,6 @@ const saltLength int = 32 const sessionLength int = 80 var templates = template.Must(template.ParseGlob("templates/*")) -//var custom_pages = template.Must(template.ParseGlob("pages/*")) var no_css_tmpl = template.CSS("") var staff_css_tmpl = template.CSS(staff_css) var settings map[string]interface{} = make(map[string]interface{}) @@ -32,29 +30,33 @@ var external_sites map[string]string = make(map[string]string) var groups map[int]Group = make(map[int]Group) var forums map[int]Forum = make(map[int]Forum) var static_files map[string]SFile = make(map[string]SFile) -var ctemplates map[string]func(Page,io.Writer) = make(map[string]func(Page,io.Writer)) +var ctemplates []string +var template_topic_handle func(TopicPage,io.Writer) = nil +var template_topics_handle func(Page,io.Writer) = nil +var template_forum_handle func(Page,io.Writer) = nil +var template_forums_handle func(Page,io.Writer) = nil +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,"",false,"","","","",""} + user := User{0,"",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} var noticeList map[int]string = make(map[int]string) noticeList[0] = "test" log.Print("Compiling the templates") topic := TopicUser{0,"",template.HTML(""),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} - var replyList []interface{} + var replyList []Reply replyList = append(replyList, Reply{0,0,"",template.HTML(""),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) - var varList map[string]VarItem = make(map[string]VarItem) - varList["extra_data"] = VarItem{"extra_data","tmpl_topic_vars.Something.(TopicUser)","TopicUser"} - pi := Page{"Title","name",user,noticeList,replyList,topic} - topic_id_tmpl := c.compile_template("topic.html","templates/","Page", pi, varList) + var varList map[string]VarItem = make(map[string]VarItem) + tpage := TopicPage{"Title","name",user,noticeList,replyList,topic,false} + topic_id_tmpl := c.compile_template("topic.html","templates/","TopicPage", tpage, varList) varList = make(map[string]VarItem) varList["extra_data"] = VarItem{"extra_data","tmpl_profile_vars.Something.(User)","User"} - pi = Page{"Title","name",user,noticeList,replyList,user} - profile_tmpl := c.compile_template("profile.html","templates/","Page", pi, varList) + //pi := Page{"Title","name",user,noticeList,replyList,user} + //profile_tmpl := c.compile_template("profile.html","templates/","Page", pi, varList) var forumList []interface{} for _, forum := range forums { @@ -63,7 +65,7 @@ func compile_templates() { } } varList = make(map[string]VarItem) - pi = Page{"Forum List","forums",user,noticeList,forumList,0} + pi := Page{"Forum List","forums",user,noticeList,forumList,0} forums_tmpl := c.compile_template("forums.html","templates/","Page", pi, varList) var topicList []interface{} @@ -76,7 +78,7 @@ func compile_templates() { log.Print("Writing the templates") write_template("topic", topic_id_tmpl) - write_template("profile", profile_tmpl) + //write_template("profile", profile_tmpl) write_template("forums", forums_tmpl) write_template("topics", topics_tmpl) write_template("forum", forum_tmpl) @@ -203,6 +205,7 @@ func main(){ http.HandleFunc("/panel/plugins/activate/", route_panel_plugins_activate) 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("/", default_route) diff --git a/mod_routes.go b/mod_routes.go index 23d5cf1b..adabbacb 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -24,15 +24,10 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) { if is_js == "" { is_js = "0" } - - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.EditTopic { NoPermissionsJSQ(w,r,user,is_js) return } - if user.Is_Banned { - BannedJSQ(w,r,user,is_js) - return - } var tid int tid, err = strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):]) @@ -70,8 +65,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.DeleteTopic { NoPermissions(w,r,user) return } @@ -106,8 +100,7 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.PinTopic { NoPermissions(w,r,user) return } @@ -123,7 +116,6 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) { InternalError(err,w,r,user) return } - http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) } @@ -132,8 +124,7 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.PinTopic { NoPermissions(w,r,user) return } @@ -149,7 +140,6 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) { InternalError(err,w,r,user) return } - http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) } @@ -169,8 +159,7 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) { if is_js == "" { is_js = "0" } - - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.EditReply { NoPermissionsJSQ(w,r,user,is_js) return } @@ -214,13 +203,12 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) { LocalError("Bad Form", w, r, user) return } - is_js := r.PostFormValue("is_js") if is_js == "" { is_js = "0" } - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ViewTopic || !user.Perms.DeleteReply { NoPermissionsJSQ(w,r,user,is_js) return } @@ -266,7 +254,6 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { LocalError("Bad Form", w, r, user) return } - is_js := r.PostFormValue("js") if is_js == "" { is_js = "0" @@ -286,7 +273,7 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { return } - if user.ID != uid && !user.Is_Mod && !user.Is_Admin { + if user.ID != uid && !user.Perms.EditReply { NoPermissionsJSQ(w,r,user,is_js) return } @@ -338,7 +325,7 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) { return } - if user.ID != uid && !user.Is_Mod && !user.Is_Admin { + if user.ID != uid && !user.Perms.DeleteReply { NoPermissionsJSQ(w,r,user,is_js) return } @@ -363,7 +350,7 @@ func route_ban(w http.ResponseWriter, r *http.Request) { return } - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.BanUsers { NoPermissions(w,r,user) return } @@ -397,7 +384,7 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request) { return } - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.BanUsers { NoPermissions(w,r,user) return } @@ -454,7 +441,7 @@ func route_unban(w http.ResponseWriter, r *http.Request) { if !ok { return } - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.BanUsers { NoPermissions(w,r,user) return } @@ -494,7 +481,7 @@ func route_activate(w http.ResponseWriter, r *http.Request) { if !ok { return } - if !user.Is_Mod && !user.Is_Admin { + if !user.Perms.ActivateUsers { NoPermissions(w,r,user) return } @@ -526,6 +513,12 @@ func route_activate(w http.ResponseWriter, r *http.Request) { InternalError(err,w,r,user) return } + + _, err = change_group_stmt.Exec(default_group, uid) + if err != nil { + InternalError(err,w,r,user) + return + } http.Redirect(w,r,"/users/" + strconv.Itoa(uid),http.StatusSeeOther) } @@ -534,8 +527,7 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManageForums { NoPermissions(w,r,user) return } @@ -556,8 +548,7 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManageForums { NoPermissions(w,r,user) return } @@ -594,11 +585,11 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManageForums { NoPermissions(w,r,user) return } + if r.FormValue("session") != user.Session { SecurityError(w,r,user) return @@ -627,11 +618,11 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManageForums { NoPermissions(w,r,user) return } + if r.FormValue("session") != user.Session { SecurityError(w,r,user) return @@ -665,8 +656,7 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManageForums { NoPermissions(w,r,user) return } @@ -711,15 +701,51 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.EditSettings { NoPermissions(w,r,user) return } var settingList map[string]interface{} = make(map[string]interface{}) - for name, content := range settings { - settingList[name] = content + rows, err := db.Query("SELECT name, content, type FROM settings") + if err != nil { + InternalError(err,w,r,user) + return + } + defer rows.Close() + + var sname string + var scontent string + var stype string + for rows.Next() { + err := rows.Scan(&sname, &scontent, &stype) + if err != nil { + InternalError(err,w,r,user) + return + } + + if stype == "list" { + llist := settingLabels[sname] + labels := strings.Split(llist,",") + conv, err := strconv.Atoi(scontent) + if err != nil { + LocalError("The setting '" + sname + "' can't be converted to an integer",w,r,user) + return + } + scontent = labels[conv - 1] + } else if stype == "bool" { + if scontent == "1" { + scontent = "Yes" + } else { + scontent = "No" + } + } + settingList[sname] = scontent + } + err = rows.Err() + if err != nil { + InternalError(err,w,r,user) + return } pi := Page{"Setting Manager","panel-settings",user, noticeList,tList,settingList} @@ -731,13 +757,12 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.EditSettings { NoPermissions(w,r,user) return } - setting := Setting{"","",""} + setting := Setting{"","","",""} setting.Name = r.URL.Path[len("/panel/settings/edit/"):] err := db.QueryRow("SELECT content, type from settings where name = ?", setting.Name).Scan(&setting.Content, &setting.Type) @@ -749,7 +774,31 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request){ return } - pi := Page{"Edit Setting","panel-setting",user,noticeList,tList,setting} + var itemList []interface{} + if setting.Type == "list" { + llist, ok := settingLabels[setting.Name] + if !ok { + LocalError("The labels for this setting don't exist",w,r,user) + return + } + + conv, err := strconv.Atoi(setting.Content) + if err != nil { + LocalError("The value of this setting couldn't be converted to an integer",w,r,user) + return + } + + labels := strings.Split(llist,",") + for index, label := range labels { + itemList = append(itemList, SettingLabel{ + Label: label, + Value: index + 1, + Selected: conv == (index + 1), + }) + } + } + + pi := Page{"Edit Setting","panel-setting",user,noticeList,itemList,setting} templates.ExecuteTemplate(w,"panel-setting.html", pi) } @@ -758,8 +807,7 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Is_Admin { + if !user.Perms.EditSettings { NoPermissions(w,r,user) return } @@ -775,10 +823,11 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) { } var stype string + var sconstraints string sname := r.URL.Path[len("/panel/settings/edit/submit/"):] scontent := r.PostFormValue("setting-value") - err = db.QueryRow("SELECT name, type from settings where name = ?", sname).Scan(&sname, &stype) + err = db.QueryRow("SELECT name, type, constraints from settings where name = ?", sname).Scan(&sname, &stype, &sconstraints) if err == sql.ErrNoRows { LocalError("The setting you want to edit doesn't exist.",w,r,user) return @@ -801,7 +850,7 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) { return } - errmsg := parseSetting(sname, scontent, stype) + errmsg := parseSetting(sname, scontent, stype, sconstraints) if errmsg != "" { LocalError(errmsg,w,r,user) return @@ -814,7 +863,7 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request){ if !ok { return } - if !user.Is_Admin { + if !user.Perms.ManagePlugins { NoPermissions(w,r,user) return } @@ -833,8 +882,7 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManagePlugins { NoPermissions(w,r,user) return } @@ -892,8 +940,7 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Perms.ManagePlugins { NoPermissions(w,r,user) return } @@ -937,8 +984,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if !user.Is_Admin { + if !user.Is_Super_Mod { NoPermissions(w,r,user) return } @@ -952,7 +998,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ defer rows.Close() for rows.Next() { - puser := User{0,"",0,false,false,false,false,false,false,"",false,"","","","",""} + puser := User{ID: 0,} err := rows.Scan(&puser.ID, &puser.Name, &puser.Group, &puser.Active, &puser.Is_Super_Admin, &puser.Avatar) if err != nil { InternalError(err,w,r,user) @@ -994,4 +1040,8 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){ if err != nil { InternalError(err, w, r, user) } -} \ No newline at end of file +} + +func route_panel_users_edit(w http.ResponseWriter, r *http.Request){ + +} diff --git a/mysql.go b/mysql.go index 2018a98d..f821537b 100644 --- a/mysql.go +++ b/mysql.go @@ -3,8 +3,9 @@ package main import "database/sql" import _ "github.com/go-sql-driver/mysql" -import "strconv" import "log" +import "fmt" +import "encoding/json" var db *sql.DB var get_session_stmt *sql.Stmt @@ -167,7 +168,7 @@ func init_database(err error) { // create_account_stmt, err = db.Prepare("INSERT INTO log.Print("Preparing register statement.") - register_stmt, err = db.Prepare("INSERT INTO users(`name`,`email`,`password`,`salt`,`group`,`is_super_admin`,`session`,`message`) VALUES(?,?,?,?," + strconv.Itoa(default_group) + ",0,?,'')") + register_stmt, err = db.Prepare("INSERT INTO users(`name`,`email`,`password`,`salt`,`group`,`is_super_admin`,`session`,`active`,`message`) VALUES(?,?,?,?,?,0,?,?,'')") if err != nil { log.Fatal(err) } @@ -252,11 +253,21 @@ func init_database(err error) { defer rows.Close() for rows.Next() { - group := Group{0,"","",false,false,false,""} - err := rows.Scan(&group.ID, &group.Name, &group.Permissions, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag) + group := Group{ID: 0,} + err := rows.Scan(&group.ID, &group.Name, &group.PermissionsText, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag) if err != nil { log.Fatal(err) } + + err = json.Unmarshal(group.PermissionsText, &group.Perms) + if err != nil { + log.Fatal(err) + } + + fmt.Println(group.Name + ": ") + fmt.Printf("%+v\n", group.Perms) + + group.Perms.ExtData = make(map[string]bool) groups[group.ID] = group } err = rows.Err() @@ -301,7 +312,7 @@ func init_database(err error) { forums[-1] = Forum{-1,"Reports",false,"",0,"",0,""} log.Print("Loading the settings.") - rows, err = db.Query("SELECT name, content, type FROM settings") + rows, err = db.Query("SELECT name, content, type, constraints FROM settings") if err != nil { log.Fatal(err) } @@ -310,12 +321,13 @@ func init_database(err error) { var sname string var scontent string var stype string + var sconstraints string for rows.Next() { - err := rows.Scan(&sname, &scontent, &stype) + err := rows.Scan(&sname, &scontent, &stype, &sconstraints) if err != nil { log.Fatal(err) } - errmsg := parseSetting(sname, scontent, stype) + errmsg := parseSetting(sname, scontent, stype, sconstraints) if errmsg != "" { log.Fatal(err) } diff --git a/old-images/settings.PNG b/old-images/settings.PNG new file mode 100644 index 00000000..3559947e Binary files /dev/null and b/old-images/settings.PNG differ diff --git a/pages.go b/pages.go index 892b5b9f..2baa6a83 100644 --- a/pages.go +++ b/pages.go @@ -12,15 +12,15 @@ type Page struct Something interface{} } -/* For testing maps versus slices */ -type Page2 struct +type TopicPage struct { Title string Name string CurrentUser User NoticeList map[int]string - ItemList map[int]interface{} - Something interface{} + ItemList []Reply + Topic TopicUser + ExtData interface{} } type PageSimple struct diff --git a/public/main.css b/public/main.css index 0b34c255..0dff9f92 100644 --- a/public/main.css +++ b/public/main.css @@ -297,6 +297,21 @@ button.username position: relative; top: -0.25px; } +.tag-mini +{ + text-transform: none; + margin-left: 0px; + padding-left: 3px; + padding-right: 3px; + padding-top: 1.5px; + padding-bottom: 0px; + color: #505050; /* 80,80,80 */ + background-color: #FFFFFF; + border-style: dotted; + border-color: #505050; /* 232,232,232. All three RGB colours being the same seems to create a shade of gray */ + border-width: 1px; + font-size: 10px; +} .show_on_edit { diff --git a/routes.go b/routes.go index 1648b2a2..0b34c298 100644 --- a/routes.go +++ b/routes.go @@ -1,7 +1,6 @@ /* Copyright Azareal 2016 - 2017 */ package main -import "errors" import "log" import "fmt" import "strconv" @@ -78,11 +77,14 @@ func route_topics(w http.ResponseWriter, r *http.Request){ if !ok { return } + // I'll have to find a solution which doesn't involve shutting down all of the routes for a user, if they don't have ANY permissions + /*if !user.Perms.ViewTopic { + NoPermissions(w,r,user) + return + }*/ var( topicList []interface{} - currentID int - tid int title string content string @@ -123,11 +125,11 @@ func route_topics(w http.ResponseWriter, r *http.Request){ avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1) } - topicList = append(topicList, TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,"","","",""}) - + topicItem := TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,"","","",""} if hooks["trow_assign"] != nil { - topicList[currentID] = run_hook("trow_assign", topicList[currentID]) + topicItem = run_hook("trow_assign", topicItem).(TopicUser) } + topicList = append(topicList, topicItem) } err = rows.Err() if err != nil { @@ -135,16 +137,9 @@ func route_topics(w http.ResponseWriter, r *http.Request){ return } - var msg string - if len(topicList) == 0 { - msg = "There aren't any topics yet." - } else { - msg = "" - } - - pi := Page{"Topic List","topics",user,noticeList,topicList,msg} - if ctemplates["topics"] != nil { - ctemplates["topics"](pi,w) + pi := Page{"Topic List","topics",user,noticeList,topicList,0} + if template_topics_handle != nil { + template_topics_handle(pi,w) } else { err = templates.ExecuteTemplate(w,"topics.html", pi) if err != nil { @@ -161,8 +156,6 @@ func route_forum(w http.ResponseWriter, r *http.Request){ var( topicList []interface{} - currentID int - tid int title string content string @@ -187,6 +180,10 @@ func route_forum(w http.ResponseWriter, r *http.Request){ NotFound(w,r,user) return } + if !user.Perms.ViewTopic { + NoPermissions(w,r,user) + 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) if err != nil { @@ -215,11 +212,11 @@ func route_forum(w http.ResponseWriter, r *http.Request){ avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1) } - topicList = append(topicList, TopicUser{tid,title,content,createdBy,is_closed,sticky,createdAt,parentID,status,name,avatar,"",0,"","","",""}) - + topicItem := TopicUser{tid,title,content,createdBy,is_closed,sticky,createdAt,parentID,status,name,avatar,"",0,"","","",""} if hooks["trow_assign"] != nil { - topicList[currentID] = run_hook("trow_assign", topicList[currentID]) + topicItem = run_hook("trow_assign", topicItem).(TopicUser) } + topicList = append(topicList, topicItem) } err = rows.Err() if err != nil { @@ -227,16 +224,9 @@ func route_forum(w http.ResponseWriter, r *http.Request){ return } - var msg string - if len(topicList) == 0 { - msg = "There aren't any topics in this forum yet." - } else { - msg = "" - } - - pi := Page{forums[fid].Name,"forum",user,noticeList,topicList,msg} - if ctemplates["forum"] != nil { - ctemplates["forum"](pi,w) + pi := Page{forums[fid].Name,"forum",user,noticeList,topicList,0} + if template_forum_handle != nil { + template_forum_handle(pi,w) } else { err = templates.ExecuteTemplate(w,"forum.html", pi) if err != nil { @@ -258,14 +248,9 @@ func route_forums(w http.ResponseWriter, r *http.Request){ } } - if len(forums) == 0 { - InternalError(errors.New("No forums"),w,r,user) - return - } - pi := Page{"Forum List","forums",user,noticeList,forumList,0} - if ctemplates["forums"] != nil { - ctemplates["forums"](pi,w) + if template_forums_handle != nil { + template_forums_handle(pi,w) } else { err := templates.ExecuteTemplate(w,"forums.html", pi) if err != nil { @@ -300,7 +285,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ is_super_admin bool group int - replyList []interface{} + replyList []Reply ) topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} @@ -309,6 +294,10 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ LocalError("The provided TopicID is not a valid number.",w,r,user) return } + if !user.Perms.ViewTopic { + NoPermissions(w,r,user) + return + } // 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 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) @@ -411,11 +400,11 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ return } - pi := Page{topic.Title,"topic",user,noticeList,replyList,topic} - if ctemplates["topic"] != nil { - ctemplates["topic"](pi,w) + tpage := TopicPage{topic.Title,"topic",user,noticeList,replyList,topic,0} + if template_topic_handle != nil { + template_topic_handle(tpage,w) } else { - err = templates.ExecuteTemplate(w,"topic.html", pi) + err = templates.ExecuteTemplate(w,"topic.html", tpage) if err != nil { InternalError(err, w, r, user) } @@ -447,7 +436,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){ replyList []interface{} ) - puser := User{0,"",0,false,false,false,false,false,false,"",false,"","","","",""} + puser := User{ID: 0,} puser.ID, err = strconv.Atoi(r.URL.Path[len("/user/"):]) if err != nil { LocalError("The provided TopicID is not a valid number.",w,r,user) @@ -536,8 +525,8 @@ func route_profile(w http.ResponseWriter, r *http.Request){ } pi := Page{puser.Name + "'s Profile","profile",user,noticeList,replyList,puser} - if ctemplates["profile"] != nil { - ctemplates["profile"](pi,w) + if template_profile_handle != nil { + template_profile_handle(pi,w) } else { err = templates.ExecuteTemplate(w,"profile.html", pi) if err != nil { @@ -551,9 +540,8 @@ func route_topic_create(w http.ResponseWriter, r *http.Request){ if !ok { return } - - if user.Is_Banned { - Banned(w,r,user) + if !user.Loggedin || !user.Perms.CreateTopic { + NoPermissions(w,r,user) return } @@ -567,13 +555,8 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Loggedin { - LoginRequired(w,r,user) - return - } - if user.Is_Banned { - Banned(w,r,user) + if !user.Loggedin || !user.Perms.CreateTopic { + NoPermissions(w,r,user) return } @@ -622,13 +605,8 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Loggedin { - LoginRequired(w,r,user) - return - } - if user.Is_Banned { - Banned(w,r,user) + if !user.Loggedin || !user.Perms.CreateReply { + NoPermissions(w,r,user) return } @@ -698,13 +676,8 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) { if !ok { return } - - if !user.Loggedin { - LoginRequired(w,r,user) - return - } - if user.Is_Banned { - Banned(w,r,user) + if !user.Loggedin || !user.Perms.CreateReply { + NoPermissions(w,r,user) return } @@ -1452,7 +1425,17 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) { return } - res, err := register_stmt.Exec(username,email,string(hashed_password),salt,session) + var active int + var group int + if settings["activation_type"] == 1 { + active = 1 + group = default_group + } else { + active = 0 + group = activation_group + } + + res, err := register_stmt.Exec(username,email,string(hashed_password),salt,group,session,active) if err != nil { InternalError(err,w,r,user) return diff --git a/setting.go b/setting.go index f8804346..63fa461b 100644 --- a/setting.go +++ b/setting.go @@ -1,14 +1,30 @@ package main import "strconv" +import "strings" + +var settingLabels map[string]string + +type SettingLabel struct +{ + Label string + Value int + Selected bool +} type Setting struct { Name string Content string Type string + Constraint string } -func parseSetting(sname string, scontent string, stype string) string { +func init() { + settingLabels = make(map[string]string) + settingLabels["activation_type"] = "Activate All,Email Activation,Admin Approval" +} + +func parseSetting(sname string, scontent string, stype string, constraint string) string { var err error if stype == "bool" { if scontent == "1" { @@ -26,6 +42,30 @@ func parseSetting(sname string, scontent string, stype string) string { if err != nil { return "You were supposed to enter an integer x.x\nType mismatch in " + sname } + } else if stype == "list" { + cons := strings.Split(constraint,"-") + if len(cons) < 2 { + return "Invalid constraint! The second field wasn't set!" + } + + con1, err := strconv.Atoi(cons[0]) + if err != nil { + return "Invalid contraint! The constraint field wasn't an integer!" + } + con2, err := strconv.Atoi(cons[1]) + if err != nil { + return "Invalid contraint! The constraint field wasn't an integer!" + } + + value, err := strconv.Atoi(scontent) + if err != nil { + return "Only integers are allowed in this setting x.x\nType mismatch in " + sname + } + + if value < con1 || value > con2 { + return "Only integers between a certain range are allowed in this setting" + } + settings[sname] = value } else { settings[sname] = scontent } diff --git a/template_forum.go b/template_forum.go index 82df2d08..88775921 100644 --- a/template_forum.go +++ b/template_forum.go @@ -1,9 +1,9 @@ package main -import "strconv" import "io" +import "strconv" func init() { -ctemplates["forum"] = template_forum +template_forum_handle = template_forum } func template_forum(tmpl_forum_vars Page, w io.Writer) { @@ -83,20 +83,14 @@ w.Write([]byte(`Status - `)) + + `)) } +} else { +w.Write([]byte(`
diff --git a/template_forums.go b/template_forums.go index 0d300fe8..2d33bce2 100644 --- a/template_forums.go +++ b/template_forums.go @@ -3,7 +3,7 @@ import "io" import "strconv" func init() { -ctemplates["forums"] = template_forums +template_forums_handle = template_forums } func template_forums(tmpl_forums_vars Page, w io.Writer) { @@ -66,8 +66,11 @@ for _, item := range tmpl_forums_vars.ItemList { w.Write([]byte(`
`)) + + `)) } +} else { +w.Write([]byte(`
`)) } w.Write([]byte(` diff --git a/template_profile.go b/template_profile.go deleted file mode 100644 index 85a48a3f..00000000 --- a/template_profile.go +++ /dev/null @@ -1,148 +0,0 @@ -package main -import "io" -import "strconv" - -func init() { -ctemplates["profile"] = template_profile -} - -func template_profile(tmpl_profile_vars Page, w io.Writer) { -var extra_data User = tmpl_profile_vars.Something.(User) -w.Write([]byte(` - -
-
- - - - - -
-