Oops, we want these in separate repos / folders.
This commit is contained in:
parent
dcd4d7d7eb
commit
8ab9ca3bf0
|
@ -1,218 +0,0 @@
|
||||||
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?
|
|
|
@ -1,26 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,241 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
Loading…
Reference in New Issue