You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.0 KiB

package handler
import (
"context"
"fmt"
"github.com/rs/zerolog/log"
"github.com/turnage/graw"
"net/http"
"regexp"
"strings"
"time"
"go.jolheiser.com/lurk/config"
"github.com/turnage/graw/reddit"
"go.jolheiser.com/disco"
)
var httpClient = &http.Client{Timeout: time.Minute}
type Reddit struct {
Bot reddit.Bot
Config *config.Config
}
func (r *Reddit) Run() error {
_, wait, err := graw.Run(r, r.Bot, graw.Config{
Subreddits: r.Config.Reddit.SubRedditNames(),
})
if err != nil {
return err
}
return wait()
}
func (r *Reddit) Post(p *reddit.Post) error {
sub := r.Config.Reddit.Map[strings.ToLower(p.Subreddit)]
if err := checkPost(r.Config, p); err != nil {
log.Debug().Err(err).Msg(p.Subreddit)
return nil
}
title := p.Title
if len(title) > sub.TitleLimit {
title = title[:sub.TitleLimit] + "..."
}
description := p.SelfText
if len(description) > sub.BodyLimit {
description = description[:sub.BodyLimit] + "..."
}
e := &disco.Webhook{
Username: "/r/" + p.Subreddit,
AvatarURL: sub.IconURL,
Embeds: []*disco.Embed{
{
Title: title,
URL: p.URL,
Description: description,
Color: 0x007D96,
Timestamp: disco.Now(),
Author: &disco.Author{
Name: "/u/" + p.Author,
URL: fmt.Sprintf("https://reddit.com/user/%s", p.Author),
},
},
},
}
if sub.Webhook == "" {
log.Error().Msgf("no webhook for %s", p.Subreddit)
return nil
}
req, err := e.Request(context.Background(), sub.Webhook)
if err != nil {
log.Err(err).Msg("")
return nil
}
resp, err := httpClient.Do(req)
if err != nil {
log.Err(err).Msg("")
return nil
}
if resp.StatusCode != http.StatusNoContent {
log.Error().Msgf(resp.Status)
return nil
}
return nil
}
func checkPost(c *config.Config, p *reddit.Post) error {
sub := c.Reddit.Map[strings.ToLower(p.Subreddit)]
// Check blocklist first
// Any match means we ignore
if matchesAny(p.LinkFlairText, sub.FlairBlocklistRe) {
return fmt.Errorf("flair matched blocklisted regex: %s", p.LinkFlairText)
}
if matchesAny(p.Title, sub.TitleBlocklistRe) {
return fmt.Errorf("title matched blocklisted regex: %s", p.Title)
}
if matchesAny(p.SelfText, sub.BodyBlocklistRe) {
return fmt.Errorf("body matched blocklisted regex: %s", p.SelfText)
}
// Check allowlist
// Any match means we pass
// If no allowlist, pass
if len(sub.FlairAllowlistRe) > 0 && !matchesAny(p.LinkFlairText, sub.FlairAllowlistRe) {
return fmt.Errorf("flair didn't match any allowlisted regex: %s", p.LinkFlairText)
}
if len(sub.TitleAllowlistRe) > 0 && !matchesAny(p.Title, sub.TitleAllowlistRe) {
return fmt.Errorf("title didn't match any allowlisted regex: %s", p.Title)
}
if len(sub.BodyAllowlistRe) > 0 && !matchesAny(p.SelfText, sub.BodyAllowlistRe) {
return fmt.Errorf("body didn't match any allowlisted regex: %s", p.SelfText)
}
return nil
}
func matchesAny(input string, re []*regexp.Regexp) bool {
for _, r := range re {
if r.MatchString(input) {
return true
}
}
return false
}