From 21999cd7c61d8da8c7b0e1f3ea106ca38e437b90 Mon Sep 17 00:00:00 2001 From: Azareal Date: Tue, 26 Dec 2017 07:17:26 +0000 Subject: [PATCH] Fixed the forum editor on Cosora. More excavating coming up. Tweaked the preparser to hopefully fix a few problems with the WYSIWYG Editor. Added BulkGetCopy to the ForumStores. Added InternalErrorXML and SilentInternalErrorXML. Tweaked the element queries so that the topic titles aren't truncated too short. Began refactoring the topic list logic, more to come here. --- bot_routes.go | 83 ++++++---------------------------- common/errors.go | 20 ++++++++ common/forum_store.go | 14 ++++++ common/parser.go | 6 +-- common/topic_list.go | 35 ++++++++++++++ routes.go | 24 ++-------- themes/cosora/public/main.css | 35 +++++++------- themes/cosora/public/panel.css | 33 +++++++++++++- 8 files changed, 141 insertions(+), 109 deletions(-) create mode 100644 common/topic_list.go diff --git a/bot_routes.go b/bot_routes.go index 4e26f376..32c77733 100644 --- a/bot_routes.go +++ b/bot_routes.go @@ -1,13 +1,13 @@ package main import ( + "errors" "log" "net/http" "strconv" "strings" "./common" - "./query_gen/lib" ) // TODO: Make this a static file somehow? Is it possible for us to put this file somewhere else? @@ -23,8 +23,6 @@ Disallow: /report/ return nil } -var xmlInternalError = []byte(` -A problem has occured`) var sitemapPageCap = 40000 // 40k, bump it up to 50k once we gzip this? Does brotli work on sitemaps? func writeXMLHeader(w http.ResponseWriter, r *http.Request) { @@ -110,11 +108,7 @@ func routeSitemapForums(w http.ResponseWriter, r *http.Request) common.RouteErro group, err := common.Groups.Get(common.GuestUser.Group) if err != nil { - log.Print("The guest group doesn't exist for some reason") - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - return common.HandledRouteError() + return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } writeXMLHeader(w, r) @@ -145,54 +139,29 @@ func routeSitemapTopics(w http.ResponseWriter, r *http.Request) common.RouteErro `)) } - writeXMLHeader(w, r) group, err := common.Groups.Get(common.GuestUser.Group) if err != nil { - log.Print("The guest group doesn't exist for some reason") - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - return common.HandledRouteError() + return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } - var argList []interface{} - var qlist string + var visibleForums []common.Forum for _, fid := range group.CanSee { forum := common.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active { - argList = append(argList, strconv.Itoa(fid)) - qlist += "?," + visibleForums = append(visibleForums, forum.Copy()) } } - if qlist != "" { - qlist = qlist[0 : len(qlist)-1] - } - // TODO: Abstract this - topicCountStmt, err := qgen.Builder.SimpleCount("topics", "parentID IN("+qlist+")", "") + topicCount, err := common.TopicCountInForums(visibleForums) if err != nil { - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - common.LogError(err) - return common.HandledRouteError() - } - defer topicCountStmt.Close() - - var topicCount int - err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) - if err != nil && err != ErrNoRows { - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - common.LogError(err) - return common.HandledRouteError() + return common.InternalErrorXML(err, w, r) } var pageCount = topicCount / sitemapPageCap //log.Print("topicCount", topicCount) //log.Print("pageCount", pageCount) + writeXMLHeader(w, r) w.Write([]byte("\n")) for i := 0; i <= pageCount; i++ { sitemapItem("sitemaps/topics_page_" + strconv.Itoa(i) + ".xml") @@ -215,45 +184,21 @@ func routeSitemapTopic(w http.ResponseWriter, r *http.Request, page int) common. group, err := common.Groups.Get(common.GuestUser.Group) if err != nil { - log.Print("The guest group doesn't exist for some reason") - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - return common.HandledRouteError() + return common.SilentInternalErrorXML(errors.New("The guest group doesn't exist for some reason"), w, r) } - var argList []interface{} - var qlist string + var visibleForums []common.Forum for _, fid := range group.CanSee { forum := common.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active { - argList = append(argList, strconv.Itoa(fid)) - qlist += "?," + visibleForums = append(visibleForums, forum.Copy()) } } - if qlist != "" { - qlist = qlist[0 : len(qlist)-1] - } - // TODO: Abstract this - topicCountStmt, err := qgen.Builder.SimpleCount("topics", "parentID IN("+qlist+")", "") + argList, qlist := common.ForumListToArgQ(visibleForums) + topicCount, err := common.ArgQToTopicCount(argList, qlist) if err != nil { - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - common.LogError(err) - return common.HandledRouteError() - } - defer topicCountStmt.Close() - - var topicCount int - err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) - if err != nil && err != ErrNoRows { - // TODO: Add XML error handling to errors.go - w.WriteHeader(500) - w.Write(xmlInternalError) - common.LogError(err) - return common.HandledRouteError() + return common.InternalErrorXML(err, w, r) } var pageCount = topicCount / sitemapPageCap diff --git a/common/errors.go b/common/errors.go index cc1ad568..79f39ce6 100644 --- a/common/errors.go +++ b/common/errors.go @@ -99,6 +99,26 @@ func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteErr return HandledRouteError() } +var xmlInternalError = []byte(` +A problem has occured`) + +func InternalErrorXML(err error, w http.ResponseWriter, r *http.Request) RouteError { + w.Header().Set("Content-Type", "application/xml") + w.WriteHeader(500) + w.Write(xmlInternalError) + LogError(err) + return HandledRouteError() +} + +// TODO: Stop killing the instance upon hitting an error with InternalError* and deprecate this +func SilentInternalErrorXML(err error, w http.ResponseWriter, r *http.Request) RouteError { + w.Header().Set("Content-Type", "application/xml") + w.WriteHeader(500) + w.Write(xmlInternalError) + log.Print("InternalError: ", err) + return HandledRouteError() +} + func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError { w.WriteHeader(500) pi := Page{"Error", GuestUser, DefaultHeaderVar(), tList, errmsg} diff --git a/common/forum_store.go b/common/forum_store.go index d9177e8b..fb75e931 100644 --- a/common/forum_store.go +++ b/common/forum_store.go @@ -27,6 +27,7 @@ type ForumStore interface { DirtyGet(id int) *Forum Get(id int) (*Forum, error) BypassGet(id int) (*Forum, error) + BulkGetCopy(ids []int) (forums []Forum, err error) Reload(id int) error // ? - Should we move this to ForumCache? It might require us to do some unnecessary casting though //Update(Forum) error Delete(id int) error @@ -188,6 +189,19 @@ func (mfs *MemoryForumStore) BypassGet(id int) (*Forum, error) { return forum, err } +// TODO: Optimise this +func (mfs *MemoryForumStore) BulkGetCopy(ids []int) (forums []Forum, err error) { + forums = make([]Forum, len(ids)) + for i, id := range ids { + forum, err := mfs.Get(id) + if err != nil { + return nil, err + } + forums[i] = forum.Copy() + } + return forums, nil +} + func (mfs *MemoryForumStore) Reload(id int) error { var forum = &Forum{ID: id} err := mfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.ParentID, &forum.ParentType, &forum.TopicCount, &forum.LastTopicID, &forum.LastReplyerID) diff --git a/common/parser.go b/common/parser.go index 52b86ee9..ff051c16 100644 --- a/common/parser.go +++ b/common/parser.go @@ -165,10 +165,10 @@ func shortcodeToUnicode(msg string) string { } func PreparseMessage(msg string) string { - msg = strings.Replace(msg, "


