From 534ef10194b14b31c272f705759d332d00f385c4 Mon Sep 17 00:00:00 2001 From: Azareal Date: Fri, 10 Feb 2017 13:39:13 +0000 Subject: [PATCH] You can now upvote topics and replies. The number of upvotes is visible on the posts. The static resources now support Gzip Compression. Software-wide support is coming with the upcoming router rewrite! Revamped Tempra Simple's topic view. We now use emojis instead of text for the fields. Experimental. Simplified the json permissions in the installer. Fixed some places where the wrong error handler is used. Fixed a bug in the word counter where it was off by one. The word count is now tracked by the topics and replies. --- data.sql | 17 +- files.go | 16 +- main.go | 16 +- mod_routes.go | 40 ++--- mysql.go | 31 +++- permissions.go | 6 + reply.go | 3 + routes.go | 167 ++++++++++++++++++-- template_forum.go | 2 +- template_forums.go | 2 +- template_list.go | 223 ++++++++++++++------------- template_profile.go | 2 +- template_topic.go | 165 ++++++++++++-------- template_topic_alt.go | 124 +++++++-------- templates/topic.html | 32 ++-- templates/topic_alt.html | 2 +- themes.go | 2 +- themes/tempra-simple/public/main.css | 38 ++--- topic.go | 3 + user.go | 17 ++ utils.go | 5 +- 21 files changed, 588 insertions(+), 325 deletions(-) diff --git a/data.sql b/data.sql index 2eb810ad..e2e1d6ec 100644 --- a/data.sql +++ b/data.sql @@ -77,6 +77,8 @@ CREATE TABLE `topics`( `parentID` int DEFAULT 2 not null, `ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null, `postCount` int DEFAULT 1 not null, + `likeCount` int DEFAULT 0 not null, + `words` int DEFAULT 0 not null, `data` varchar(200) DEFAULT '' not null, primary key(`tid`) ) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; @@ -91,6 +93,8 @@ CREATE TABLE `replies`( `lastEdit` int not null, `lastEditBy` int not null, `ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null, + `likeCount` int DEFAULT 0 not null, + `words` int DEFAULT 1 not null, primary key(`rid`) ) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; @@ -108,8 +112,8 @@ CREATE TABLE `users_replies`( CREATE TABLE `likes`( `weight` tinyint DEFAULT 1 not null, - `type` tinyint not null, /* Regular Post = 1, Big Post = 2, Mega Post = 3, etc.*/ `targetItem` int not null, + `targetType` varchar(50) DEFAULT 'replies' not null, `sentBy` int not null, `recalc` tinyint DEFAULT 0 not null ); @@ -162,6 +166,7 @@ ManagePlugins ViewIPs ViewTopic +LikeItem CreateTopic EditTopic DeleteTopic @@ -172,11 +177,11 @@ PinTopic CloseTopic */ -INSERT INTO users_groups(`name`,`permissions`,`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,"ManageThemes":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,"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,"ManageThemes":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,"ManageThemes":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,"ManageThemes":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`) VALUES ('Awaiting Activation','{"BanUsers":false,"ActivateUsers":false,"EditUser":false,"EditUserEmail":false,"EditUserPassword":false,"EditUserGroup":false,"EditUserGroupSuperMod":false,"EditUserGroupAdmin":false,"ManageForums":false,"EditSettings":false,"ManageThemes":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`,`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,"ManageThemes":true,"ManagePlugins":true,"ViewIPs":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}',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,"ManageThemes":false,"ManagePlugins":false,"ViewIPs":true,"ViewTopic":true,"LikeItem":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','{"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}'); +INSERT INTO users_groups(`name`,`permissions`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}',1); +INSERT INTO users_groups(`name`,`permissions`) VALUES ('Awaiting Activation','{"ViewTopic":true}'); INSERT INTO users_groups(`name`,`permissions`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','Guest'); INSERT INTO forums(`name`,`active`) VALUES ('Reports',0); diff --git a/files.go b/files.go index d8bb61cf..38ac39fd 100644 --- a/files.go +++ b/files.go @@ -1,5 +1,7 @@ package main + import "log" +import "bytes" import "strings" import "mime" import "errors" @@ -8,10 +10,12 @@ import "io" import "io/ioutil" import "path/filepath" import "net/http" +import "compress/gzip" type SFile struct { Data []byte + GzipData []byte Pos int64 Length int64 Mimetype string @@ -74,6 +78,14 @@ func add_static_file(path string, prefix string) error { path = strings.TrimPrefix(path, prefix) log.Print("Added the '" + path + "' static file") - static_files["/static" + path] = SFile{data,0,int64(len(data)),mime.TypeByExtension(filepath.Ext(prefix + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} + static_files["/static" + path] = SFile{data,compress_bytes_gzip(data),0,int64(len(data)),mime.TypeByExtension(filepath.Ext(prefix + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} return nil -} \ No newline at end of file +} + +func compress_bytes_gzip(in []byte) []byte { + var buff bytes.Buffer + gz := gzip.NewWriter(&buff) + gz.Write(in) + gz.Close() + return buff.Bytes() +} diff --git a/main.go b/main.go index 5e011c0a..87073ecf 100644 --- a/main.go +++ b/main.go @@ -51,9 +51,9 @@ func compile_templates() { log.Print("Compiling the templates") - topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"Date","Date",0,"","127.0.0.1",0,"","",no_css_tmpl,0,"","","","",58} + topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"","",no_css_tmpl,0,"","","","",58,false} var replyList []Reply - replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1"}) + replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1}) var varList map[string]VarItem = make(map[string]VarItem) tpage := TopicPage{"Title",user,noticeList,replyList,topic,1,1,false} @@ -67,7 +67,7 @@ func compile_templates() { var forumList []Forum for _, forum := range forums { if forum.Active { - forumList = append(forumList, forum) + forumList = append(forumList,forum) } } varList = make(map[string]VarItem) @@ -75,12 +75,12 @@ func compile_templates() { forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage", forums_page, varList) var topicsList []TopicsRow - topicsList = append(topicsList, TopicsRow{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,"Admin","","",0,"","","","",58,"General"}) + topicsList = append(topicsList,TopicsRow{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"Admin","","",0,"","","","",58,"General"}) topics_page := TopicsPage{"Topic List",user,noticeList,topicsList,""} topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList) var topicList []TopicUser - topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,"Admin","","",0,"","","","",58}) + topicList = append(topicList,TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"Admin","","",0,"","","","",58,false}) forum_item := Forum{1,"General Forum",true,"all",0,"",0,"",0,""} forum_page := ForumPage{"General Forum",user,noticeList,topicList,forum_item,1,1,nil} forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList) @@ -92,7 +92,7 @@ func compile_templates() { 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) + go write_file("./template_list.go","package main\n\n" + c.FragOut) } func write_template(name string, content string) { @@ -157,7 +157,7 @@ func main(){ path = strings.TrimPrefix(path,"public/") log.Print("Added the '" + path + "' static file.") - static_files["/static/" + path] = SFile{data,0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/public/" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} + static_files["/static/" + path] = SFile{data,compress_bytes_gzip(data),0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/public/" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} return nil }) if err != nil { @@ -188,11 +188,13 @@ func main(){ //router.HandleFunc("/reply/delete/", route_reply_delete) router.HandleFunc("/reply/edit/submit/", route_reply_edit_submit) router.HandleFunc("/reply/delete/submit/", route_reply_delete_submit) + router.HandleFunc("/reply/like/submit/", route_reply_like_submit) router.HandleFunc("/report/submit/", route_report_submit) router.HandleFunc("/topic/edit/submit/", route_edit_topic) router.HandleFunc("/topic/delete/submit/", route_delete_topic) router.HandleFunc("/topic/stick/submit/", route_stick_topic) router.HandleFunc("/topic/unstick/submit/", route_unstick_topic) + router.HandleFunc("/topic/like/submit/", route_like_topic) // Custom Pages router.HandleFunc("/pages/", route_custom_page) diff --git a/mod_routes.go b/mod_routes.go index 4639379b..d6feb1f4 100644 --- a/mod_routes.go +++ b/mod_routes.go @@ -30,10 +30,10 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) { err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid) if err == sql.ErrNoRows { - PreError("The topic you tried to edit doesn't exist.",w,r) + PreErrorJSQ("The topic you tried to edit doesn't exist.",w,r,is_js) return } else if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -197,14 +197,14 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) { rid, err := strconv.Atoi(r.URL.Path[len("/reply/edit/submit/"):]) if err != nil { - PreError("The provided Reply ID is not a valid number.",w,r) + PreErrorJSQ("The provided Reply ID is not a valid number.",w,r,is_js) return } content := html.EscapeString(preparse_message(r.PostFormValue("edit_item"))) _, err = edit_reply_stmt.Exec(content, parse_message(content), rid) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -212,17 +212,17 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) { var tid int err = db.QueryRow("select tid from replies where rid = ?", rid).Scan(&tid) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } var fid int err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid) if err == sql.ErrNoRows { - PreError("The parent topic doesn't exist.",w,r) + PreErrorJSQ("The parent topic doesn't exist.",w,r,is_js) return } else if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -231,7 +231,7 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) { return } if !user.Perms.ViewTopic || !user.Perms.EditReply { - NoPermissions(w,r,user) + NoPermissionsJSQ(w,r,user,is_js) return } @@ -274,10 +274,10 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) { var fid int err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid) if err == sql.ErrNoRows { - PreError("The parent topic doesn't exist.",w,r) + PreErrorJSQ("The parent topic doesn't exist.",w,r,is_js) return } else if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -286,7 +286,7 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) { return } if !user.Perms.ViewTopic || !user.Perms.DeleteReply { - NoPermissions(w,r,user) + NoPermissionsJSQ(w,r,user,is_js) return } @@ -305,12 +305,12 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) { wcount := word_count(content) err = decrease_post_user_stats(wcount, createdBy, false, user) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } _, err = remove_replies_from_topic_stmt.Exec(1,tid) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) } } @@ -332,7 +332,7 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { rid, err := strconv.Atoi(r.URL.Path[len("/profile/reply/edit/submit/"):]) if err != nil { - LocalError("The provided Reply ID is not a valid number.",w,r,user) + LocalErrorJSQ("The provided Reply ID is not a valid number.",w,r,user,is_js) return } @@ -340,7 +340,7 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { var uid int err = db.QueryRow("select uid from users_replies where rid = ?", rid).Scan(&uid) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -352,7 +352,7 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { content := html.EscapeString(preparse_message(r.PostFormValue("edit_item"))) _, err = edit_profile_reply_stmt.Exec(content, parse_message(content), rid) if err != nil { - InternalError(err,w,r) + InternalErrorJSQ(err,w,r,is_js) return } @@ -1374,11 +1374,11 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){ var themeList []interface{} for _, theme := range themes { - themeList = append(themeList, theme) + themeList = append(themeList,theme) } pi := Page{"Theme Manager",user,noticeList,themeList,nil} - err := templates.ExecuteTemplate(w,"panel-themes.html", pi) + err := templates.ExecuteTemplate(w,"panel-themes.html",pi) if err != nil { log.Print(err) } @@ -1422,7 +1422,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request){ LocalError("The theme is already active",w,r,user) return } - _, err = update_theme_stmt.Exec(1, uname) + _, err = update_theme_stmt.Exec(1,uname) if err != nil { InternalError(err,w,r) return @@ -1435,7 +1435,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request){ } } - _, err = update_theme_stmt.Exec(0, defaultTheme) + _, err = update_theme_stmt.Exec(0,defaultTheme) if err != nil { InternalError(err,w,r) return diff --git a/mysql.go b/mysql.go index 373c70b9..6133085f 100644 --- a/mysql.go +++ b/mysql.go @@ -24,6 +24,9 @@ var remove_replies_from_topic_stmt *sql.Stmt var add_topics_to_forum_stmt *sql.Stmt var remove_topics_from_forum_stmt *sql.Stmt var update_forum_cache_stmt *sql.Stmt +var create_like_stmt *sql.Stmt +var add_likes_to_topic_stmt *sql.Stmt +var add_likes_to_reply_stmt *sql.Stmt var edit_topic_stmt *sql.Stmt var edit_reply_stmt *sql.Stmt var delete_reply_stmt *sql.Stmt @@ -100,7 +103,7 @@ func init_database(err error) { } 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, topics.ipaddress, topics.postCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?") + get_topic_user_stmt, err = db.Prepare("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?") if err != nil { log.Fatal(err) } @@ -112,7 +115,7 @@ func init_database(err error) { } log.Print("Preparing get_topic_replies_offset statement.") - get_topic_replies_offset_stmt, err = db.Prepare("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress from replies left join users on replies.createdBy = users.uid where tid = ? limit ?, " + strconv.Itoa(items_per_page)) + get_topic_replies_offset_stmt, err = db.Prepare("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount from replies left join users on replies.createdBy = users.uid where tid = ? limit ?, " + strconv.Itoa(items_per_page)) if err != nil { log.Fatal(err) } @@ -124,13 +127,13 @@ func init_database(err error) { } log.Print("Preparing get_forum_topics_offset statement.") - get_forum_topics_offset_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, 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 limit ?, " + strconv.Itoa(items_per_page)) + get_forum_topics_offset_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.likeCount, 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 limit ?, " + strconv.Itoa(items_per_page)) if err != nil { log.Fatal(err) } log.Print("Preparing create_topic statement.") - create_topic_stmt, err = db.Prepare("insert into topics(parentID,title,content,parsed_content,createdAt,lastReplyAt,ipaddress,createdBy) VALUES(?,?,?,?,NOW(),NOW(),?,?)") + create_topic_stmt, err = db.Prepare("insert into topics(parentID,title,content,parsed_content,createdAt,lastReplyAt,ipaddress,words,createdBy) VALUES(?,?,?,?,NOW(),NOW(),?,?,?)") if err != nil { log.Fatal(err) } @@ -142,7 +145,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,ipaddress,createdBy) VALUES(?,?,?,NOW(),?,?)") + create_reply_stmt, err = db.Prepare("INSERT INTO replies(tid,content,parsed_content,createdAt,ipaddress,words,createdBy) VALUES(?,?,?,NOW(),?,?,?)") if err != nil { log.Fatal(err) } @@ -177,6 +180,24 @@ func init_database(err error) { log.Fatal(err) } + log.Print("Preparing create_like statement.") + create_like_stmt, err = db.Prepare("INSERT INTO likes(weight, targetItem, targetType, sentBy) VALUES(?,?,?,?)") + if err != nil { + log.Fatal(err) + } + + log.Print("Preparing add_likes_to_topic statement.") + add_likes_to_topic_stmt, err = db.Prepare("UPDATE topics SET likeCount = likeCount + ? WHERE tid = ?") + if err != nil { + log.Fatal(err) + } + + log.Print("Preparing add_likes_to_reply statement.") + add_likes_to_reply_stmt, err = db.Prepare("UPDATE replies SET likeCount = likeCount + ? WHERE rid = ?") + if err != nil { + log.Fatal(err) + } + log.Print("Preparing edit_topic statement.") edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?") if err != nil { diff --git a/permissions.go b/permissions.go index 5a74c681..6801772d 100644 --- a/permissions.go +++ b/permissions.go @@ -34,6 +34,7 @@ type Perms struct // Forum permissions ViewTopic bool + LikeItem bool CreateTopic bool EditTopic bool DeleteTopic bool @@ -53,6 +54,7 @@ type Perms struct type ForumPerms struct { ViewTopic bool + LikeItem bool CreateTopic bool EditTopic bool DeleteTopic bool @@ -99,6 +101,7 @@ func init() { ViewIPs: true, ViewTopic: true, + LikeItem: true, CreateTopic: true, EditTopic: true, DeleteTopic: true, @@ -113,6 +116,7 @@ func init() { AllForumPerms = ForumPerms{ ViewTopic: true, + LikeItem: true, CreateTopic: true, EditTopic: true, DeleteTopic: true, @@ -128,6 +132,7 @@ func init() { ReadWriteForumPerms = ForumPerms{ ViewTopic: true, + LikeItem: true, CreateTopic: true, CreateReply: true, Overrides: true, @@ -136,6 +141,7 @@ func init() { ReadReplyForumPerms = ForumPerms{ ViewTopic: true, + LikeItem: true, CreateReply: true, Overrides: true, ExtData: make(map[string]bool), diff --git a/reply.go b/reply.go index 0a1e8533..98a4a183 100644 --- a/reply.go +++ b/reply.go @@ -22,4 +22,7 @@ type Reply struct URLName string Level int IpAddress string + Liked bool + LikeCount int } + diff --git a/routes.go b/routes.go index e559054d..8403d28d 100644 --- a/routes.go +++ b/routes.go @@ -44,7 +44,12 @@ func route_static(w http.ResponseWriter, r *http.Request){ h.Set("Content-Length", strconv.FormatInt(file.Length, 10)) // Avoid doing a type conversion every time? //http.ServeContent(w,r,r.URL.Path,file.Info.ModTime(),file) //w.Write(file.Data) - io.Copy(w, bytes.NewReader(file.Data)) // Use w.Write instead? + if strings.Contains(r.Header.Get("Accept-Encoding"),"gzip") { + h.Set("Content-Encoding","gzip") + io.Copy(w, bytes.NewReader(file.GzipData)) // Use w.Write instead? + } else { + io.Copy(w, bytes.NewReader(file.Data)) + } //io.CopyN(w, bytes.NewReader(file.Data), static_files[r.URL.Path].Length) } @@ -101,7 +106,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){ } var topicList []TopicsRow - rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(fidList,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC") + rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(fidList,",")+") 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) @@ -110,7 +115,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){ topicItem := TopicsRow{ID: 0,} for rows.Next() { - err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.CreatedByName, &topicItem.Avatar) + err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.LikeCount, &topicItem.CreatedByName, &topicItem.Avatar) if err != nil { InternalError(err,w,r) return @@ -200,7 +205,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){ var topicList []TopicUser topicItem := TopicUser{ID: 0} for rows.Next() { - err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.CreatedByName, &topicItem.Avatar) + err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.LikeCount, &topicItem.CreatedByName, &topicItem.Avatar) if err != nil { InternalError(err,w,r) return @@ -299,7 +304,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ } // Get the topic.. - err = get_topic_user_stmt.QueryRow(topic.ID).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.CreatedByName, &topic.Avatar, &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.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.CreatedByName, &topic.Avatar, &group, &topic.URLPrefix, &topic.URLName, &topic.Level) if err == sql.ErrNoRows { NotFound(w,r) return @@ -377,7 +382,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ replyItem := Reply{Css: no_css_tmpl} for rows.Next() { - err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress) + err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress, &replyItem.LikeCount) if err != nil { InternalError(err,w,r) return @@ -402,7 +407,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ replyItem.Tag = groups[group].Tag - if settings["url_tags"] == false { + /*if settings["url_tags"] == false { replyItem.URLName = "" } else { replyItem.URL, ok = external_sites[replyItem.URLPrefix] @@ -411,7 +416,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){ } else { replyItem.URL = replyItem.URL + replyItem.URLName } - } + }*/ + + replyItem.Liked = false if hooks["rrow_assign"] != nil { replyItem = run_hook("rrow_assign", replyItem).(Reply) @@ -528,6 +535,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){ } else { replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1) } + if groups[group].Tag != "" { replyTag = groups[group].Tag } else if puser.ID == replyCreatedBy { @@ -536,7 +544,10 @@ 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,""}) + replyLiked := false + replyLikeCount := 0 + + replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0,"",replyLiked,replyLikeCount}) } err = rows.Err() if err != nil { @@ -626,7 +637,8 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) { return } - res, err := create_topic_stmt.Exec(fid,topic_name,content,parse_message(content),ipaddress,user.ID) + wcount := word_count(content) + res, err := create_topic_stmt.Exec(fid,topic_name,content,parse_message(content),ipaddress,wcount,user.ID) if err != nil { InternalError(err,w,r) return @@ -656,7 +668,6 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) { forums[fid].LastTopicTime = "" http.Redirect(w, r, "/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther) - wcount := word_count(content) err = increase_post_user_stats(wcount,user.ID,true,user) if err != nil { InternalError(err,w,r) @@ -672,7 +683,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { } tid, err := strconv.Atoi(r.PostFormValue("tid")) if err != nil { - PreError("Failed to convert the TopicID",w,r) + PreError("Failed to convert the Topic ID",w,r) return } @@ -703,7 +714,8 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { return } - _, err = create_reply_stmt.Exec(tid,content,parse_message(content),ipaddress,user.ID) + wcount := word_count(content) + _, err = create_reply_stmt.Exec(tid,content,parse_message(content),ipaddress,wcount, user.ID) if err != nil { InternalError(err,w,r) return @@ -721,7 +733,6 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { } http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) - wcount := word_count(content) err = increase_post_user_stats(wcount, user.ID, false, user) if err != nil { InternalError(err,w,r) @@ -729,6 +740,134 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) { } } +func route_like_topic(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + PreError("Bad Form",w,r) + return + } + + tid, err := strconv.Atoi(r.URL.Path[len("/topic/like/submit/"):]) + if err != nil { + PreError("Topic IDs can only ever be numbers.",w,r) + return + } + + var words int + var fid int + err = db.QueryRow("select parentID, words from topics where tid = ?", tid).Scan(&fid,&words) + if err == sql.ErrNoRows { + PreError("The requested topic doesn't exist.",w,r) + return + } else if err != nil { + InternalError(err,w,r) + return + } + + user, ok := SimpleForumSessionCheck(w,r,fid) + if !ok { + return + } + if !user.Perms.ViewTopic || !user.Perms.LikeItem { + NoPermissions(w,r,user) + return + } + + err = db.QueryRow("select targetItem from likes where sentBy = ? and targetItem = ? and targetType = 'topics'", user.ID, tid).Scan(&tid) + if err != nil && err != sql.ErrNoRows { + InternalError(err,w,r) + return + } else if err != sql.ErrNoRows { + LocalError("You already liked this!",w,r,user) + return + } + + //score := words_to_score(words,true) + score := 1 + _, err = create_like_stmt.Exec(score,tid,"topics",user.ID) + if err != nil { + InternalError(err,w,r) + return + } + + _, err = add_likes_to_topic_stmt.Exec(1,tid) + if err != nil { + InternalError(err,w,r) + return + } + + http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) +} + +func route_reply_like_submit(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + PreError("Bad Form",w,r) + return + } + + rid, err := strconv.Atoi(r.URL.Path[len("/reply/like/submit/"):]) + if err != nil { + PreError("The provided Reply ID is not a valid number.",w,r) + return + } + + var tid int + var words int + err = db.QueryRow("select tid, words from replies where rid = ?", rid).Scan(&tid, &words) + if err == sql.ErrNoRows { + PreError("You can't like something which doesn't exist!",w,r) + return + } else if err != nil { + InternalError(err,w,r) + return + } + + var fid int + err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid) + if err == sql.ErrNoRows { + PreError("The parent topic doesn't exist.",w,r) + return + } else if err != nil { + InternalError(err,w,r) + return + } + + user, ok := SimpleForumSessionCheck(w,r,fid) + if !ok { + return + } + if !user.Perms.ViewTopic || !user.Perms.LikeItem { + NoPermissions(w,r,user) + return + } + + err = db.QueryRow("select targetItem from likes where sentBy = ? and targetItem = ? and targetType = 'replies'", user.ID, rid).Scan(&rid) + if err != nil && err != sql.ErrNoRows { + InternalError(err,w,r) + return + } else if err != sql.ErrNoRows { + LocalError("You already liked this!",w,r,user) + return + } + + //score := words_to_score(words,false) + score := 1 + _, err = create_like_stmt.Exec(score,rid,"replies",user.ID) + if err != nil { + InternalError(err,w,r) + return + } + + _, err = add_likes_to_reply_stmt.Exec(1,rid) + if err != nil { + InternalError(err,w,r) + return + } + + http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) +} + func route_profile_reply_create(w http.ResponseWriter, r *http.Request) { user, ok := SimpleSessionCheck(w,r) if !ok { diff --git a/template_forum.go b/template_forum.go index 55a5e609..a9f00d89 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 "io" import "strconv" +import "io" func init() { template_forum_handle = template_forum diff --git a/template_forums.go b/template_forums.go index 4f0e2372..d912d703 100644 --- a/template_forums.go +++ b/template_forums.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 "io" import "strconv" +import "io" func init() { template_forums_handle = template_forums diff --git a/template_list.go b/template_list.go index 0001b432..b917b1f0 100644 --- a/template_list.go +++ b/template_list.go @@ -64,95 +64,111 @@ var topic_8 []byte = []byte(`
`) var topic_13 []byte = []byte(` `) var topic_14 []byte = []byte(`🔒︎`) var topic_15 []byte = []byte(` - Edit - Delete - `) -var topic_18 []byte = []byte(`Unpin`) -var topic_20 []byte = []byte(`Pin`) -var topic_22 []byte = []byte(` - +var topic_16 []byte = []byte(`' type="text" /> `) -var topic_24 []byte = []byte(` - Report +var topic_17 []byte = []byte(`
-

`) -var topic_32 []byte = []byte(`

+var topic_18 []byte = []byte(`background-image:url(`) +var topic_19 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px `) +var topic_20 []byte = []byte(`-1`) +var topic_21 []byte = []byte(`0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;`) +var topic_22 []byte = []byte(`"> +

`) +var topic_23 []byte = []byte(`



+var topic_24 []byte = []byte(`

`) -var topic_35 []byte = []byte(` - `) -var topic_37 []byte = []byte(`style="color: #505050;float: right;">Level `) -var topic_38 []byte = []byte(` +var topic_25 []byte = []byte(`" class="username real_username">`) +var topic_26 []byte = []byte(` + + `) +var topic_30 []byte = []byte(` + + `) +var topic_33 []byte = []byte(``) +var topic_35 []byte = []byte(``) +var topic_37 []byte = []byte(` + + `) +var topic_40 []byte = []byte(``) +var topic_41 []byte = []byte(`😀`) +var topic_42 []byte = []byte(``) +var topic_43 []byte = []byte(``) +var topic_44 []byte = []byte(``) +var topic_45 []byte = []byte(`👑`) +var topic_46 []byte = []byte(`

`) -var topic_39 []byte = []byte(` +var topic_47 []byte = []byte(`
+var topic_48 []byte = []byte(`background-image:url(`) +var topic_49 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px `) +var topic_50 []byte = []byte(`-1`) +var topic_51 []byte = []byte(`0px;background-repeat:no-repeat, repeat-y;background-size:128px;padding-left:136px;`) +var topic_52 []byte = []byte(`">

`) -var topic_45 []byte = []byte(`



+var topic_53 []byte = []byte(`



`) -var topic_47 []byte = []byte(` +var topic_54 []byte = []byte(`" class="username real_username">`) +var topic_55 []byte = []byte(` + `) -var topic_48 []byte = []byte(` `) -var topic_50 []byte = []byte(` `) -var topic_52 []byte = []byte(` +var topic_59 []byte = []byte(` `) +var topic_61 []byte = []byte(` `) +var topic_63 []byte = []byte(` - `) -var topic_56 []byte = []byte(`style="color: #505050;float: right;">Level `) -var topic_57 []byte = []byte(` +var topic_64 []byte = []byte(`?session=`) +var topic_65 []byte = []byte(`&type=reply" class="mod_button" title="Flag Reply"> + `) +var topic_66 []byte = []byte(``) +var topic_67 []byte = []byte(`😀`) +var topic_68 []byte = []byte(``) +var topic_69 []byte = []byte(``) +var topic_70 []byte = []byte(``) +var topic_71 []byte = []byte(`👑`) +var topic_72 []byte = []byte(`
`) -var topic_58 []byte = []byte(`
+var topic_73 []byte = []byte(` `) -var topic_59 []byte = []byte(` +var topic_74 []byte = []byte(`
+var topic_75 []byte = []byte(`' type="hidden" />
@@ -187,30 +203,31 @@ var topic_alt_12 []byte = []byte(`"> var topic_alt_13 []byte = []byte(` `) var topic_alt_14 []byte = []byte(`🔒︎`) -var topic_alt_15 []byte = []byte(` +var topic_alt_15 []byte = []byte(`🖤︎`) +var topic_alt_16 []byte = []byte(` Edit +var topic_alt_17 []byte = []byte(`' class="username hide_on_edit open_edit topic_button" style="font-weight: normal;margin-left: 6px;">Edit Delete +var topic_alt_18 []byte = []byte(`' class="username topic_button" style="font-weight: normal;">Delete `) -var topic_alt_18 []byte = []byte(`Unpin`) -var topic_alt_20 []byte = []byte(`Pin`) -var topic_alt_22 []byte = []byte(` +var topic_alt_19 []byte = []byte(`Unpin`) +var topic_alt_21 []byte = []byte(`Pin`) +var topic_alt_23 []byte = []byte(` +var topic_alt_24 []byte = []byte(`' type="text" /> `) -var topic_alt_24 []byte = []byte(` +var topic_alt_25 []byte = []byte(` Report +var topic_alt_26 []byte = []byte(`?session=`) +var topic_alt_27 []byte = []byte(`&type=topic" class="username report_item topic_button" style="font-weight: normal;">Report
@@ -219,75 +236,75 @@ var topic_alt_26 []byte = []byte(`&type=topic" class="username report_item topic
 
+var topic_alt_28 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> 
`) -var topic_alt_29 []byte = []byte(` +var topic_alt_29 []byte = []byte(`" class="the_name">`) +var topic_alt_30 []byte = []byte(` `) -var topic_alt_30 []byte = []byte(`
`) -var topic_alt_32 []byte = []byte(`
`) -var topic_alt_34 []byte = []byte(` +var topic_alt_31 []byte = []byte(`
`) +var topic_alt_33 []byte = []byte(`
`) +var topic_alt_35 []byte = []byte(`
`) -var topic_alt_35 []byte = []byte(`
+var topic_alt_36 []byte = []byte(`
+var topic_alt_37 []byte = []byte(`
`) -var topic_alt_37 []byte = []byte(``) -var topic_alt_38 []byte = []byte(``) -var topic_alt_39 []byte = []byte(` +var topic_alt_38 []byte = []byte(``) +var topic_alt_39 []byte = []byte(``) +var topic_alt_40 []byte = []byte(`
`) -var topic_alt_40 []byte = []byte(` +var topic_alt_41 []byte = []byte(`
 
+var topic_alt_42 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> 
`) -var topic_alt_43 []byte = []byte(` +var topic_alt_43 []byte = []byte(`" class="the_name">`) +var topic_alt_44 []byte = []byte(` `) -var topic_alt_44 []byte = []byte(`
`) -var topic_alt_46 []byte = []byte(`
`) -var topic_alt_48 []byte = []byte(` +var topic_alt_45 []byte = []byte(`
`) +var topic_alt_47 []byte = []byte(`
`) +var topic_alt_49 []byte = []byte(`
`) -var topic_alt_49 []byte = []byte(`
+var topic_alt_50 []byte = []byte(`
`) -var topic_alt_50 []byte = []byte(`Edit`) -var topic_alt_52 []byte = []byte(`Delete`) -var topic_alt_54 []byte = []byte(` +var topic_alt_51 []byte = []byte(`Edit`) +var topic_alt_53 []byte = []byte(`Delete`) +var topic_alt_55 []byte = []byte(` Report +var topic_alt_56 []byte = []byte(`?session=`) +var topic_alt_57 []byte = []byte(`&type=reply" class="action_button report_item">Report `) -var topic_alt_57 []byte = []byte(``) -var topic_alt_58 []byte = []byte(``) -var topic_alt_59 []byte = []byte(` +var topic_alt_58 []byte = []byte(``) +var topic_alt_59 []byte = []byte(``) +var topic_alt_60 []byte = []byte(`
`) -var topic_alt_60 []byte = []byte(` +var topic_alt_61 []byte = []byte(` `) -var topic_alt_61 []byte = []byte(` +var topic_alt_62 []byte = []byte(`
+var topic_alt_63 []byte = []byte(`' type="hidden" />
diff --git a/template_profile.go b/template_profile.go index e71179bf..609431b3 100644 --- a/template_profile.go +++ b/template_profile.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_profile_handle = template_profile diff --git a/template_topic.go b/template_topic.go index 4a9b9cf9..16824192 100644 --- a/template_topic.go +++ b/template_topic.go @@ -1,8 +1,8 @@ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ package main -import "io" import "strconv" import "html/template" +import "io" func init() { template_topic_handle = template_topic @@ -77,105 +77,134 @@ w.Write(topic_14) } if tmpl_topic_vars.CurrentUser.Is_Mod { w.Write(topic_15) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_16) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_17) -if tmpl_topic_vars.Topic.Sticky { -w.Write(topic_18) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_19) -} else { -w.Write(topic_20) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_21) -} -w.Write(topic_22) w.Write([]byte(tmpl_topic_vars.Topic.Title)) -w.Write(topic_23) +w.Write(topic_16) } -w.Write(topic_24) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) -w.Write(topic_25) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) -w.Write(topic_26) +w.Write(topic_17) if tmpl_topic_vars.Topic.Avatar != "" { -w.Write(topic_27) +w.Write(topic_18) w.Write([]byte(tmpl_topic_vars.Topic.Avatar)) -w.Write(topic_28) +w.Write(topic_19) if tmpl_topic_vars.Topic.ContentLines <= 5 { -w.Write(topic_29) +w.Write(topic_20) } -w.Write(topic_30) +w.Write(topic_21) w.Write([]byte(string(tmpl_topic_vars.Topic.Css))) } -w.Write(topic_31) +w.Write(topic_22) w.Write([]byte(string(tmpl_topic_vars.Topic.Content.(template.HTML)))) -w.Write(topic_32) +w.Write(topic_23) w.Write([]byte(string(tmpl_topic_vars.Topic.Content.(template.HTML)))) -w.Write(topic_33) +w.Write(topic_24) w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.CreatedBy))) -w.Write(topic_34) +w.Write(topic_25) w.Write([]byte(tmpl_topic_vars.Topic.CreatedByName)) -w.Write(topic_35) -if tmpl_topic_vars.Topic.Tag != "" { -w.Write(topic_36) -w.Write([]byte(tmpl_topic_vars.Topic.Tag)) -} else { -w.Write(topic_37) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level))) +w.Write(topic_26) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_27) +if tmpl_topic_vars.Topic.Liked { +w.Write(topic_28) } +w.Write(topic_29) +if tmpl_topic_vars.CurrentUser.Is_Mod { +w.Write(topic_30) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_31) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_32) +if tmpl_topic_vars.Topic.Sticky { +w.Write(topic_33) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_34) +} else { +w.Write(topic_35) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_36) +} +} +w.Write(topic_37) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) w.Write(topic_38) +w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) +w.Write(topic_39) +if tmpl_topic_vars.Topic.LikeCount > 0 { +w.Write(topic_40) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.LikeCount))) +w.Write(topic_41) +} +if tmpl_topic_vars.Topic.Tag != "" { +w.Write(topic_42) +w.Write([]byte(tmpl_topic_vars.Topic.Tag)) +w.Write(topic_43) +} else { +w.Write(topic_44) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.Level))) +w.Write(topic_45) +} +w.Write(topic_46) if len(tmpl_topic_vars.ItemList) != 0 { for _, item := range tmpl_topic_vars.ItemList { -w.Write(topic_39) +w.Write(topic_47) if item.Avatar != "" { -w.Write(topic_40) +w.Write(topic_48) w.Write([]byte(item.Avatar)) -w.Write(topic_41) +w.Write(topic_49) if item.ContentLines <= 5 { -w.Write(topic_42) +w.Write(topic_50) } -w.Write(topic_43) +w.Write(topic_51) w.Write([]byte(string(item.Css))) } -w.Write(topic_44) -w.Write([]byte(string(item.ContentHtml))) -w.Write(topic_45) -w.Write([]byte(strconv.Itoa(item.CreatedBy))) -w.Write(topic_46) -w.Write([]byte(item.CreatedByName)) -w.Write(topic_47) -if tmpl_topic_vars.CurrentUser.Perms.EditReply { -w.Write(topic_48) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_49) -} -if tmpl_topic_vars.CurrentUser.Perms.DeleteReply { -w.Write(topic_50) -w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_51) -} w.Write(topic_52) -w.Write([]byte(strconv.Itoa(item.ID))) +w.Write([]byte(string(item.ContentHtml))) w.Write(topic_53) -w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) +w.Write([]byte(strconv.Itoa(item.CreatedBy))) w.Write(topic_54) -if item.Tag != "" { +w.Write([]byte(item.CreatedByName)) w.Write(topic_55) -w.Write([]byte(item.Tag)) -} else { +w.Write([]byte(strconv.Itoa(item.ID))) w.Write(topic_56) -w.Write([]byte(strconv.Itoa(item.Level))) -} +if item.Liked { w.Write(topic_57) } -} w.Write(topic_58) -if tmpl_topic_vars.CurrentUser.Perms.CreateReply { +if tmpl_topic_vars.CurrentUser.Perms.EditReply { w.Write(topic_59) -w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write([]byte(strconv.Itoa(item.ID))) w.Write(topic_60) } +if tmpl_topic_vars.CurrentUser.Perms.DeleteReply { +w.Write(topic_61) +w.Write([]byte(strconv.Itoa(item.ID))) +w.Write(topic_62) +} +w.Write(topic_63) +w.Write([]byte(strconv.Itoa(item.ID))) +w.Write(topic_64) +w.Write([]byte(tmpl_topic_vars.CurrentUser.Session)) +w.Write(topic_65) +if item.LikeCount > 0 { +w.Write(topic_66) +w.Write([]byte(strconv.Itoa(item.LikeCount))) +w.Write(topic_67) +} +if item.Tag != "" { +w.Write(topic_68) +w.Write([]byte(item.Tag)) +w.Write(topic_69) +} else { +w.Write(topic_70) +w.Write([]byte(strconv.Itoa(item.Level))) +w.Write(topic_71) +} +w.Write(topic_72) +} +} +w.Write(topic_73) +if tmpl_topic_vars.CurrentUser.Perms.CreateReply { +w.Write(topic_74) +w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) +w.Write(topic_75) +} w.Write(footer_0) } diff --git a/template_topic_alt.go b/template_topic_alt.go index cb82e6fc..fbf6737f 100644 --- a/template_topic_alt.go +++ b/template_topic_alt.go @@ -1,8 +1,8 @@ /* 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 "html/template" import "io" import "strconv" +import "html/template" func init() { template_topic_alt_handle = template_topic_alt @@ -74,106 +74,108 @@ w.Write([]byte(tmpl_topic_alt_vars.Topic.Title)) w.Write(topic_alt_13) if tmpl_topic_alt_vars.Topic.Is_Closed { w.Write(topic_alt_14) +} else { +w.Write(topic_alt_15) } if tmpl_topic_alt_vars.CurrentUser.Is_Mod { -w.Write(topic_alt_15) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) w.Write(topic_alt_16) w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) w.Write(topic_alt_17) -if tmpl_topic_alt_vars.Topic.Sticky { +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) w.Write(topic_alt_18) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) +if tmpl_topic_alt_vars.Topic.Sticky { w.Write(topic_alt_19) -} else { +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) w.Write(topic_alt_20) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_21) -} -w.Write(topic_alt_22) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Title)) -w.Write(topic_alt_23) -} -w.Write(topic_alt_24) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) -w.Write(topic_alt_25) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(topic_alt_26) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar)) -w.Write(topic_alt_27) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.CreatedBy))) -w.Write(topic_alt_28) -w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName)) -w.Write(topic_alt_29) -if tmpl_topic_alt_vars.Topic.Tag != "" { -w.Write(topic_alt_30) -w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag)) -w.Write(topic_alt_31) } else { -w.Write(topic_alt_32) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level))) -w.Write(topic_alt_33) +w.Write(topic_alt_21) +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) +w.Write(topic_alt_22) } +w.Write(topic_alt_23) +w.Write([]byte(tmpl_topic_alt_vars.Topic.Title)) +w.Write(topic_alt_24) +} +w.Write(topic_alt_25) +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) +w.Write(topic_alt_26) +w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) +w.Write(topic_alt_27) +w.Write([]byte(tmpl_topic_alt_vars.Topic.Avatar)) +w.Write(topic_alt_28) +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.CreatedBy))) +w.Write(topic_alt_29) +w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedByName)) +w.Write(topic_alt_30) +if tmpl_topic_alt_vars.Topic.Tag != "" { +w.Write(topic_alt_31) +w.Write([]byte(tmpl_topic_alt_vars.Topic.Tag)) +w.Write(topic_alt_32) +} else { +w.Write(topic_alt_33) +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.Level))) w.Write(topic_alt_34) -w.Write([]byte(string(tmpl_topic_alt_vars.Topic.Content.(template.HTML)))) +} w.Write(topic_alt_35) w.Write([]byte(string(tmpl_topic_alt_vars.Topic.Content.(template.HTML)))) w.Write(topic_alt_36) -if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { +w.Write([]byte(string(tmpl_topic_alt_vars.Topic.Content.(template.HTML)))) w.Write(topic_alt_37) -w.Write([]byte(tmpl_topic_alt_vars.Topic.IpAddress)) +if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { w.Write(topic_alt_38) -} +w.Write([]byte(tmpl_topic_alt_vars.Topic.IpAddress)) w.Write(topic_alt_39) +} +w.Write(topic_alt_40) if len(tmpl_topic_alt_vars.ItemList) != 0 { for _, item := range tmpl_topic_alt_vars.ItemList { -w.Write(topic_alt_40) -w.Write([]byte(item.Avatar)) w.Write(topic_alt_41) -w.Write([]byte(strconv.Itoa(item.CreatedBy))) +w.Write([]byte(item.Avatar)) w.Write(topic_alt_42) -w.Write([]byte(item.CreatedByName)) +w.Write([]byte(strconv.Itoa(item.CreatedBy))) w.Write(topic_alt_43) -if item.Tag != "" { +w.Write([]byte(item.CreatedByName)) w.Write(topic_alt_44) -w.Write([]byte(item.Tag)) +if item.Tag != "" { w.Write(topic_alt_45) -} else { +w.Write([]byte(item.Tag)) w.Write(topic_alt_46) -w.Write([]byte(strconv.Itoa(item.Level))) +} else { w.Write(topic_alt_47) -} +w.Write([]byte(strconv.Itoa(item.Level))) w.Write(topic_alt_48) -w.Write([]byte(string(item.ContentHtml))) +} w.Write(topic_alt_49) -if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply { +w.Write([]byte(string(item.ContentHtml))) w.Write(topic_alt_50) -w.Write([]byte(strconv.Itoa(item.ID))) +if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply { w.Write(topic_alt_51) +w.Write([]byte(strconv.Itoa(item.ID))) +w.Write(topic_alt_52) } if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply { -w.Write(topic_alt_52) -w.Write([]byte(strconv.Itoa(item.ID))) w.Write(topic_alt_53) -} -w.Write(topic_alt_54) w.Write([]byte(strconv.Itoa(item.ID))) -w.Write(topic_alt_55) -w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) -w.Write(topic_alt_56) -if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { -w.Write(topic_alt_57) -w.Write([]byte(item.IpAddress)) -w.Write(topic_alt_58) +w.Write(topic_alt_54) } +w.Write(topic_alt_55) +w.Write([]byte(strconv.Itoa(item.ID))) +w.Write(topic_alt_56) +w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session)) +w.Write(topic_alt_57) +if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs { +w.Write(topic_alt_58) +w.Write([]byte(item.IpAddress)) w.Write(topic_alt_59) } -} w.Write(topic_alt_60) -if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply { +} +} w.Write(topic_alt_61) -w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) +if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply { w.Write(topic_alt_62) +w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) +w.Write(topic_alt_63) } w.Write(footer_0) } diff --git a/templates/topic.html b/templates/topic.html index c5e70ef4..506e9134 100644 --- a/templates/topic.html +++ b/templates/topic.html @@ -4,14 +4,10 @@ {{end}}
-
+
{{.Topic.Title}} {{if .Topic.Is_Closed}}🔒︎{{end}} {{if .CurrentUser.Is_Mod}} - Edit - Delete - {{if .Topic.Sticky}}Unpin{{else}}Pin{{end}} - {{end}} - Report
-
-

{{.Topic.Content}}

+
+

{{.Topic.Content}}



{{.Topic.CreatedByName}} - {{.Topic.Tag}}{{else}}style="color: #505050;float: right;">Level {{.Topic.Level}}{{end}} + + {{if .CurrentUser.Is_Mod}} + + {{if .Topic.Sticky}}{{else}}{{end}} + {{end}} + + {{if .Topic.LikeCount}}{{.Topic.LikeCount}}😀{{end}} + {{if .Topic.Tag}}{{.Topic.Tag}}{{else}}{{.Topic.Level}}👑{{end}}

{{range .ItemList}} -
+

{{.ContentHtml}}



{{.CreatedByName}} - {{if $.CurrentUser.Perms.EditReply}} {{end}} - {{if $.CurrentUser.Perms.DeleteReply}} {{end}} - - {{.Tag}}{{else}}style="color: #505050;float: right;">Level {{.Level}}{{end}} + + {{if $.CurrentUser.Perms.EditReply}} {{end}} + {{if $.CurrentUser.Perms.DeleteReply}} {{end}} + + {{if .LikeCount}}{{.LikeCount}}😀{{end}} + {{if .Tag}}{{.Tag}}{{else}}{{.Level}}👑{{end}}
{{end}}
{{if .CurrentUser.Perms.CreateReply}} diff --git a/templates/topic_alt.html b/templates/topic_alt.html index 8775b098..23bef1b6 100644 --- a/templates/topic_alt.html +++ b/templates/topic_alt.html @@ -6,7 +6,7 @@
{{.Topic.Title}} - {{if .Topic.Is_Closed}}🔒︎{{end}} + {{if .Topic.Is_Closed}}🔒︎{{else}}🖤︎{{end}} {{if .CurrentUser.Is_Mod}} Edit Delete diff --git a/themes.go b/themes.go index 712051ca..fc84fbab 100644 --- a/themes.go +++ b/themes.go @@ -105,7 +105,7 @@ func add_theme_static_files(themeName string) { path = strings.TrimPrefix(path,"themes/" + themeName + "/public") log.Print("Added the '" + path + "' static file for default theme " + themeName + ".") - static_files["/static" + path] = SFile{data,0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/themes/" + themeName + "/public" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} + static_files["/static" + path] = SFile{data,compress_bytes_gzip(data),0,int64(len(data)),mime.TypeByExtension(filepath.Ext("/themes/" + themeName + "/public" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} return nil }) if err != nil { diff --git a/themes/tempra-simple/public/main.css b/themes/tempra-simple/public/main.css index 15f74567..794ef75f 100644 --- a/themes/tempra-simple/public/main.css +++ b/themes/tempra-simple/public/main.css @@ -179,20 +179,9 @@ li a font-weight: bold; } -.formitem:first-child -{ - font-weight: bold; -} - -.formitem:not(:last-child) -{ - border-right: 1px dotted #ccc; -} - -.formitem.invisible_border -{ - border: none; -} +.formitem:first-child { font-weight: bold; } +.formitem:not(:last-child) { border-right: 1px dotted #ccc; } +.formitem.invisible_border { border: none; } /* Mostly for textareas */ .formitem:only-child { width: 100%; } @@ -249,7 +238,9 @@ button.username position: relative; top: -0.25px; } -.username.level {color: #303030;} +.username.level { color: #303030; } +.username.real_username { color: #404040; font-size: 17px; } +.username.real_username:hover { color: black; } .tag-mini { text-transform: none; @@ -266,6 +257,15 @@ button.username font-size: 10px; } +.post_item > .mod_button > button { + font-size: 15px; + color: #202020; + opacity: 0.7; +} +.post_item > .mod_button > button:hover { + opacity: 0.9; +} + .show_on_edit { display: none; } .alert { @@ -335,10 +335,7 @@ button.username font-weight: normal; text-transform: none; } - .rowitem - { - text-transform: none; - } + .rowitem { text-transform: none; } } @media (max-width: 620px) { @@ -381,6 +378,9 @@ button.username position: relative; top: -14px; } + .post_item > .mod_button > button { + opacity: 1; + } .post_item > .real_username { position: absolute; top: 70px; diff --git a/topic.go b/topic.go index 5b41d52f..8890b419 100644 --- a/topic.go +++ b/topic.go @@ -30,6 +30,7 @@ type TopicUser struct Status string // Deprecated. Marked for removal. IpAddress string PostCount int + LikeCount int CreatedByName string Avatar string @@ -40,6 +41,7 @@ type TopicUser struct URLPrefix string URLName string Level int + Liked bool } type TopicsRow struct @@ -56,6 +58,7 @@ type TopicsRow struct Status string // Deprecated. Marked for removal. IpAddress string PostCount int + LikeCount int CreatedByName string Avatar string diff --git a/user.go b/user.go index d914efa8..adfc1285 100644 --- a/user.go +++ b/user.go @@ -82,6 +82,7 @@ func SimpleForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (u fperms := groups[user.Group].Forums[fid] if fperms.Overrides && !user.Is_Super_Admin { user.Perms.ViewTopic = fperms.ViewTopic + user.Perms.LikeItem = fperms.LikeItem user.Perms.CreateTopic = fperms.CreateTopic user.Perms.EditTopic = fperms.EditTopic user.Perms.DeleteTopic = fperms.DeleteTopic @@ -103,6 +104,7 @@ func ForumSessionCheck(w http.ResponseWriter, r *http.Request, fid int) (user Us fperms := groups[user.Group].Forums[fid] if fperms.Overrides && !user.Is_Super_Admin { user.Perms.ViewTopic = fperms.ViewTopic + user.Perms.LikeItem = fperms.LikeItem user.Perms.CreateTopic = fperms.CreateTopic user.Perms.EditTopic = fperms.EditTopic user.Perms.DeleteTopic = fperms.DeleteTopic @@ -198,6 +200,21 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, succ return user, true } +func words_to_score(wcount int, topic bool) (score int) { + if topic { + score = 2 + } else { + score = 1 + } + + if wcount > settings["megapost_min_chars"].(int) { + score += 4 + } else if wcount > settings["bigpost_min_chars"].(int) { + score += 1 + } + return score +} + func increase_post_user_stats(wcount int, uid int, topic bool, user User) error { var mod int base_score := 1 diff --git a/utils.go b/utils.go index e836e566..f7668b14 100644 --- a/utils.go +++ b/utils.go @@ -122,6 +122,9 @@ func write_file(name string, content string) { func word_count(input string) (count int) { input = strings.TrimSpace(input) + if input == "" { + return 0 + } in_space := false for _, value := range input { if unicode.IsSpace(value) { @@ -133,7 +136,7 @@ func word_count(input string) (count int) { in_space = false } } - return count + return count + 1 } func getLevel(score int) (level int) {