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 @@
-
+