", "\n", -1) - msg = strings.Replace(msg, "

", "\n", -1) + msg = strings.Replace(msg, "


", "\n\n", -1) + msg = strings.Replace(msg, "

", "\n\n", -1) msg = strings.Replace(msg, "

", "", -1) - msg = strings.Replace(msg, "
", "\n", -1) + msg = strings.Replace(msg, "
", "\n\n", -1) if Sshooks["preparse_preassign"] != nil { msg = RunSshook("preparse_preassign", msg) } diff --git a/common/topic_list.go b/common/topic_list.go new file mode 100644 index 00000000..b6282417 --- /dev/null +++ b/common/topic_list.go @@ -0,0 +1,35 @@ +package common + +import "strconv" +import "../query_gen/lib" + +// Internal. Don't rely on it. +func ForumListToArgQ(forums []Forum) (argList []interface{}, qlist string) { + for _, forum := range forums { + argList = append(argList, strconv.Itoa(forum.ID)) + qlist += "?," + } + if qlist != "" { + qlist = qlist[0 : len(qlist)-1] + } + return argList, qlist +} + +// Internal. Don't rely on it. +func ArgQToTopicCount(argList []interface{}, qlist string) (topicCount int, err error) { + topicCountStmt, err := qgen.Builder.SimpleCount("topics", "parentID IN("+qlist+")", "") + if err != nil { + return 0, err + } + defer topicCountStmt.Close() + + err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) + if err != nil && err != ErrNoRows { + return 0, err + } + return topicCount, err +} + +func TopicCountInForums(forums []Forum) (topicCount int, err error) { + return ArgQToTopicCount(ForumListToArgQ(forums)) +} diff --git a/routes.go b/routes.go index e8b00891..1cfdfb01 100644 --- a/routes.go +++ b/routes.go @@ -135,8 +135,6 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo headerVars.Zone = "topics" headerVars.MetaDesc = headerVars.Settings["meta_desc"].(string) - // TODO: Add a function for the qlist stuff - var qlist string group, err := common.Groups.Get(user.Group) if err != nil { log.Printf("Group #%d doesn't exist despite being used by common.User #%d", user.Group, user.ID) @@ -156,39 +154,28 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo // We need a list of the visible forums for Quick Topic var forumList []common.Forum - var argList []interface{} - for _, fid := range canSee { forum := common.Forums.DirtyGet(fid) if forum.Name != "" && forum.Active { // This bit's for quick topic, as we don't want unbound forums (e.g. ones in plugin_socialgroups) showing up + // ? - Would it be useful, if we could post in social groups from /topics/? if (forum.ParentType == "" || forum.ParentType == "forum") && user.Loggedin { fcopy := forum.Copy() // TODO: Add a hook here for plugin_guilds forumList = append(forumList, fcopy) } - // ? - Should we be showing plugin_guilds posts on /topics/? - // ? - Would it be useful, if we could post in social groups from /topics/? - argList = append(argList, strconv.Itoa(fid)) - qlist += "?," } } + // ? - Should we be showing plugin_guilds posts on /topics/? + argList, qlist := common.ForumListToArgQ(forumList) + // ! Need an inline error not a page level error if qlist == "" { return common.NotFound(w, r) } - qlist = qlist[0 : len(qlist)-1] - // TODO: Abstract this - topicCountStmt, err := qgen.Builder.SimpleCount("topics", "parentID IN("+qlist+")", "") - if err != nil { - return common.InternalError(err, w, r) - } - defer topicCountStmt.Close() - - var topicCount int - err = topicCountStmt.QueryRow(argList...).Scan(&topicCount) + topicCount, err := common.ArgQToTopicCount(argList, qlist) if err != nil { return common.InternalError(err, w, r) } @@ -304,7 +291,6 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s if ferr != nil { return ferr } - if !user.Perms.ViewTopic { return common.NoPermissions(w, r, user) } diff --git a/themes/cosora/public/main.css b/themes/cosora/public/main.css index b57df627..f4e73676 100644 --- a/themes/cosora/public/main.css +++ b/themes/cosora/public/main.css @@ -580,11 +580,10 @@ select, input, textarea, button { display: inline-block; } .topic_list .rowtopic span { - max-width: 112px; + max-width: 162px; overflow: hidden; color: var(--primary-text-color); } - .topic_list .rowsmall { font-size: 15px; } @@ -596,17 +595,9 @@ select, input, textarea, button { font-size: 15px; } -.topic_list .rowsmall.starter:before { - content: "\f007"; - font: normal normal normal 14px/1 FontAwesome; - margin-right: 5px; - font-size: 15px; -} - .topic_list .lastReplyAt { font-size: 14px; } - .topic_list .topic_status_e { display: none; } @@ -615,7 +606,6 @@ select, input, textarea, button { flex: 1 1 calc(100% - 380px); border-right: none; } - .topic_inner_right { margin-left: 15%; margin-right: auto; @@ -633,12 +623,9 @@ select, input, textarea, button { .topic_inner_right { margin-top: 12px; } - .topic_inner_right span { - /*font-size: 15px;*/ font-size: 16px; } - .topic_inner_right span:after { font-size: 13.5px; } @@ -656,7 +643,6 @@ select, input, textarea, button { content: var(--likes-lang-string); color: var(--lightened-primary-text-color); } - .parent_forum { color: var(--lightened-primary-text-color); } @@ -684,7 +670,7 @@ select, input, textarea, button { margin-top: 12px; margin-left: 8px; margin-bottom: 14px; - width: 240px; + width: 220px; } .topic_right > span { margin-top: 12px; @@ -698,7 +684,7 @@ select, input, textarea, button { background-color: hsl(81, 60%, 95%); } -@element .topic_left .rowtopic and (min-width: 110px) { +@element .topic_left .rowtopic and (min-width: 160px) { $this, $this span, $this + .parent_forum { float: left; } @@ -712,6 +698,18 @@ select, input, textarea, button { } } +@element .topic_list and (min-width: 738px) { + .topic_left .topic_inner_left { + width: calc(240px + 1%); + } +} + +@element .topic_list and (min-width: 875px) { + .topic_left .topic_inner_left { + width: calc(240px + 10%); + } +} + .forum_list, .post_container { border: none; } @@ -778,6 +776,9 @@ select, input, textarea, button { .userinfo .tag_block { color: var(--extra-lightened-primary-text-color); } +.post_item .user_content { + margin-bottom: 10px; +} .button_container { margin-top: auto; display: flex; diff --git a/themes/cosora/public/panel.css b/themes/cosora/public/panel.css index 8ad5abc3..f5248a38 100644 --- a/themes/cosora/public/panel.css +++ b/themes/cosora/public/panel.css @@ -77,10 +77,41 @@ .formlist .formitem { padding: 8px; } -#forum_quick_perms .panel_floater, .panel_theme_mobile, .panel_theme_tag { display: none; } #panel_plugins .rowitem { display: block; +} + +#forum_quick_perms .formitem { + display: flex; +} +#forum_quick_perms .formitem .edit_fields { + margin-left: 3px; + margin-top: 1px; +} +.perm_preset_no_access:before { + content: "No Access"; + color: hsl(0,100%,20%); +} +.perm_preset_read_only:before, .perm_preset_can_post:before { + color: hsl(120,100%,20%); +} +.perm_preset_read_only:before { + content: "Read Only"; +} +.perm_preset_can_post:before { + content: "Can Post"; +} +.perm_preset_can_moderate:before { + content: "Can Moderate"; + color: hsl(240,100%,20%); +} +.perm_preset_custom:before { + content: "Custom"; + color: hsl(0,0%,20%); +} +.perm_preset_default:before { + content: "Default"; } \ No newline at end of file