From 2be884edc15451a2ef1ae84bf06e635c5e5b0fa8 Mon Sep 17 00:00:00 2001 From: Azareal Date: Tue, 15 May 2018 15:59:52 +1000 Subject: [PATCH] Commented out more debug code. Main Menu is now shown on the main menu in the menu list for extra clarity. Travis should now be able to run it's tests. Moved routeChangeTheme to the routes package. Moved routeShowAttachment to the routes package and partially refactored it. Moved routeLikeTopicSubmit to the routes package. Moved routeReplyLikeSubmit to the routes package and partially refactored it. Moved routeProfileReplyCreateSubmit to the routes package. Moved routeLogout to the routes package, now known as routes.AccountLogout. Moved the routeDynamic stub to the routes package, now known as routes.DynamicRoute. Moved the routeUploads stub to the routes package, now known as routes.UploadedFile. Moved the BadRoute stub to the routes package, now known as routes.BadRoute. All routes moved to the routes package have had the route prefix dropped from their name. Simplified the email token route to redirect back to the main email route instead of rendering the same template. Refactored the panel menus to use the new submenu system instead of the old one which had a lot of menu duplication. Added a stub directory for Nox, the next major theme after Cosora. Fixed a bug where the alerts wouldn't load outside of the index. Tweaked the CSS in the topic creation and reply forms on Shadow. Tweaked the padding on the stickies on Shadow. Improved the submenu CSS on every theme. Fixed the submitrow CSS on Shadow, Tempra Conflux. Fixed some double borders on Tempra Conflux. The frontend sidebar should no longer show up in the Control Panel in Tempra Conflux and Tempra Simple. Tweaked the title CSS on Cosora. Tweaked the user manager CSS on Cosora. Changed the primary text colour on Cosora. Fixed attachment images taking up too much space on Cosora. Run the patcher or update script for this commit. --- common/files.go | 24 +-- common/pages.go | 1 + config_default.noparse | 2 +- gen_mssql.go | 9 - gen_mysql.go | 8 - gen_router.go | 66 +++--- langs/english.json | 1 + main.go | 3 +- member_routes.go | 225 +------------------- panel_routes.go | 5 + patcher/main.go | 13 +- patcher/patches.go | 54 +++++ public/global.js | 18 +- query_gen/main.go | 2 - router_gen/main.go | 12 +- router_gen/routes.go | 12 +- routes.go | 49 +---- routes/account.go | 9 + routes/misc.go | 88 ++++++++ routes/reply.go | 96 +++++++++ routes/stubs.go | 24 +++ routes/topic.go | 56 +++++ schema/schema.json | 2 +- templates/panel-inner-menu.html | 10 +- templates/panel_adminlogs.html | 11 +- templates/panel_modlogs.html | 11 +- templates/panel_themes.html | 15 +- templates/panel_themes_menus.html | 17 +- templates/panel_themes_menus_item_edit.html | 14 +- templates/panel_themes_menus_items.html | 13 +- themes/cosora/public/main.css | 7 +- themes/cosora/public/panel.css | 2 +- themes/nox/public/main.css | 0 themes/nox/theme.json | 32 +++ themes/shadow/public/main.css | 11 +- themes/shadow/public/panel.css | 13 +- themes/tempra-conflux/public/main.css | 6 +- themes/tempra-conflux/public/panel.css | 12 +- themes/tempra-simple/public/panel.css | 15 +- 39 files changed, 519 insertions(+), 449 deletions(-) create mode 100644 routes/stubs.go create mode 100644 themes/nox/public/main.css create mode 100644 themes/nox/theme.json diff --git a/common/files.go b/common/files.go index 361f64be..cf22554f 100644 --- a/common/files.go +++ b/common/files.go @@ -3,7 +3,6 @@ package common import ( "bytes" "errors" - "fmt" "mime" "strings" "sync" @@ -38,9 +37,10 @@ type CSSData struct { } func (list SFileList) JSTmplInit() error { + DebugLog("Initialising the client side templates") var fragMap = make(map[string][][]byte) fragMap["alert"] = tmpl.GetFrag("alert") - fmt.Println("fragMap: ", fragMap) + DebugLog("fragMap: ", fragMap) return filepath.Walk("./tmpl_client", func(path string, f os.FileInfo, err error) error { if f.IsDir() { return nil @@ -75,15 +75,15 @@ func (list SFileList) JSTmplInit() error { if !hasBrace { return errors.New("no right brace found after the template function name") } - fmt.Println("spaceIndex: ", spaceIndex) - fmt.Println("endBrace: ", endBrace) - fmt.Println("string(data[spaceIndex:endBrace]): ", string(data[spaceIndex:endBrace])) + //fmt.Println("spaceIndex: ", spaceIndex) + //fmt.Println("endBrace: ", endBrace) + //fmt.Println("string(data[spaceIndex:endBrace]): ", string(data[spaceIndex:endBrace])) preLen := len(data) data = replace(data, string(data[spaceIndex:endBrace]), "") data = replace(data, "))\n", "\n") endBrace -= preLen - len(data) // Offset it as we've deleted portions - var showPos = func(data []byte, index int) (out string) { + /*var showPos = func(data []byte, index int) (out string) { out = "[" for j, char := range data { if index == j { @@ -93,16 +93,16 @@ func (list SFileList) JSTmplInit() error { } } return out + "]" - } + }*/ // ? Can we just use a regex? I'm thinking of going more efficient, or just outright rolling wasm, this is a temp hack in a place where performance doesn't particularly matter var each = func(phrase string, handle func(index int)) { - fmt.Println("find each '" + phrase + "'") + //fmt.Println("find each '" + phrase + "'") var index = endBrace var foundIt bool for { - fmt.Println("in index: ", index) - fmt.Println("pos: ", showPos(data, index)) + //fmt.Println("in index: ", index) + //fmt.Println("pos: ", showPos(data, index)) index, foundIt = skipAllUntilCharsExist(data, index, []byte(phrase)) if !foundIt { break @@ -136,7 +136,7 @@ func (list SFileList) JSTmplInit() error { } }) each("if ", func(index int) { - fmt.Println("if index: ", index) + //fmt.Println("if index: ", index) braceAt, hasBrace := skipUntilIfExists(data, index, '{') if hasBrace { if data[braceAt-1] != ' ' { @@ -161,7 +161,7 @@ func (list SFileList) JSTmplInit() error { tmplName := strings.TrimSuffix(path, ".go") fragset, ok := fragMap[strings.TrimPrefix(tmplName, "template_")] if !ok { - fmt.Println("tmplName: ", tmplName) + DebugLog("tmplName: ", tmplName) return errors.New("couldn't find template in fragmap") } diff --git a/common/pages.go b/common/pages.go index 86a82ead..c464dc61 100644 --- a/common/pages.go +++ b/common/pages.go @@ -254,6 +254,7 @@ type PanelThemesPage struct { } type PanelMenuListItem struct { + Name string ID int ItemCount int } diff --git a/config_default.noparse b/config_default.noparse index dc8ac451..3d11ee93 100644 --- a/config_default.noparse +++ b/config_default.noparse @@ -1,4 +1,4 @@ -package main +package config import "../common" diff --git a/gen_mssql.go b/gen_mssql.go index 03e2a5b2..a4439713 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -21,7 +21,6 @@ type Stmts struct { getTopicBasic *sql.Stmt forumEntryExists *sql.Stmt groupEntryExists *sql.Stmt - getAttachment *sql.Stmt getForumTopics *sql.Stmt createReport *sql.Stmt addForumPermsToForum *sql.Stmt @@ -154,14 +153,6 @@ func _gen_mssql() (err error) { return err } - common.DebugLog("Preparing getAttachment statement.") - stmts.getAttachment, err = db.Prepare("SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3") - if err != nil { - log.Print("Error in getAttachment statement.") - log.Print("Bad Query: ","SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3") - return err - } - common.DebugLog("Preparing getForumTopics statement.") stmts.getForumTopics, 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] = ?1 ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC") if err != nil { diff --git a/gen_mysql.go b/gen_mysql.go index 18d71b9e..f40d843a 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -23,7 +23,6 @@ type Stmts struct { getTopicBasic *sql.Stmt forumEntryExists *sql.Stmt groupEntryExists *sql.Stmt - getAttachment *sql.Stmt getForumTopics *sql.Stmt createReport *sql.Stmt addForumPermsToForum *sql.Stmt @@ -144,13 +143,6 @@ func _gen_mysql() (err error) { return err } - common.DebugLog("Preparing getAttachment statement.") - stmts.getAttachment, err = db.Prepare("SELECT `sectionID`,`sectionTable`,`originID`,`originTable`,`uploadedBy`,`path` FROM `attachments` WHERE `path` = ? AND `sectionID` = ? AND `sectionTable` = ?") - if err != nil { - log.Print("Error in getAttachment statement.") - return err - } - common.DebugLog("Preparing getForumTopics statement.") stmts.getForumTopics, 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") if err != nil { diff --git a/gen_router.go b/gen_router.go index 3dde6ba4..bff1313d 100644 --- a/gen_router.go +++ b/gen_router.go @@ -24,8 +24,8 @@ var RouteMap = map[string]interface{}{ "routes.CustomPage": routes.CustomPage, "routes.ForumList": routes.ForumList, "routes.ViewForum": routes.ViewForum, - "routeChangeTheme": routeChangeTheme, - "routeShowAttachment": routeShowAttachment, + "routes.ChangeTheme": routes.ChangeTheme, + "routes.ShowAttachment": routes.ShowAttachment, "common.RouteWebsockets": common.RouteWebsockets, "routeReportSubmit": routeReportSubmit, "routes.CreateTopic": routes.CreateTopic, @@ -109,28 +109,28 @@ var RouteMap = map[string]interface{}{ "routes.LockTopicSubmit": routes.LockTopicSubmit, "routes.UnlockTopicSubmit": routes.UnlockTopicSubmit, "routes.MoveTopicSubmit": routes.MoveTopicSubmit, - "routeLikeTopicSubmit": routeLikeTopicSubmit, + "routes.LikeTopicSubmit": routes.LikeTopicSubmit, "routes.ViewTopic": routes.ViewTopic, "routes.CreateReplySubmit": routes.CreateReplySubmit, "routes.ReplyEditSubmit": routes.ReplyEditSubmit, "routes.ReplyDeleteSubmit": routes.ReplyDeleteSubmit, - "routeReplyLikeSubmit": routeReplyLikeSubmit, - "routeProfileReplyCreateSubmit": routeProfileReplyCreateSubmit, + "routes.ReplyLikeSubmit": routes.ReplyLikeSubmit, + "routes.ProfileReplyCreateSubmit": routes.ProfileReplyCreateSubmit, "routes.ProfileReplyEditSubmit": routes.ProfileReplyEditSubmit, "routes.ProfileReplyDeleteSubmit": routes.ProfileReplyDeleteSubmit, "routes.PollVote": routes.PollVote, "routes.PollResults": routes.PollResults, "routes.AccountLogin": routes.AccountLogin, "routes.AccountRegister": routes.AccountRegister, - "routeLogout": routeLogout, + "routes.AccountLogout": routes.AccountLogout, "routes.AccountLoginSubmit": routes.AccountLoginSubmit, "routes.AccountRegisterSubmit": routes.AccountRegisterSubmit, - "routeDynamic": routeDynamic, - "routeUploads": routeUploads, + "routes.DynamicRoute": routes.DynamicRoute, + "routes.UploadedFile": routes.UploadedFile, "routes.StaticFile": routes.StaticFile, "routes.RobotsTxt": routes.RobotsTxt, "routes.SitemapXml": routes.SitemapXml, - "BadRoute": BadRoute, + "routes.BadRoute": routes.BadRoute, } // ! NEVER RELY ON THESE REMAINING THE SAME BETWEEN COMMITS @@ -140,8 +140,8 @@ var routeMapEnum = map[string]int{ "routes.CustomPage": 2, "routes.ForumList": 3, "routes.ViewForum": 4, - "routeChangeTheme": 5, - "routeShowAttachment": 6, + "routes.ChangeTheme": 5, + "routes.ShowAttachment": 6, "common.RouteWebsockets": 7, "routeReportSubmit": 8, "routes.CreateTopic": 9, @@ -225,28 +225,28 @@ var routeMapEnum = map[string]int{ "routes.LockTopicSubmit": 87, "routes.UnlockTopicSubmit": 88, "routes.MoveTopicSubmit": 89, - "routeLikeTopicSubmit": 90, + "routes.LikeTopicSubmit": 90, "routes.ViewTopic": 91, "routes.CreateReplySubmit": 92, "routes.ReplyEditSubmit": 93, "routes.ReplyDeleteSubmit": 94, - "routeReplyLikeSubmit": 95, - "routeProfileReplyCreateSubmit": 96, + "routes.ReplyLikeSubmit": 95, + "routes.ProfileReplyCreateSubmit": 96, "routes.ProfileReplyEditSubmit": 97, "routes.ProfileReplyDeleteSubmit": 98, "routes.PollVote": 99, "routes.PollResults": 100, "routes.AccountLogin": 101, "routes.AccountRegister": 102, - "routeLogout": 103, + "routes.AccountLogout": 103, "routes.AccountLoginSubmit": 104, "routes.AccountRegisterSubmit": 105, - "routeDynamic": 106, - "routeUploads": 107, + "routes.DynamicRoute": 106, + "routes.UploadedFile": 107, "routes.StaticFile": 108, "routes.RobotsTxt": 109, "routes.SitemapXml": 110, - "BadRoute": 111, + "routes.BadRoute": 111, } var reverseRouteMapEnum = map[int]string{ 0: "routeAPI", @@ -254,8 +254,8 @@ var reverseRouteMapEnum = map[int]string{ 2: "routes.CustomPage", 3: "routes.ForumList", 4: "routes.ViewForum", - 5: "routeChangeTheme", - 6: "routeShowAttachment", + 5: "routes.ChangeTheme", + 6: "routes.ShowAttachment", 7: "common.RouteWebsockets", 8: "routeReportSubmit", 9: "routes.CreateTopic", @@ -339,28 +339,28 @@ var reverseRouteMapEnum = map[int]string{ 87: "routes.LockTopicSubmit", 88: "routes.UnlockTopicSubmit", 89: "routes.MoveTopicSubmit", - 90: "routeLikeTopicSubmit", + 90: "routes.LikeTopicSubmit", 91: "routes.ViewTopic", 92: "routes.CreateReplySubmit", 93: "routes.ReplyEditSubmit", 94: "routes.ReplyDeleteSubmit", - 95: "routeReplyLikeSubmit", - 96: "routeProfileReplyCreateSubmit", + 95: "routes.ReplyLikeSubmit", + 96: "routes.ProfileReplyCreateSubmit", 97: "routes.ProfileReplyEditSubmit", 98: "routes.ProfileReplyDeleteSubmit", 99: "routes.PollVote", 100: "routes.PollResults", 101: "routes.AccountLogin", 102: "routes.AccountRegister", - 103: "routeLogout", + 103: "routes.AccountLogout", 104: "routes.AccountLoginSubmit", 105: "routes.AccountRegisterSubmit", - 106: "routeDynamic", - 107: "routeUploads", + 106: "routes.DynamicRoute", + 107: "routes.UploadedFile", 108: "routes.StaticFile", 109: "routes.RobotsTxt", 110: "routes.SitemapXml", - 111: "BadRoute", + 111: "routes.BadRoute", } var osMapEnum = map[string]int{ "unknown": 0, @@ -860,7 +860,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(5) - err = routeChangeTheme(w,req,user) + err = routes.ChangeTheme(w,req,user) if err != nil { router.handleError(err,w,req,user) } @@ -872,7 +872,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(6) - err = routeShowAttachment(w,req,user,extraData) + err = routes.ShowAttachment(w,req,user,extraData) if err != nil { router.handleError(err,w,req,user) } @@ -1632,7 +1632,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(90) - err = routeLikeTopicSubmit(w,req,user,extraData) + err = routes.LikeTopicSubmit(w,req,user,extraData) default: counters.RouteViewCounter.Bump(91) err = routes.ViewTopic(w,req,user, extraData) @@ -1712,7 +1712,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(95) - err = routeReplyLikeSubmit(w,req,user,extraData) + err = routes.ReplyLikeSubmit(w,req,user,extraData) } if err != nil { router.handleError(err,w,req,user) @@ -1733,7 +1733,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(96) - err = routeProfileReplyCreateSubmit(w,req,user) + err = routes.ProfileReplyCreateSubmit(w,req,user) case "/profile/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { @@ -1814,7 +1814,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(103) - err = routeLogout(w,req,user) + err = routes.AccountLogout(w,req,user) case "/accounts/login/submit/": err = common.ParseForm(w,req,user) if err != nil { diff --git a/langs/english.json b/langs/english.json index 29dfce23..ff7dc157 100644 --- a/langs/english.json +++ b/langs/english.json @@ -701,6 +701,7 @@ "panel_themes_make_default":"Make Default", "panel_themes_menus_head":"Menus", + "panel_themes_menus_main":"Main Menu", "panel_themes_menus_item_edit_button_aria":"Edit menu item", "panel_themes_menus_item_delete_button_aria":"Delete menu item", diff --git a/main.go b/main.go index bd4996b5..aceeed77 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( "./common/counters" "./config" "./query_gen/lib" + "./routes" "github.com/fsnotify/fsnotify" ) @@ -445,7 +446,7 @@ func main() { // TODO: Redirect to port 443 go func() { log.Print("Listening on port 80") - err = newServer(":80", &HTTPSRedirect{}).ListenAndServe() + err = newServer(":80", &routes.HTTPSRedirect{}).ListenAndServe() if err != nil { log.Fatal(err) } diff --git a/member_routes.go b/member_routes.go index 57c9296c..dc9d6c6e 100644 --- a/member_routes.go +++ b/member_routes.go @@ -2,166 +2,12 @@ package main import ( "net/http" - "path/filepath" "strconv" - "strings" "./common" "./common/counters" ) -// TODO: Refactor this -func routeLikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { - isJs := (r.PostFormValue("isJs") == "1") - tid, err := strconv.Atoi(stid) - if err != nil { - return common.PreErrorJSQ("Topic IDs can only ever be numbers.", w, r, isJs) - } - - topic, err := common.Topics.Get(tid) - if err == ErrNoRows { - return common.PreErrorJSQ("The requested topic doesn't exist.", w, r, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - // TODO: Add hooks to make use of headerLite - _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) - if ferr != nil { - return ferr - } - if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return common.NoPermissionsJSQ(w, r, user, isJs) - } - if topic.CreatedBy == user.ID { - return common.LocalErrorJSQ("You can't like your own topics", w, r, user, isJs) - } - - _, err = common.Users.Get(topic.CreatedBy) - if err != nil && err == ErrNoRows { - return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - score := 1 - err = topic.Like(score, user.ID) - //log.Print("likeErr: ", err) - if err == common.ErrAlreadyLiked { - return common.LocalErrorJSQ("You already liked this", w, r, user, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - err = common.AddActivityAndNotifyTarget(user.ID, topic.CreatedBy, "like", "topic", tid) - if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - if !isJs { - http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) - } else { - _, _ = w.Write(successJSONBytes) - } - return nil -} - -func routeReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { - isJs := (r.PostFormValue("isJs") == "1") - - rid, err := strconv.Atoi(srid) - if err != nil { - return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) - } - - reply, err := common.Rstore.Get(rid) - if err == ErrNoRows { - return common.PreErrorJSQ("You can't like something which doesn't exist!", w, r, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - var fid int - err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid) - if err == ErrNoRows { - return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - // TODO: Add hooks to make use of headerLite - _, ferr := common.SimpleForumUserCheck(w, r, &user, fid) - if ferr != nil { - return ferr - } - if !user.Perms.ViewTopic || !user.Perms.LikeItem { - return common.NoPermissionsJSQ(w, r, user, isJs) - } - if reply.CreatedBy == user.ID { - return common.LocalErrorJSQ("You can't like your own replies", w, r, user, isJs) - } - - _, err = common.Users.Get(reply.CreatedBy) - if err != nil && err != ErrNoRows { - return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - err = reply.Like(user.ID) - if err == common.ErrAlreadyLiked { - return common.LocalErrorJSQ("You've already liked this!", w, r, user, isJs) - } else if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - err = common.AddActivityAndNotifyTarget(user.ID, reply.CreatedBy, "like", "post", rid) - if err != nil { - return common.InternalErrorJSQ(err, w, r, isJs) - } - - if !isJs { - http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther) - } else { - _, _ = w.Write(successJSONBytes) - } - return nil -} - -func routeProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - if !user.Perms.ViewTopic || !user.Perms.CreateReply { - return common.NoPermissions(w, r, user) - } - - uid, err := strconv.Atoi(r.PostFormValue("uid")) - if err != nil { - return common.LocalError("Invalid UID", w, r, user) - } - - profileOwner, err := common.Users.Get(uid) - if err == ErrNoRows { - return common.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) - } else if err != nil { - return common.InternalError(err, w, r) - } - - content := common.PreparseMessage(r.PostFormValue("reply-content")) - // TODO: Fully parse the post and store it in the parsed column - _, err = common.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP) - if err != nil { - return common.InternalError(err, w, r) - } - - err = common.AddActivityAndNotifyTarget(user.ID, profileOwner.ID, "reply", "user", profileOwner.ID) - if err != nil { - return common.InternalError(err, w, r) - } - - counters.PostCounter.Bump() - http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) - return nil -} - func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError { itemID, err := strconv.Atoi(sitemID) if err != nil { @@ -292,9 +138,13 @@ func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user common.U email.Primary = true emailList = append(emailList, email) } + if !common.Site.EnableEmails { headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_mail_disabled")) } + if r.FormValue("verified") == "1" { + headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_mail_verify_success")) + } pi := common.Page{"Email Manager", user, headerVars, emailList, nil} if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { @@ -361,72 +211,7 @@ func routeAccountEditEmailTokenSubmit(w http.ResponseWriter, r *http.Request, us return common.InternalError(err, w, r) } } + http.Redirect(w, r, "/user/edit/email/?verified=1", http.StatusSeeOther) - if !common.Site.EnableEmails { - headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_mail_disabled")) - } - headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_mail_verify_success")) - pi := common.Page{"Email Manager", user, headerVars, emailList, nil} - if common.RunPreRenderHook("pre_render_account_own_edit_email", w, r, &user, &pi) { - return nil - } - err = common.Templates.ExecuteTemplate(w, "account_own_edit_email.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil -} - -func routeLogout(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - if !user.Loggedin { - return common.LocalError("You can't logout without logging in first.", w, r, user) - } - common.Auth.Logout(w, user.ID) - http.Redirect(w, r, "/", http.StatusSeeOther) - return nil -} - -func routeShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, filename string) common.RouteError { - filename = common.Stripslashes(filename) - var ext = filepath.Ext("./attachs/" + filename) - //log.Print("ext ", ext) - //log.Print("filename ", filename) - if !common.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { - return common.LocalError("Bad extension", w, r, user) - } - - sectionID, err := strconv.Atoi(r.FormValue("sectionID")) - if err != nil { - return common.LocalError("The sectionID is not an integer", w, r, user) - } - var sectionTable = r.FormValue("sectionType") - - var originTable string - var originID, uploadedBy int - err = stmts.getAttachment.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename) - if err == ErrNoRows { - return common.NotFound(w, r, nil) - } else if err != nil { - return common.InternalError(err, w, r) - } - - if sectionTable == "forums" { - _, ferr := common.SimpleForumUserCheck(w, r, &user, sectionID) - if ferr != nil { - return ferr - } - if !user.Perms.ViewTopic { - return common.NoPermissions(w, r, user) - } - } else { - return common.LocalError("Unknown section", w, r, user) - } - - if originTable != "topics" && originTable != "replies" { - return common.LocalError("Unknown origin", w, r, user) - } - - // TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side - http.ServeFile(w, r, "./attachs/"+filename) return nil } diff --git a/panel_routes.go b/panel_routes.go index cbb510ba..adc6704e 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -2397,7 +2397,12 @@ func routePanelThemesMenus(w http.ResponseWriter, r *http.Request, user common.U var menuList []common.PanelMenuListItem for mid, list := range common.Menus.GetAllMap() { + var name = "" + if mid == 1 { + name = common.GetTmplPhrase("panel_themes_menus_main") + } menuList = append(menuList, common.PanelMenuListItem{ + Name: name, ID: mid, ItemCount: len(list.List), }) diff --git a/patcher/main.go b/patcher/main.go index 91322a1e..a87ce9aa 100644 --- a/patcher/main.go +++ b/patcher/main.go @@ -92,13 +92,16 @@ func patcher(scanner *bufio.Scanner) error { } fmt.Println("Applying the patches") - if dbVersion < 1 { - err := patch0(scanner) - if err != nil { - return err + if dbVersion < 2 { + if dbVersion < 1 { + err := patch0(scanner) + if err != nil { + return err + } } + return patch1(scanner) } - return patch1(scanner) + return patch2(scanner) } func execStmt(stmt *sql.Stmt, err error) error { diff --git a/patcher/patches.go b/patcher/patches.go index 6fef4d26..42ce668c 100644 --- a/patcher/patches.go +++ b/patcher/patches.go @@ -152,3 +152,57 @@ func patch1(scanner *bufio.Scanner) error { return nil } + +func patch2(scanner *bufio.Scanner) error { + // ! Don't reuse this function blindly, it doesn't escape apostrophes + var replaceTextWhere = func(replaceThis string, withThis string) error { + return execStmt(qgen.Builder.SimpleUpdate("viewchunks", "route = '"+withThis+"'", "route = '"+replaceThis+"'")) + } + + err := replaceTextWhere("routeLogout", "routes.AccountLogout") + if err != nil { + return err + } + + err = replaceTextWhere("routeShowAttachment", "routes.ShowAttachment") + if err != nil { + return err + } + + err = replaceTextWhere("routeChangeTheme", "routes.ChangeTheme") + if err != nil { + return err + } + + err = replaceTextWhere("routeProfileReplyCreateSubmit", "routes.ProfileReplyCreateSubmit") + if err != nil { + return err + } + + err = replaceTextWhere("routeLikeTopicSubmit", "routes.LikeTopicSubmit") + if err != nil { + return err + } + + err = replaceTextWhere("routeReplyLikeSubmit", "routes.ReplyLikeSubmit") + if err != nil { + return err + } + + err = replaceTextWhere("routeDynamic", "routes.DynamicRoute") + if err != nil { + return err + } + + err = replaceTextWhere("routeUploads", "routes.UploadedFile") + if err != nil { + return err + } + + err = replaceTextWhere("BadRoute", "routes.BadRoute") + if err != nil { + return err + } + + return nil +} diff --git a/public/global.js b/public/global.js index e75db775..d354f862 100644 --- a/public/global.js +++ b/public/global.js @@ -217,16 +217,30 @@ function runWebSockets() { } } +function loadScript(name, callback) { + let url = "//" +siteURL+"/static/"+name + $.getScript(url) + .done(callback) + .fail((e,xhr,settings,ex) => { + console.log("Unable to get script '"+url+"'"); + console.log("e: ", e); + console.log("xhr: ", xhr); + console.log("settings: ", settings); + console.log("ex: ",ex); + console.trace(); + }); +} + $(document).ready(function(){ runHook("start_init"); - $.getScript( "./static/template_alert.js", () => { + loadScript("template_alert.js",() => { console.log("Loaded template_alert.js"); alertsInitted = true; var alertMenuList = document.getElementsByClassName("menu_alerts"); for(var i = 0; i < alertMenuList.length; i++) { loadAlerts(alertMenuList[i]); } - }); + }) if(window["WebSocket"]) runWebSockets(); else conn = false; diff --git a/query_gen/main.go b/query_gen/main.go index d77fe4eb..eed0036b 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -283,8 +283,6 @@ func writeSelects(adapter qgen.Adapter) error { build.Select("groupEntryExists").Table("users_groups").Columns("gid").Where("name = ''").Orderby("gid ASC").Limit("0,1").Parse() - build.Select("getAttachment").Table("attachments").Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path").Where("path = ? AND sectionID = ? AND sectionTable = ?").Parse() - return nil } diff --git a/router_gen/main.go b/router_gen/main.go index 6c3296f3..6d0bd3aa 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -155,12 +155,12 @@ func main() { } // Stubs for us to refer to these routes through - mapIt("routeDynamic") - mapIt("routeUploads") + mapIt("routes.DynamicRoute") + mapIt("routes.UploadedFile") mapIt("routes.StaticFile") mapIt("routes.RobotsTxt") mapIt("routes.SitemapXml") - mapIt("BadRoute") + mapIt("routes.BadRoute") tmplVars.AllRouteNames = allRouteNames tmplVars.AllRouteMap = allRouteMap @@ -652,7 +652,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { common.NotFound(w,req,nil) return } - counters.RouteViewCounter.Bump({{.AllRouteMap.routeUploads}}) + counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.UploadedFile" }}) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? router.UploadHandler(w,req) // TODO: Count these views @@ -697,7 +697,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { router.RUnlock() if ok { - counters.RouteViewCounter.Bump({{.AllRouteMap.routeDynamic}}) // TODO: Be more specific about *which* dynamic route it is + counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.DynamicRoute" }}) // TODO: Be more specific about *which* dynamic route it is req.URL.Path += extraData err = handle(w,req,user) if err != nil { @@ -712,7 +712,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } else { router.DumpRequest(req,"Bad Route") } - counters.RouteViewCounter.Bump({{.AllRouteMap.BadRoute}}) + counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.BadRoute" }}) common.NotFound(w,req,nil) } } diff --git a/router_gen/routes.go b/router_gen/routes.go index d571a1eb..a7bf715b 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -7,9 +7,9 @@ func routes() { addRoute(View("routes.CustomPage", "/pages/", "extraData")) addRoute(View("routes.ForumList", "/forums/" /*,"&forums"*/)) addRoute(View("routes.ViewForum", "/forum/", "extraData")) - addRoute(AnonAction("routeChangeTheme", "/theme/")) + addRoute(AnonAction("routes.ChangeTheme", "/theme/")) addRoute( - View("routeShowAttachment", "/attachs/", "extraData").Before("ParseForm"), + View("routes.ShowAttachment", "/attachs/", "extraData").Before("ParseForm"), ) // TODO: Reduce the number of Befores. With a new method, perhaps? @@ -74,7 +74,7 @@ func buildTopicRoutes() { Action("routes.LockTopicSubmit", "/topic/lock/submit/").LitBefore("req.URL.Path += extraData"), Action("routes.UnlockTopicSubmit", "/topic/unlock/submit/", "extraData"), Action("routes.MoveTopicSubmit", "/topic/move/submit/", "extraData"), - Action("routeLikeTopicSubmit", "/topic/like/submit/", "extraData").Before("ParseForm"), + Action("routes.LikeTopicSubmit", "/topic/like/submit/", "extraData").Before("ParseForm"), ) addRouteGroup(topicGroup) } @@ -88,7 +88,7 @@ func buildReplyRoutes() { UploadAction("routes.CreateReplySubmit", "/reply/create/").MaxSizeVar("int(common.Config.MaxRequestSize)"), // TODO: Rename the route so it's /reply/create/submit/ Action("routes.ReplyEditSubmit", "/reply/edit/submit/", "extraData"), Action("routes.ReplyDeleteSubmit", "/reply/delete/submit/", "extraData"), - Action("routeReplyLikeSubmit", "/reply/like/submit/", "extraData").Before("ParseForm"), + Action("routes.ReplyLikeSubmit", "/reply/like/submit/", "extraData").Before("ParseForm"), ) addRouteGroup(replyGroup) } @@ -98,7 +98,7 @@ func buildProfileReplyRoutes() { //router.HandleFunc("/user/edit/submit/", routeLogout) // routeLogout? what on earth? o.o pReplyGroup := newRouteGroup("/profile/") pReplyGroup.Routes( - Action("routeProfileReplyCreateSubmit", "/profile/reply/create/"), // TODO: Add /submit/ to the end + Action("routes.ProfileReplyCreateSubmit", "/profile/reply/create/"), // TODO: Add /submit/ to the end Action("routes.ProfileReplyEditSubmit", "/profile/reply/edit/submit/", "extraData"), Action("routes.ProfileReplyDeleteSubmit", "/profile/reply/delete/submit/", "extraData"), ) @@ -120,7 +120,7 @@ func buildAccountRoutes() { accReplyGroup.Routes( View("routes.AccountLogin", "/accounts/login/"), View("routes.AccountRegister", "/accounts/create/"), - Action("routeLogout", "/accounts/logout/"), + Action("routes.AccountLogout", "/accounts/logout/"), AnonAction("routes.AccountLoginSubmit", "/accounts/login/submit/"), // TODO: Guard this with a token, maybe the IP hashed with a rotated key? AnonAction("routes.AccountRegisterSubmit", "/accounts/create/submit/"), ) diff --git a/routes.go b/routes.go index 308b82d1..8fae9f97 100644 --- a/routes.go +++ b/routes.go @@ -7,7 +7,6 @@ package main import ( - "html" "net/http" "strconv" @@ -20,51 +19,8 @@ var tList []interface{} //var nList []string var successJSONBytes = []byte(`{"success":"1"}`) -// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS -type HTTPSRedirect struct { -} - -func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Connection", "close") - dest := "https://" + req.Host + req.URL.Path - if len(req.URL.RawQuery) > 0 { - dest += "?" + req.URL.RawQuery - } - http.Redirect(w, req, dest, http.StatusTemporaryRedirect) -} - -// Temporary stubs for view tracking -func routeDynamic() { -} -func routeUploads() { -} -func BadRoute() { -} - -// TODO: Set the cookie domain -func routeChangeTheme(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - //headerLite, _ := SimpleUserCheck(w, r, &user) - // TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly? - isJs := (r.PostFormValue("isJs") == "1") - newTheme := html.EscapeString(r.PostFormValue("newTheme")) - - theme, ok := common.Themes[newTheme] - if !ok || theme.HideFromThemes { - return common.LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) - } - - cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: int(common.Year)} - http.SetCookie(w, &cookie) - - if !isJs { - http.Redirect(w, r, "/", http.StatusSeeOther) - } else { - _, _ = w.Write(successJSONBytes) - } - return nil -} - // TODO: Refactor this +// TODO: Use the phrase system var phraseLoginAlerts = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`) // TODO: Refactor this endpoint @@ -81,8 +37,7 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.R return common.PreErrorJS("Invalid Action", w, r) } - module := r.FormValue("module") - switch module { + switch r.FormValue("module") { case "dismiss-alert": asid, err := strconv.Atoi(r.FormValue("asid")) if err != nil { diff --git a/routes/account.go b/routes/account.go index 78031b5e..2f6b45a3 100644 --- a/routes/account.go +++ b/routes/account.go @@ -77,6 +77,15 @@ func AccountLoginSubmit(w http.ResponseWriter, r *http.Request, user common.User return nil } +func AccountLogout(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + if !user.Loggedin { + return common.LocalError("You can't logout without logging in first.", w, r, user) + } + common.Auth.Logout(w, user.ID) + http.Redirect(w, r, "/", http.StatusSeeOther) + return nil +} + func AccountRegister(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { header, ferr := common.UserCheck(w, r, &user) if ferr != nil { diff --git a/routes/misc.go b/routes/misc.go index 59b24fdf..ffe5fb03 100644 --- a/routes/misc.go +++ b/routes/misc.go @@ -2,13 +2,17 @@ package routes import ( "bytes" + "database/sql" + "html" "io" "net/http" + "path/filepath" "strconv" "strings" "time" "../common" + "../query_gen/lib" ) var cacheControlMaxAge = "max-age=" + strconv.Itoa(int(common.Day)) // TODO: Make this a common.Config value @@ -86,3 +90,87 @@ func CustomPage(w http.ResponseWriter, r *http.Request, user common.User, name s } return nil } + +type AttachmentStmts struct { + get *sql.Stmt +} + +var attachmentStmts AttachmentStmts + +// TODO: Move these DbInits into a TopicList abstraction +func init() { + common.DbInits.Add(func(acc *qgen.Accumulator) error { + attachmentStmts = AttachmentStmts{ + get: acc.Select("attachments").Columns("sectionID, sectionTable, originID, originTable, uploadedBy, path").Where("path = ? AND sectionID = ? AND sectionTable = ?").Prepare(), + } + return acc.FirstError() + }) +} + +func ShowAttachment(w http.ResponseWriter, r *http.Request, user common.User, filename string) common.RouteError { + filename = common.Stripslashes(filename) + var ext = filepath.Ext("./attachs/" + filename) + //log.Print("ext ", ext) + //log.Print("filename ", filename) + if !common.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { + return common.LocalError("Bad extension", w, r, user) + } + + sectionID, err := strconv.Atoi(r.FormValue("sectionID")) + if err != nil { + return common.LocalError("The sectionID is not an integer", w, r, user) + } + var sectionTable = r.FormValue("sectionType") + + var originTable string + var originID, uploadedBy int + err = attachmentStmts.get.QueryRow(filename, sectionID, sectionTable).Scan(§ionID, §ionTable, &originID, &originTable, &uploadedBy, &filename) + if err == sql.ErrNoRows { + return common.NotFound(w, r, nil) + } else if err != nil { + return common.InternalError(err, w, r) + } + + if sectionTable == "forums" { + _, ferr := common.SimpleForumUserCheck(w, r, &user, sectionID) + if ferr != nil { + return ferr + } + if !user.Perms.ViewTopic { + return common.NoPermissions(w, r, user) + } + } else { + return common.LocalError("Unknown section", w, r, user) + } + + if originTable != "topics" && originTable != "replies" { + return common.LocalError("Unknown origin", w, r, user) + } + + // TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side + http.ServeFile(w, r, "./attachs/"+filename) + return nil +} + +// TODO: Set the cookie domain +func ChangeTheme(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + //headerLite, _ := SimpleUserCheck(w, r, &user) + // TODO: Rename isJs to something else, just in case we rewrite the JS side in WebAssembly? + isJs := (r.PostFormValue("isJs") == "1") + newTheme := html.EscapeString(r.PostFormValue("newTheme")) + + theme, ok := common.Themes[newTheme] + if !ok || theme.HideFromThemes { + return common.LocalErrorJSQ("That theme doesn't exist", w, r, user, isJs) + } + + cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: int(common.Year)} + http.SetCookie(w, &cookie) + + if !isJs { + http.Redirect(w, r, "/", http.StatusSeeOther) + } else { + _, _ = w.Write(successJSONBytes) + } + return nil +} diff --git a/routes/reply.go b/routes/reply.go index 1d6ddafe..af9541c0 100644 --- a/routes/reply.go +++ b/routes/reply.go @@ -297,6 +297,41 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, return nil } +// TODO: Move the profile reply routes to their own file? +func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { + if !user.Perms.ViewTopic || !user.Perms.CreateReply { + return common.NoPermissions(w, r, user) + } + + uid, err := strconv.Atoi(r.PostFormValue("uid")) + if err != nil { + return common.LocalError("Invalid UID", w, r, user) + } + + profileOwner, err := common.Users.Get(uid) + if err == sql.ErrNoRows { + return common.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) + } else if err != nil { + return common.InternalError(err, w, r) + } + + content := common.PreparseMessage(r.PostFormValue("reply-content")) + // TODO: Fully parse the post and store it in the parsed column + _, err = common.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP) + if err != nil { + return common.InternalError(err, w, r) + } + + err = common.AddActivityAndNotifyTarget(user.ID, profileOwner.ID, "reply", "user", profileOwner.ID) + if err != nil { + return common.InternalError(err, w, r) + } + + counters.PostCounter.Bump() + http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) + return nil +} + func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { isJs := (r.PostFormValue("js") == "1") @@ -372,3 +407,64 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user commo } return nil } + +func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError { + isJs := (r.PostFormValue("isJs") == "1") + + rid, err := strconv.Atoi(srid) + if err != nil { + return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs) + } + + reply, err := common.Rstore.Get(rid) + if err == sql.ErrNoRows { + return common.PreErrorJSQ("You can't like something which doesn't exist!", w, r, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + topic, err := common.Topics.Get(reply.ParentID) + if err == sql.ErrNoRows { + return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + // TODO: Add hooks to make use of headerLite + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + if ferr != nil { + return ferr + } + if !user.Perms.ViewTopic || !user.Perms.LikeItem { + return common.NoPermissionsJSQ(w, r, user, isJs) + } + if reply.CreatedBy == user.ID { + return common.LocalErrorJSQ("You can't like your own replies", w, r, user, isJs) + } + + _, err = common.Users.Get(reply.CreatedBy) + if err != nil && err != sql.ErrNoRows { + return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + err = reply.Like(user.ID) + if err == common.ErrAlreadyLiked { + return common.LocalErrorJSQ("You've already liked this!", w, r, user, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + err = common.AddActivityAndNotifyTarget(user.ID, reply.CreatedBy, "like", "post", rid) + if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + if !isJs { + http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther) + } else { + _, _ = w.Write(successJSONBytes) + } + return nil +} diff --git a/routes/stubs.go b/routes/stubs.go new file mode 100644 index 00000000..c57c847c --- /dev/null +++ b/routes/stubs.go @@ -0,0 +1,24 @@ +package routes + +import "net/http" + +// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS +type HTTPSRedirect struct { +} + +func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Connection", "close") + dest := "https://" + req.Host + req.URL.Path + if len(req.URL.RawQuery) > 0 { + dest += "?" + req.URL.RawQuery + } + http.Redirect(w, req, dest, http.StatusTemporaryRedirect) +} + +// Temporary stubs for view tracking +func DynamicRoute() { +} +func UploadedFile() { +} +func BadRoute() { +} diff --git a/routes/topic.go b/routes/topic.go index 5906c59f..dfe00c47 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -842,3 +842,59 @@ func addTopicAction(action string, topic *common.Topic, user common.User) error } return topic.CreateActionReply(action, user.LastIP, user) } + +// TODO: Refactor this +func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError { + isJs := (r.PostFormValue("isJs") == "1") + tid, err := strconv.Atoi(stid) + if err != nil { + return common.PreErrorJSQ("Topic IDs can only ever be numbers.", w, r, isJs) + } + + topic, err := common.Topics.Get(tid) + if err == sql.ErrNoRows { + return common.PreErrorJSQ("The requested topic doesn't exist.", w, r, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + // TODO: Add hooks to make use of headerLite + _, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID) + if ferr != nil { + return ferr + } + if !user.Perms.ViewTopic || !user.Perms.LikeItem { + return common.NoPermissionsJSQ(w, r, user, isJs) + } + if topic.CreatedBy == user.ID { + return common.LocalErrorJSQ("You can't like your own topics", w, r, user, isJs) + } + + _, err = common.Users.Get(topic.CreatedBy) + if err != nil && err == sql.ErrNoRows { + return common.LocalErrorJSQ("The target user doesn't exist", w, r, user, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + score := 1 + err = topic.Like(score, user.ID) + //log.Print("likeErr: ", err) + if err == common.ErrAlreadyLiked { + return common.LocalErrorJSQ("You already liked this", w, r, user, isJs) + } else if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + err = common.AddActivityAndNotifyTarget(user.ID, topic.CreatedBy, "like", "topic", tid) + if err != nil { + return common.InternalErrorJSQ(err, w, r, isJs) + } + + if !isJs { + http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther) + } else { + _, _ = w.Write(successJSONBytes) + } + return nil +} diff --git a/schema/schema.json b/schema/schema.json index 58f877eb..1e592ab3 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -1,5 +1,5 @@ { - "DBVersion":"2", + "DBVersion":"3", "DynamicFileVersion":"0", "MinGoVersion":"1.10", "MinVersion":"" diff --git a/templates/panel-inner-menu.html b/templates/panel-inner-menu.html index eb7f9f00..817e3be6 100644 --- a/templates/panel-inner-menu.html +++ b/templates/panel-inner-menu.html @@ -17,9 +17,15 @@
{{lang "panel_menu_word_filters"}} ({{.Stats.WordFilters}})
{{end}} - {{if .CurrentUser.Perms.ManageThemes}}
+ {{if .CurrentUser.Perms.ManageThemes}} + {{end}} +
+ {{if eq .Zone "themes"}} + + + {{end}} + {{end}}
diff --git a/templates/panel_adminlogs.html b/templates/panel_adminlogs.html index 55c5c220..2bd46de4 100644 --- a/templates/panel_adminlogs.html +++ b/templates/panel_adminlogs.html @@ -1,15 +1,6 @@ {{template "header.html" . }}
- +{{template "panel-menu.html" . }}

{{lang "panel_logs_administration_head"}}

diff --git a/templates/panel_modlogs.html b/templates/panel_modlogs.html index c67a9433..f5aec23f 100644 --- a/templates/panel_modlogs.html +++ b/templates/panel_modlogs.html @@ -1,15 +1,6 @@ {{template "header.html" . }}
- +{{template "panel-menu.html" . }}

{{lang "panel_logs_moderation_head"}}

diff --git a/templates/panel_themes.html b/templates/panel_themes.html index 9044fa35..7319a164 100644 --- a/templates/panel_themes.html +++ b/templates/panel_themes.html @@ -1,19 +1,6 @@ {{template "header.html" . }}
- - - +{{template "panel-menu.html" . }} {{/** Stop inlining this x.x **/}}