From 30de658e158c03eb918b15cf70994256d2a47337 Mon Sep 17 00:00:00 2001 From: Azareal Date: Fri, 11 Oct 2019 10:36:08 +1000 Subject: [PATCH] Experiment with rehoming the plugins. Shorten more things and eliminate unnecessary bytes. --- .../plugin_adventure.go | 12 +- plugin_bbcode.go => extend/plugin_bbcode.go | 17 +- extend/plugin_discord.go | 218 ++++++++++++++++ extend/plugin_gallery.go | 26 ++ .../plugin_heythere.go | 2 +- extend/plugin_hyperdrive.go | 241 ++++++++++++++++++ .../plugin_markdown.go | 35 ++- .../plugin_skeleton.go | 2 +- general_test.go | 7 +- main.go | 1 + plugin_test.go | 47 +--- routes/panel/groups.go | 4 +- templates/forum.html | 2 +- templates/forums.html | 4 +- templates/guilds_guild_list.html | 10 +- templates/password_reset_token.html | 2 +- templates/topic_c_edit_post.html | 2 +- templates/topic_poll.html | 2 +- templates/widget_menu.html | 4 +- templates/widget_online.html | 2 +- 20 files changed, 553 insertions(+), 87 deletions(-) rename plugin_adventure.go => extend/plugin_adventure.go (66%) rename plugin_bbcode.go => extend/plugin_bbcode.go (96%) create mode 100644 extend/plugin_discord.go create mode 100644 extend/plugin_gallery.go rename plugin_heythere.go => extend/plugin_heythere.go (98%) create mode 100644 extend/plugin_hyperdrive.go rename plugin_markdown.go => extend/plugin_markdown.go (93%) rename plugin_skeleton.go => extend/plugin_skeleton.go (99%) diff --git a/plugin_adventure.go b/extend/plugin_adventure.go similarity index 66% rename from plugin_adventure.go rename to extend/plugin_adventure.go index 3c117d97..3356c831 100644 --- a/plugin_adventure.go +++ b/extend/plugin_adventure.go @@ -1,10 +1,10 @@ // WIP - Experimental adventure plugin, this might find a new home soon, but it's here to stress test Gosora's extensibility for now -package main +package extend -import "github.com/Azareal/Gosora/common" +import c "github.com/Azareal/Gosora/common" func init() { - common.Plugins.Add(&common.Plugin{ + c.Plugins.Add(&c.Plugin{ UName: "adventure", Name: "Adventure", Tag: "WIP", @@ -16,14 +16,14 @@ func init() { }) } -func initAdventure(plugin *common.Plugin) error { +func initAdventure(plugin *c.Plugin) error { return nil } // TODO: Change the signature to return an error? -func deactivateAdventure(plugin *common.Plugin) { +func deactivateAdventure(plugin *c.Plugin) { } -func installAdventure(plugin *common.Plugin) error { +func installAdventure(plugin *c.Plugin) error { return nil } diff --git a/plugin_bbcode.go b/extend/plugin_bbcode.go similarity index 96% rename from plugin_bbcode.go rename to extend/plugin_bbcode.go index 96f1aceb..0a7f012f 100644 --- a/plugin_bbcode.go +++ b/extend/plugin_bbcode.go @@ -1,4 +1,4 @@ -package main +package extend import ( "bytes" @@ -26,11 +26,11 @@ var bbcodeQuotes *regexp.Regexp var bbcodeCode *regexp.Regexp func init() { - c.Plugins.Add(&c.Plugin{UName: "bbcode", Name: "BBCode", Author: "Azareal", URL: "https://github.com/Azareal", Init: initBbcode, Deactivate: deactivateBbcode}) + c.Plugins.Add(&c.Plugin{UName: "bbcode", Name: "BBCode", Author: "Azareal", URL: "https://github.com/Azareal", Init: InitBbcode, Deactivate: deactivateBbcode}) } -func initBbcode(plugin *c.Plugin) error { - plugin.AddHook("parse_assign", bbcodeFullParse) +func InitBbcode(plugin *c.Plugin) error { + plugin.AddHook("parse_assign", BbcodeFullParse) bbcodeInvalidNumber = []byte("[Invalid Number]") bbcodeNoNegative = []byte("[No Negative Numbers]") @@ -52,10 +52,10 @@ func initBbcode(plugin *c.Plugin) error { } func deactivateBbcode(plugin *c.Plugin) { - plugin.RemoveHook("parse_assign", bbcodeFullParse) + plugin.RemoveHook("parse_assign", BbcodeFullParse) } -func bbcodeRegexParse(msg string) string { +func BbcodeRegexParse(msg string) string { msg = bbcodeBold.ReplaceAllString(msg, "$1") msg = bbcodeItalic.ReplaceAllString(msg, "$1") msg = bbcodeUnderline.ReplaceAllString(msg, "$1") @@ -118,11 +118,10 @@ func bbcodeSimpleParse(msg string) string { } // Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere -func bbcodeParseWithoutCode(msg string) string { +func BbcodeParseWithoutCode(msg string) string { var hasU, hasB, hasI, hasS bool var complexBbc bool msgbytes := []byte(msg) - for i := 0; (i + 3) < len(msgbytes); i++ { if msgbytes[i] == '[' { if msgbytes[i+2] != ']' { @@ -207,7 +206,7 @@ func bbcodeParseWithoutCode(msg string) string { } // Does every type of BBCode -func bbcodeFullParse(msg string) string { +func BbcodeFullParse(msg string) string { var hasU, hasB, hasI, hasS, hasC bool var complexBbc bool diff --git a/extend/plugin_discord.go b/extend/plugin_discord.go new file mode 100644 index 00000000..0b5c7c66 --- /dev/null +++ b/extend/plugin_discord.go @@ -0,0 +1,218 @@ +package extend + +import ( + "bytes" + "encoding/json" + "errors" + "io/ioutil" + "log" + "net" + "net/http" + "strconv" + "strings" + "time" + + c "github.com/Azareal/Gosora/common" +) + +func init() { + c.Plugins.Add(&c.Plugin{UName: "discord", Name: "Discord", Author: "Azareal", Init: discordInit, Activate: discordActivate, Deactivate: discordDeactivate}) +} + +func discordValidate() error { + webhook, ok := c.PluginConfig["DiscordWebhook"] + if !ok || webhook == "" { + return errors.New("You need to set a webhook to push to in config.json") + } + + ev := c.PluginConfig["DiscordEvents"] + if ev != "" && ev != "threads" && ev != "replies" { + return errors.New("Invalid value for DiscordEvents. Can only be blank, 'threads' or 'replies'") + } + + fidsRaw := c.PluginConfig["DiscordForums"] + if fidsRaw != "" { + for _, fidRaw := range strings.Split(fidsRaw, ",") { + _, err := strconv.Atoi(fidRaw) + if err != nil { + return errors.New("Invalid integer found in DiscordForums") + } + } + } + + return nil +} + +func discordInit(plugin *c.Plugin) error { + err := discordValidate() + if err != nil { + return err + } + plugin.AddHook("action_end_create_topic", discordEventTopic) + plugin.AddHook("action_end_create_reply", discordEventReply) + return nil +} + +// A bit of validation to make sure the admin isn't forgetting something or telling Plugin Discord to do something absurd +func discordActivate(plugin *c.Plugin) error { + return discordValidate() +} + +func discordDeactivate(plugin *c.Plugin) { + plugin.RemoveHook("action_end_create_topic", discordEventTopic) + plugin.RemoveHook("action_end_create_reply", discordEventReply) +} + +func discordEventTopic(args ...interface{}) (skip bool, rerr c.RouteError) { + discordEvent(0, args[0].(int)) + return false, nil +} +func discordEventReply(args ...interface{}) (skip bool, rerr c.RouteError) { + discordEvent(1, args[0].(int)) + return false, nil +} + +type DiscordData struct { + Username string `json:"username"` + Embeds []DiscordEmbed `json:"embeds"` +} + +type DiscordEmbed struct { + Title string `json:"title"` + Desc string `json:"description"` + URL string `json:"url"` + Author DiscordEmbedAuthor `json:"author"` +} + +type DiscordEmbedAuthor struct { + Name string `json:"name"` + URL string `json:"url"` + Avatar string `json:"icon_url"` +} + +func discordEvent(typ int, id int) { + //fmt.Println("in discordEvent") + ev := c.PluginConfig["DiscordEvents"] + if (ev == "threads" && typ != 0) || (ev == "replies" && typ != 1) { + return + } + + var content, url string + var topic *c.Topic + var err error + var createdBy int + if typ == 0 { + topic, err = c.Topics.Get(id) + if err != nil { + return + } + content = topic.Content + createdBy = topic.CreatedBy + } else { + reply, err := c.Rstore.Get(id) + if err != nil { + return + } + content = reply.Content + createdBy = reply.CreatedBy + + topic, err = reply.Topic() + if err != nil { + return + } + } + url = topic.Link + + user, err := c.Users.Get(createdBy) + if err != nil { + return + } + + fidsRaw := c.PluginConfig["DiscordForums"] + if fidsRaw != "" { + var hasForum = false + for _, fidRaw := range strings.Split(fidsRaw, ",") { + fid, err := strconv.Atoi(fidRaw) + if err != nil { + return + } + if fid == topic.ParentID { + hasForum = true + } + } + if !hasForum { + return + } + } + if len(content) > 100 { + content = content[:97] + "..." + } + + var client = &http.Client{ + Timeout: time.Second * 10, + Transport: &http.Transport{ + Dial: (&net.Dialer{Timeout: 5 * time.Second}).Dial, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + var s string + if c.Site.EnableSsl { + s = "s" + } + var preURL = "http" + s + "://" + c.Site.URL + + var avatar = user.MicroAvatar + if len(user.MicroAvatar) > 1 { + if user.MicroAvatar[0] == '/' && user.MicroAvatar[1] != '/' { + avatar = preURL + avatar + } + } + + author := DiscordEmbedAuthor{Name: user.Name, URL: preURL + user.Link, Avatar: avatar} + embed := DiscordEmbed{Title: topic.Title, Desc: content, URL: preURL + url, Author: author} + dat := DiscordData{Username: c.Site.Name, Embeds: []DiscordEmbed{embed}} + data, err := json.Marshal(dat) + if err != nil { + c.LogWarning(err) + return + } + + //fmt.Println("before discord push") + resp, err := client.Post(c.PluginConfig["DiscordWebhook"], "application/json", bytes.NewBuffer(data)) + var body string + var respErr = func(err error) { + log.Printf("Sent: %+v\n", string(data)) + log.Printf("Response: %+v\n", resp) + if body != "" { + log.Printf("Response Body: %+v\n", body) + } + c.LogWarning(err) + } + + if err != nil { + respErr(err) + return + } + defer resp.Body.Close() + + // TODO: Cap the amount we read + bBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + respErr(err) + return + } + body = string(bBody) + + if resp.StatusCode != 200 { + respErr(err) + return + } + + c.DebugLog("Pushed event to Discord") + c.DebugLogf("Sent: %+v\n", string(data)) + c.DebugLogf("Response: %+v\n", resp) + c.DebugLogf("Response Body: %+v\n", body) +} + +// TODO: Add a settings page or something? diff --git a/extend/plugin_gallery.go b/extend/plugin_gallery.go new file mode 100644 index 00000000..a1e87f3e --- /dev/null +++ b/extend/plugin_gallery.go @@ -0,0 +1,26 @@ +package extend + +import c "github.com/Azareal/Gosora/common" + +func init() { + c.Plugins.Add(&c.Plugin{UName: "gallery", Name: "Gallery", Author: "Azareal", URL: "https://github.com/Azareal", Init: initGallery, Deactivate: deactivateGallery}) +} + +// init_heythere is separate from init() as we don't want the plugin to run if the plugin is disabled +func initGallery(plugin *c.Plugin) error { + plugin.AddHook("topic_reply_row_assign", galleryReply) + return nil +} + +func deactivateGallery(plugin *c.Plugin) { + plugin.RemoveHook("topic_reply_row_assign", galleryReply) +} + +func galleryReply(data ...interface{}) interface{} { + currentUser := data[0].(*c.TopicPage).Header.CurrentUser + reply := data[1].(*c.ReplyUser) + reply.Content = "Hey there, " + currentUser.Name + "!" + reply.ContentHtml = "Hey there, " + currentUser.Name + "!" + reply.Tag = "Auto" + return nil +} diff --git a/plugin_heythere.go b/extend/plugin_heythere.go similarity index 98% rename from plugin_heythere.go rename to extend/plugin_heythere.go index 04f03b6c..c86a653c 100644 --- a/plugin_heythere.go +++ b/extend/plugin_heythere.go @@ -1,4 +1,4 @@ -package main +package extend import c "github.com/Azareal/Gosora/common" diff --git a/extend/plugin_hyperdrive.go b/extend/plugin_hyperdrive.go new file mode 100644 index 00000000..321f053d --- /dev/null +++ b/extend/plugin_hyperdrive.go @@ -0,0 +1,241 @@ +// Highly experimental plugin for caching rendered pages for guests +package extend + +import ( + //"log" + "bytes" + "errors" + "strings" + "strconv" + "time" + "sync/atomic" + "net/http" + "net/http/httptest" + + c "github.com/Azareal/Gosora/common" + "github.com/Azareal/Gosora/routes" +) + +var hyperspace *Hyperspace + +func init() { + c.Plugins.Add(&c.Plugin{UName: "hyperdrive", Name: "Hyperdrive", Author: "Azareal", Init: initHdrive, Deactivate: deactivateHdrive}) +} + +func initHdrive(plugin *c.Plugin) error { + hyperspace = newHyperspace() + plugin.AddHook("tasks_tick_topic_list",tickHdrive) + plugin.AddHook("tasks_tick_widget_wol",tickHdriveWol) + plugin.AddHook("route_topic_list_start",jumpHdriveTopicList) + plugin.AddHook("route_forum_list_start",jumpHdriveForumList) + tickHdrive() + return nil +} + +func deactivateHdrive(plugin *c.Plugin) { + plugin.RemoveHook("tasks_tick_topic_list",tickHdrive) + plugin.RemoveHook("tasks_tick_widget_wol",tickHdriveWol) + plugin.RemoveHook("route_topic_list_start",jumpHdriveTopicList) + plugin.RemoveHook("route_forum_list_start",jumpHdriveForumList) + hyperspace = nil +} + +type Hyperspace struct { + topicList atomic.Value + gzipTopicList atomic.Value + forumList atomic.Value + gzipForumList atomic.Value + lastTopicListUpdate atomic.Value +} + +func newHyperspace() *Hyperspace { + pageCache := new(Hyperspace) + blank := make(map[string][]byte,len(c.Themes)) + pageCache.topicList.Store(blank) + pageCache.gzipTopicList.Store(blank) + pageCache.forumList.Store(blank) + pageCache.gzipForumList.Store(blank) + pageCache.lastTopicListUpdate.Store(int64(0)) + return pageCache +} + +func tickHdriveWol(args ...interface{}) (skip bool, rerr c.RouteError) { + c.DebugLog("docking at wol") + return tickHdrive(args) +} + +// TODO: Find a better way of doing this +func tickHdrive(args ...interface{}) (skip bool, rerr c.RouteError) { + c.DebugLog("Refueling...") + + // Avoid accidentally caching already cached content + blank := make(map[string][]byte,len(c.Themes)) + hyperspace.topicList.Store(blank) + hyperspace.gzipTopicList.Store(blank) + hyperspace.forumList.Store(blank) + hyperspace.gzipForumList.Store(blank) + + tListMap := make(map[string][]byte) + gtListMap := make(map[string][]byte) + fListMap := make(map[string][]byte) + gfListMap := make(map[string][]byte) + + var cacheTheme = func(tname string) (skip bool, fail bool, rerr c.RouteError) { + + themeCookie := http.Cookie{Name: "current_theme", Value: tname, Path: "/", MaxAge: c.Year} + + w := httptest.NewRecorder() + req := httptest.NewRequest("get", "/topics/", bytes.NewReader(nil)) + req.AddCookie(&themeCookie) + user := c.GuestUser + + head, rerr := c.UserCheck(w, req, &user) + if rerr != nil { + return true, true, rerr + } + + rerr = routes.TopicList(w, req, user, head) + if rerr != nil { + return true, true, rerr + } + if w.Code != 200 { + c.LogWarning(errors.New("not 200 for topic list in hyperdrive")) + return false, true, nil + } + + buf := new(bytes.Buffer) + buf.ReadFrom(w.Result().Body) + tListMap[tname] = buf.Bytes() + + gbuf, err := c.CompressBytesGzip(buf.Bytes()) + if err != nil { + c.LogWarning(err) + return false, true, nil + } + gtListMap[tname] = gbuf + + w = httptest.NewRecorder() + req = httptest.NewRequest("get", "/forums/", bytes.NewReader(nil)) + user = c.GuestUser + + head, rerr = c.UserCheck(w, req, &user) + if rerr != nil { + return true, true, rerr + } + + rerr = routes.ForumList(w, req, user, head) + if rerr != nil { + return true, true, rerr + } + if w.Code != 200 { + c.LogWarning(errors.New("not 200 for forum list in hyperdrive")) + return false, true, nil + } + + buf = new(bytes.Buffer) + buf.ReadFrom(w.Result().Body) + fListMap[tname] = buf.Bytes() + + gbuf, err = c.CompressBytesGzip(buf.Bytes()) + if err != nil { + c.LogWarning(err) + return false, true, nil + } + gfListMap[tname] = gbuf + return false, false, nil + } + + for tname, _ := range c.Themes { + skip, fail, rerr := cacheTheme(tname) + if fail || rerr != nil { + return skip, rerr + } + } + + hyperspace.topicList.Store(tListMap) + hyperspace.gzipTopicList.Store(gtListMap) + hyperspace.forumList.Store(fListMap) + hyperspace.gzipForumList.Store(gfListMap) + hyperspace.lastTopicListUpdate.Store(time.Now().Unix()) + + return false, nil +} + +func jumpHdriveTopicList(args ...interface{}) (skip bool, rerr c.RouteError) { + theme := c.GetThemeByReq(args[1].(*http.Request)) + p := hyperspace.topicList.Load().(map[string][]byte) + pg := hyperspace.gzipTopicList.Load().(map[string][]byte) + return jumpHdrive(pg[theme.Name], p[theme.Name], args) +} + +func jumpHdriveForumList(args ...interface{}) (skip bool, rerr c.RouteError) { + theme := c.GetThemeByReq(args[1].(*http.Request)) + p := hyperspace.forumList.Load().(map[string][]byte) + pg := hyperspace.gzipForumList.Load().(map[string][]byte) + return jumpHdrive(pg[theme.Name], p[theme.Name], args) +} + +func jumpHdrive(pg []byte, p []byte, args []interface{}) (skip bool, rerr c.RouteError) { + var tList []byte + w := args[0].(http.ResponseWriter) + var iw http.ResponseWriter + gzw, ok := w.(c.GzipResponseWriter) + if ok { + tList = pg + iw = gzw.ResponseWriter + } else { + tList = p + iw = w + } + if len(tList) == 0 { + c.DebugLog("no itemlist in hyperspace") + return false, nil + } + //c.DebugLog("tList: ", tList) + + // Avoid intercepting user requests as we only have guests in cache right now + user := args[2].(*c.User) + if user.ID != 0 { + c.DebugLog("not guest") + return false, nil + } + + // Avoid intercepting search requests and filters as we don't have those in cache + r := args[1].(*http.Request) + //c.DebugLog("r.URL.Path:",r.URL.Path) + //c.DebugLog("r.URL.RawQuery:",r.URL.RawQuery) + if r.URL.RawQuery != "" { + return false, nil + } + if r.FormValue("js") == "1" { + return false, nil + } + //c.DebugLog + c.DebugLog("Successful jump") + + var etag string + lastUpdate := hyperspace.lastTopicListUpdate.Load().(int64) + c.DebugLog("lastUpdate:",lastUpdate) + if ok { + iw.Header().Set("X-I","1") + etag = "\""+strconv.FormatInt(lastUpdate, 10)+"-g\"" + } else { + etag = "\""+strconv.FormatInt(lastUpdate, 10)+"\"" + } + + if lastUpdate != 0 { + iw.Header().Set("ETag", etag) + if match := r.Header.Get("If-None-Match"); match != "" { + if strings.Contains(match, etag) { + iw.WriteHeader(http.StatusNotModified) + return true, nil + } + } + } + + header := args[3].(*c.Header) + routes.FootHeaders(w, header) + iw.Write(tList) + + return true, nil +} \ No newline at end of file diff --git a/plugin_markdown.go b/extend/plugin_markdown.go similarity index 93% rename from plugin_markdown.go rename to extend/plugin_markdown.go index eef85d6f..1a404a87 100644 --- a/plugin_markdown.go +++ b/extend/plugin_markdown.go @@ -1,4 +1,4 @@ -package main +package extend import ( "strings" @@ -23,11 +23,11 @@ var markdownH1TagOpen []byte var markdownH1TagClose []byte func init() { - c.Plugins.Add(&c.Plugin{UName: "markdown", Name: "Markdown", Author: "Azareal", URL: "https://github.com/Azareal", Init: initMarkdown, Deactivate: deactivateMarkdown}) + c.Plugins.Add(&c.Plugin{UName: "markdown", Name: "Markdown", Author: "Azareal", URL: "https://github.com/Azareal", Init: InitMarkdown, Deactivate: deactivateMarkdown}) } -func initMarkdown(plugin *c.Plugin) error { - plugin.AddHook("parse_assign", markdownParse) +func InitMarkdown(plugin *c.Plugin) error { + plugin.AddHook("parse_assign", MarkdownParse) markdownUnclosedElement = []byte("[Unclosed Element]") @@ -47,12 +47,12 @@ func initMarkdown(plugin *c.Plugin) error { } func deactivateMarkdown(plugin *c.Plugin) { - plugin.RemoveHook("parse_assign", markdownParse) + plugin.RemoveHook("parse_assign", MarkdownParse) } // An adapter for the parser, so that the parser can call itself recursively. // This is less for the simple Markdown elements like bold and italics and more for the really complicated ones I plan on adding at some point. -func markdownParse(msg string) string { +func MarkdownParse(msg string) string { msg = _markdownParse(msg+" ", 0) if msg[len(msg)-1] == ' ' { msg = msg[:len(msg)-1] @@ -68,12 +68,12 @@ func _markdownParse(msg string, n int) string { var outbytes []byte var lastElement int - var breaking = false + breaking := false c.DebugLogf("Initial Message: %+v\n", strings.Replace(msg, "\r", "\\r", -1)) for index := 0; index < len(msg); index++ { - var simpleMatch = func(char byte, o []byte, c []byte) { - var startIndex = index + simpleMatch := func(char byte, o []byte, c []byte) { + startIndex := index if (index + 1) >= len(msg) { breaking = true return @@ -100,8 +100,8 @@ func _markdownParse(msg string, n int) string { index-- } - var startLine = func() { - var startIndex = index + startLine := func() { + startIndex := index if (index + 1) >= len(msg) /*|| (index + 2) >= len(msg)*/ { breaking = true return @@ -152,9 +152,9 @@ func _markdownParse(msg string, n int) string { break } case '*': - var startIndex = index - var italic = true - var bold = false + startIndex := index + italic := true + bold := false if (index + 2) < len(msg) { if msg[index+1] == '*' { bold = true @@ -178,7 +178,7 @@ func _markdownParse(msg string, n int) string { break } - var preBreak = func() { + preBreak := func() { outbytes = append(outbytes, msg[lastElement:startIndex]...) lastElement = startIndex } @@ -317,7 +317,7 @@ func markdownSkipUntilNotChar(data string, index int, char byte) int { } func markdownSkipUntilStrongSpace(data string, index int) int { - var inSpace = false + inSpace := false for ; index < len(data); index++ { if inSpace && data[index] == 32 { index-- @@ -351,8 +351,7 @@ SwitchLoop: // plugin_markdown doesn't support lists yet, but I want it to be easy to have nested lists when we do have them func markdownSkipList(data string, index int) int { var lastNewline int - var datalen = len(data) - + datalen := len(data) for ; index < datalen; index++ { SkipListInnerLoop: if data[index] == 10 { diff --git a/plugin_skeleton.go b/extend/plugin_skeleton.go similarity index 99% rename from plugin_skeleton.go rename to extend/plugin_skeleton.go index 191465fc..bee024b0 100644 --- a/plugin_skeleton.go +++ b/extend/plugin_skeleton.go @@ -1,4 +1,4 @@ -package main +package extend import c "github.com/Azareal/Gosora/common" diff --git a/general_test.go b/general_test.go index 62659ac2..56b1f219 100644 --- a/general_test.go +++ b/general_test.go @@ -15,6 +15,7 @@ import ( "github.com/pkg/errors" c "github.com/Azareal/Gosora/common" + e "github.com/Azareal/Gosora/extend" "github.com/Azareal/Gosora/install" "github.com/Azareal/Gosora/query_gen" "github.com/Azareal/Gosora/routes" @@ -969,7 +970,7 @@ func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) { f := func(name string, msg string) { b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - _ = bbcodeRegexParse(msg) + _ = e.BbcodeRegexParse(msg) } }) } @@ -989,7 +990,7 @@ func BenchmarkBBCodePluginWithoutCodeTagSerial(b *testing.B) { f := func(name string, msg string) { b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - _ = bbcodeParseWithoutCode(msg) + _ = e.BbcodeParseWithoutCode(msg) } }) } @@ -1009,7 +1010,7 @@ func BenchmarkBBCodePluginWithFullParserSerial(b *testing.B) { f := func(name string, msg string) { b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { - _ = bbcodeFullParse(msg) + _ = e.BbcodeFullParse(msg) } }) } diff --git a/main.go b/main.go index 8b8b0fef..df22f294 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ import ( "time" c "github.com/Azareal/Gosora/common" + _ "github.com/Azareal/Gosora/extend" co "github.com/Azareal/Gosora/common/counters" p "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" diff --git a/plugin_test.go b/plugin_test.go index a2bf52db..38a2ca59 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -5,6 +5,7 @@ import ( "testing" c "github.com/Azareal/Gosora/common" + e "github.com/Azareal/Gosora/extend" ) // go test -v @@ -26,8 +27,7 @@ func (l *MEPairList) Add(msg string, expects string) { func TestBBCodeRender(t *testing.T) { //t.Skip() - err := initBbcode(c.Plugins["bbcode"]) - if err != nil { + if err := e.InitBbcode(c.Plugins["bbcode"]); err != nil { t.Fatal(err) } @@ -75,7 +75,7 @@ func TestBBCodeRender(t *testing.T) { t.Log("Testing bbcodeFullParse") for _, item := range l.Items { - res = bbcodeFullParse(item.Msg) + res = e.BbcodeFullParse(item.Msg) if res != item.Expects { t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") @@ -85,7 +85,7 @@ func TestBBCodeRender(t *testing.T) { f := func(msg, expects string) { t.Log("Testing string '" + msg + "'") - res := bbcodeFullParse(msg) + res := e.BbcodeFullParse(msg) if res != expects { t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+expects+"'") @@ -101,7 +101,7 @@ func TestBBCodeRender(t *testing.T) { msg := "[rand]1[/rand]" t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) conv, err := strconv.Atoi(res) if err != nil || (conv > 1 || conv < 0) { t.Error("Bad output:", "'"+res+"'") @@ -110,7 +110,7 @@ func TestBBCodeRender(t *testing.T) { msg = "[rand]0[/rand]" t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) conv, err = strconv.Atoi(res) if err != nil || conv != 0 { t.Error("Bad output:", "'"+res+"'") @@ -119,7 +119,7 @@ func TestBBCodeRender(t *testing.T) { msg = "[rand]2147483647[/rand]" // Signed 32-bit MAX t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) conv, err = strconv.Atoi(res) if err != nil || (conv > 2147483647 || conv < 0) { t.Error("Bad output:", "'"+res+"'") @@ -128,7 +128,7 @@ func TestBBCodeRender(t *testing.T) { msg = "[rand]9223372036854775807[/rand]" // Signed 64-bit MAX t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) conv, err = strconv.Atoi(res) if err != nil || (conv > 9223372036854775807 || conv < 0) { t.Error("Bad output:", "'"+res+"'") @@ -138,7 +138,7 @@ func TestBBCodeRender(t *testing.T) { // Note: conv is commented out in these two, as these numbers overflow int msg = "[rand]18446744073709551615[/rand]" // Unsigned 64-bit MAX t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) _, err = strconv.Atoi(res) if err != nil && res != "[Invalid Number][rand]18446744073709551615[/rand]" { t.Error("Bad output:", "'"+res+"'") @@ -146,7 +146,7 @@ func TestBBCodeRender(t *testing.T) { } msg = "[rand]170141183460469231731687303715884105727[/rand]" // Signed 128-bit MAX t.Log("Testing string '" + msg + "'") - res = bbcodeFullParse(msg) + res = e.BbcodeFullParse(msg) _, err = strconv.Atoi(res) if err != nil && res != "[Invalid Number][rand]170141183460469231731687303715884105727[/rand]" { t.Error("Bad output:", "'"+res+"'") @@ -166,8 +166,7 @@ func TestBBCodeRender(t *testing.T) { func TestMarkdownRender(t *testing.T) { //t.Skip() - err := initMarkdown(c.Plugins["markdown"]) - if err != nil { + if err := e.InitMarkdown(c.Plugins["markdown"]); err != nil { t.Fatal(err) } @@ -251,7 +250,7 @@ func TestMarkdownRender(t *testing.T) { l.Add("*-你好-*", "-你好-") // TODO: More of these Unicode tests? Emoji, Chinese, etc.? for _, item := range l.Items { - if res := markdownParse(item.Msg); res != item.Expects { + if res := e.MarkdownParse(item.Msg); res != item.Expects { t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") //t.Error("Ouput in bytes:", []byte(res)) @@ -260,7 +259,7 @@ func TestMarkdownRender(t *testing.T) { } for _, item := range l2.Items { - if res := markdownParse(item.Msg); res != item.Expects { + if res := e.MarkdownParse(item.Msg); res != item.Expects { t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") //t.Error("Ouput in bytes:", []byte(res)) @@ -268,26 +267,8 @@ func TestMarkdownRender(t *testing.T) { } } - /*for _, item := range l.Items { - if res := markdownParse("\n" + item.Msg); res != "\n"+item.Expects { - t.Error("Testing string '\n" + item.Msg + "'") - t.Error("Bad output:", "'"+res+"'") - //t.Error("Ouput in bytes:", []byte(res)) - t.Error("Expected:", "'\n"+item.Expects+"'") - } - } - for _, item := range l.Items { - if res := markdownParse("\t" + item.Msg); res != "\t"+item.Expects { - t.Error("Testing string '\t" + item.Msg + "'") - t.Error("Bad output:", "'"+res+"'") - //t.Error("Ouput in bytes:", []byte(res)) - t.Error("Expected:", "'\t"+item.Expects+"'") - } - }*/ - - for _, item := range l.Items { - if res := markdownParse("d" + item.Msg); res != "d"+item.Expects { + if res := e.MarkdownParse("d" + item.Msg); res != "d"+item.Expects { t.Error("Testing string 'd" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") //t.Error("Ouput in bytes:", []byte(res)) diff --git a/routes/panel/groups.go b/routes/panel/groups.go index 4b69798d..3aee3c4f 100644 --- a/routes/panel/groups.go +++ b/routes/panel/groups.go @@ -31,7 +31,7 @@ func Groups(w http.ResponseWriter, r *http.Request, u c.User) c.RouteError { } var rank string var rankClass string - var canDelete = false + canDelete := false // TODO: Localise this switch { @@ -202,7 +202,7 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c return c.LocalError("to must be integer", w, r, user) } if from == to { - return c.LocalError("the from group and to group cannot be the same",w,r,user) + return c.LocalError("the from group and to group cannot be the same", w, r, user) } twoWay := r.FormValue("two-way") == "1" diff --git a/templates/forum.html b/templates/forum.html index 3bd9c0fd..7a008867 100644 --- a/templates/forum.html +++ b/templates/forum.html @@ -84,4 +84,4 @@ {{template "paginator.html" . }} -{{template "footer.html" . }} +{{template "footer.html" . }} \ No newline at end of file diff --git a/templates/forums.html b/templates/forums.html index 861d215a..2b750087 100644 --- a/templates/forums.html +++ b/templates/forums.html @@ -22,10 +22,10 @@ {{if .LastTopicTime}}
{{.LastTopicTime}}{{end}} -
+
{{else}}
{{lang "forums_no_forums"}}
{{end}} -{{template "footer.html" . }} +{{template "footer.html" . }} \ No newline at end of file diff --git a/templates/guilds_guild_list.html b/templates/guilds_guild_list.html index aeb7342f..96093b1e 100644 --- a/templates/guilds_guild_list.html +++ b/templates/guilds_guild_list.html @@ -5,17 +5,17 @@
{{range .GuildList}}
- + {{.Name}}
{{.Desc}}
- - {{.MemberCount}} members + + {{.MemberCount}} members
{{.LastUpdateTime}}
-
+
{{else}}
There aren't any visible guilds.
{{end}}
-{{template "footer.html" . }} +{{template "footer.html" . }} \ No newline at end of file diff --git a/templates/password_reset_token.html b/templates/password_reset_token.html index dcdc2819..31575673 100644 --- a/templates/password_reset_token.html +++ b/templates/password_reset_token.html @@ -27,4 +27,4 @@ -{{template "footer.html" . }} +{{template "footer.html" . }} \ No newline at end of file diff --git a/templates/topic_c_edit_post.html b/templates/topic_c_edit_post.html index 936a7247..5f47fbfb 100644 --- a/templates/topic_c_edit_post.html +++ b/templates/topic_c_edit_post.html @@ -1,4 +1,4 @@ -
+
diff --git a/templates/topic_poll.html b/templates/topic_poll.html index 6e8e9f69..c5fb05ab 100644 --- a/templates/topic_poll.html +++ b/templates/topic_poll.html @@ -1,5 +1,5 @@
-
+
{{range .Poll.QuickOptions}}
diff --git a/templates/widget_menu.html b/templates/widget_menu.html index 7ea1ca86..d3b4365e 100644 --- a/templates/widget_menu.html +++ b/templates/widget_menu.html @@ -2,5 +2,5 @@

{{.Name}}

+ +{{end}} \ No newline at end of file diff --git a/templates/widget_online.html b/templates/widget_online.html index feef8d3e..bdfc4641 100644 --- a/templates/widget_online.html +++ b/templates/widget_online.html @@ -3,7 +3,7 @@
{{if lt .UserCount 30}} - {{range .Users}}
+ {{range .Users}}