219 lines
4.9 KiB
Go
219 lines
4.9 KiB
Go
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?
|