diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..580d0deb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +src/uploads/* +bin/* \ No newline at end of file diff --git a/README.md b/README.md index 291453aa..35f5632e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Set the password column of your user account in the database to what you want yo # Run the program -go run errors.go main.go pages.go reply.go routes.go topic.go user.go utils.go forum.go config.go +go run errors.go main.go pages.go reply.go routes.go topic.go user.go utils.go forum.go group.go config.go Alternatively, you could run the run.bat batch file on Windows. @@ -65,4 +65,4 @@ Tweak the CSS to make it responsive. Add a forum cache. -Add a group cache. +Cache the static files in memory. diff --git a/forum-list.PNG b/forum-list.PNG new file mode 100644 index 00000000..a2d703d5 Binary files /dev/null and b/forum-list.PNG differ diff --git a/ren.PNG b/old-images/ren.PNG similarity index 100% rename from ren.PNG rename to old-images/ren.PNG diff --git a/ren2.PNG b/old-images/ren2.PNG similarity index 100% rename from ren2.PNG rename to old-images/ren2.PNG diff --git a/ren6.PNG b/ren6.PNG new file mode 100644 index 00000000..f4967422 Binary files /dev/null and b/ren6.PNG differ diff --git a/src/config.go b/src/config.go index 93415042..aedda908 100644 --- a/src/config.go +++ b/src/config.go @@ -11,4 +11,5 @@ var dbport = "3306" // You probably won't need to change this var max_request_size = 5 * megabyte // Misc -var default_route = route_topics \ No newline at end of file +var default_route = route_topics +var staff_css = "background-color: #ffeaff;background-position: left;" \ No newline at end of file diff --git a/src/data.sql b/src/data.sql index 76a8f5c0..81d4ca3f 100644 --- a/src/data.sql +++ b/src/data.sql @@ -64,6 +64,7 @@ CREATE TABLE `replies`( INSERT INTO users(`name`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`) VALUES ('Admin',1,1,NOW(),NOW()); INSERT INTO users_groups(`name`,`permissions`,`is_admin`) VALUES ('Administrator','{}',1); +INSERT INTO users_groups(`name`,`permissions`) VALUES ('Member','{}'); INSERT INTO forums(`name`,`lastTopicTime`) VALUES ('General',NOW()); INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`createdBy`,`parentID`) VALUES ('Test Topic','A topic automatically generated by the software.',NOW(),NOW(),1,1); diff --git a/src/group.go b/src/group.go new file mode 100644 index 00000000..95a4a2c4 --- /dev/null +++ b/src/group.go @@ -0,0 +1,10 @@ +package main + +type Group struct +{ + ID int + Name string + Permissions string + Is_Admin bool + Is_Banned bool +} diff --git a/src/main.go b/src/main.go index 23aef4b7..4b7d52b1 100644 --- a/src/main.go +++ b/src/main.go @@ -17,6 +17,7 @@ const kilobyte int = 1024 const megabyte int = 1024 * 1024 const saltLength int = 32 const sessionLength int = 80 + var db *sql.DB var get_session_stmt *sql.Stmt var create_topic_stmt *sql.Stmt @@ -37,8 +38,12 @@ var set_avatar_stmt *sql.Stmt var set_username_stmt *sql.Stmt var register_stmt *sql.Stmt var username_exists_stmt *sql.Stmt + var custom_pages map[string]string = make(map[string]string) var templates = template.Must(template.ParseGlob("templates/*")) +var no_css_tmpl = template.CSS("") +var staff_css_tmpl = template.CSS(staff_css) +var groups map[int]Group = make(map[int]Group) func init_database(err error) { if(dbpassword != ""){ @@ -161,7 +166,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`,`password`,`salt`,`group`,`is_super_admin`,`session`) VALUES(?,?,?,0,0,?)") + register_stmt, err = db.Prepare("INSERT INTO users(`name`,`password`,`salt`,`group`,`is_super_admin`,`session`) VALUES(?,?,?,2,0,?)") if err != nil { log.Fatal(err) } @@ -171,6 +176,26 @@ func init_database(err error) { if err != nil { log.Fatal(err) } + + log.Print("Loading the usergroups.") + rows, err := db.Query("select gid,name,permissions,is_admin,is_banned from users_groups") + if err != nil { + log.Fatal(err) + } + defer rows.Close() + + for rows.Next() { + group := Group{0,"","",false,false} + err := rows.Scan(&group.ID, &group.Name, &group.Permissions, &group.Is_Admin, &group.Is_Banned) + if err != nil { + log.Fatal(err) + } + groups[group.ID] = group + } + err = rows.Err() + if err != nil { + log.Fatal(err) + } } func main(){ diff --git a/src/public/main.css b/src/public/main.css index bfd53d11..a8e7eaad 100644 --- a/src/public/main.css +++ b/src/public/main.css @@ -251,11 +251,17 @@ button padding-top: 2px; padding-bottom: 2px; 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: 15px; } +button.username +{ + position: relative; + top: -0.25px; +} .show_on_edit { diff --git a/src/public/white-dot.jpg b/src/public/white-dot.jpg new file mode 100644 index 00000000..70739f93 Binary files /dev/null and b/src/public/white-dot.jpg differ diff --git a/src/reply.go b/src/reply.go index 447c8639..3362e407 100644 --- a/src/reply.go +++ b/src/reply.go @@ -13,4 +13,5 @@ type Reply struct LastEdit int LastEditBy int Avatar string + Css template.CSS } diff --git a/src/routes.go b/src/routes.go index 8303f69c..6dba20c5 100644 --- a/src/routes.go +++ b/src/routes.go @@ -92,7 +92,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){ avatar = "/uploads/avatar_" + strconv.Itoa(createdBy) + avatar } - topicList[currentID] = TopicUser{tid, title, content, createdBy, is_closed, sticky, createdAt,parentID, status, name, avatar} + topicList[currentID] = TopicUser{tid, title, content, createdBy, is_closed, sticky, createdAt,parentID, status, name, avatar, ""} currentID++ } err = rows.Err() @@ -173,7 +173,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){ avatar = "/uploads/avatar_" + strconv.Itoa(createdBy) + avatar } - topicList[currentID] = TopicUser{tid, title, content, createdBy, is_closed, sticky, createdAt,parentID, status, name, avatar} + topicList[currentID] = TopicUser{tid, title, content, createdBy, is_closed, sticky, createdAt,parentID, status, name, avatar, ""} currentID++ } err = rows.Err() @@ -243,13 +243,16 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ replyLastEdit int replyLastEditBy int replyAvatar string + replyCss template.CSS + is_super_admin bool + group int currentID int replyList map[int]interface{} ) replyList = make(map[int]interface{}) currentID = 0 - topic := TopicUser{0,"","",0,false,false,"",0,"","",""} + topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl} topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):]) if err != nil { @@ -259,7 +262,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ // Get the topic.. //err = db.QueryRow("select title, content, createdBy, status, is_closed from topics where tid = ?", tid).Scan(&title, &content, &createdBy, &status, &is_closed) - err = db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, users.name, users.avatar 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) + 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 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) if err == sql.ErrNoRows { errmsg := "The requested topic doesn't exist." pi := Page{"Error","error",user,tList,errmsg} @@ -275,7 +278,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ return } - topic.Content = template.HTML(content) + topic.Content = template.HTML(parse_message(content)) if topic.Is_Closed { topic.Status = "closed" } else { @@ -284,10 +287,13 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ if topic.Avatar != "" && topic.Avatar[0] == '.' { topic.Avatar = "/uploads/avatar_" + strconv.Itoa(topic.CreatedBy) + topic.Avatar } + if is_super_admin || groups[group].Is_Admin { + topic.Css = staff_css_tmpl + } // Get the replies.. //rows, err := db.Query("select rid, content, createdBy, createdAt from replies where tid = ?", tid) - rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name from replies left join users ON replies.createdBy = users.uid where tid = ?", topic.ID) + 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 from replies left join users ON replies.createdBy = users.uid where tid = ?", topic.ID) if err != nil { InternalError(err,w,r,user) return @@ -295,17 +301,22 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ defer rows.Close() for rows.Next() { - err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName) + err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group) if err != nil { InternalError(err,w,r,user) return } + if is_super_admin || groups[group].Is_Admin { + replyCss = staff_css_tmpl + } else { + replyCss = no_css_tmpl + } if replyAvatar != "" && replyAvatar[0] == '.' { - replyAvatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + replyAvatar + replyAvatar = "/uploads/avatar_" + strconv.Itoa(replyCreatedBy) + replyAvatar } - replyList[currentID] = Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar} + replyList[currentID] = Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss} currentID++ } err = rows.Err() diff --git a/src/run.bat b/src/run.bat index 667b228c..0d459ee8 100644 --- a/src/run.bat +++ b/src/run.bat @@ -1,2 +1,2 @@ -go run errors.go main.go pages.go reply.go routes.go topic.go user.go utils.go config.go forum.go +go run errors.go main.go pages.go reply.go routes.go topic.go user.go utils.go config.go forum.go group.go pause \ No newline at end of file diff --git a/src/templates/forums.html b/src/templates/forums.html index 695fbfaf..1383e463 100644 --- a/src/templates/forums.html +++ b/src/templates/forums.html @@ -1,7 +1,7 @@ {{template "header.html" . }}
{{range .ItemList}}
- {{.Name}} + {{.Name}} {{.LastTopic}} {{.LastTopicTime}}
{{end}}
diff --git a/src/templates/topic.html b/src/templates/topic.html index e5f6f4b5..054dc381 100644 --- a/src/templates/topic.html +++ b/src/templates/topic.html @@ -4,6 +4,7 @@
{{.Something.Title}} {{.Something.Status}} + {{if .CurrentUser.Is_Admin}} Edit Delete {{ if .Something.Sticky }}Unpin{{else}}Pin{{end}} @@ -14,11 +15,12 @@ + {{end}}
-
+
{{.Something.Content}}

@@ -27,12 +29,12 @@

{{range $index, $element := .ItemList}} -
+
{{$element.ContentHtml}}

- {{$element.CreatedByName}} - - + {{$element.CreatedByName}} + {{if $.CurrentUser.Is_Admin}} + {{end}}
{{ end }}
diff --git a/src/topic.go b/src/topic.go index a88974dc..cc8a5bba 100644 --- a/src/topic.go +++ b/src/topic.go @@ -1,4 +1,5 @@ package main +import "html/template" type Topic struct { @@ -27,4 +28,5 @@ type TopicUser struct CreatedByName string Avatar string + Css template.CSS } diff --git a/staff-posts.PNG b/staff-posts.PNG new file mode 100644 index 00000000..b2fd8f2a Binary files /dev/null and b/staff-posts.PNG differ