gosora/extend/plugin_discord.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?