parent
3be4b23159
commit
ec6d61b221
@ -0,0 +1,92 @@
|
||||
package rss
|
||||
|
||||
import (
|
||||
"brainbaking.com/go-jamming/app/mf"
|
||||
"brainbaking.com/go-jamming/common"
|
||||
"brainbaking.com/go-jamming/db"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
"net/http"
|
||||
"sort"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
import _ "embed"
|
||||
|
||||
const (
|
||||
MaxRssItems = 50
|
||||
)
|
||||
|
||||
//go:embed mentionsrss.xml
|
||||
var mentionsrssTemplate []byte
|
||||
|
||||
type RssMentions struct {
|
||||
Domain string
|
||||
Date time.Time
|
||||
Items []*RssMentionItem
|
||||
}
|
||||
|
||||
type RssMentionItem struct {
|
||||
ApproveURL string
|
||||
RejectURL string
|
||||
Data *mf.IndiewebData
|
||||
}
|
||||
|
||||
func asTemplate(name string, data []byte) *template.Template {
|
||||
tmpl, err := template.New(name).Parse(string(data))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Str("name", name).Msg("Template invalid")
|
||||
}
|
||||
return tmpl
|
||||
}
|
||||
|
||||
func HandleGet(c *common.Config, repo db.MentionRepo) http.HandlerFunc {
|
||||
tmpl := asTemplate("mentionsRss", mentionsrssTemplate)
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
domain := mux.Vars(r)["domain"]
|
||||
|
||||
mentions := getLatestMentions(domain, repo, c)
|
||||
err := tmpl.Execute(w, RssMentions{
|
||||
Items: mentions,
|
||||
Date: time.Now(),
|
||||
Domain: domain,
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
log.Error().Err(err).Msg("Unable to fill in dashboard template")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getLatestMentions(domain string, repo db.MentionRepo, c *common.Config) []*RssMentionItem {
|
||||
toMod := repo.GetAllToModerate(domain).Data
|
||||
all := repo.GetAll(domain).Data
|
||||
|
||||
var data []*RssMentionItem
|
||||
for _, v := range toMod {
|
||||
wm := v.AsMention()
|
||||
data = append(data, &RssMentionItem{
|
||||
Data: v,
|
||||
ApproveURL: fmt.Sprintf("%sadmin/approve/%s/%s", c.BaseURL, c.Token, wm.Key()),
|
||||
RejectURL: fmt.Sprintf("%sadmin/reject/%s/%s", c.BaseURL, c.Token, wm.Key()),
|
||||
})
|
||||
}
|
||||
for _, v := range all {
|
||||
data = append(data, &RssMentionItem{
|
||||
Data: v,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO this date is the published date, not the webmention received date!
|
||||
// This means it "might" disappear after the cutoff point in the RSS feed, and we don't store a received timestamp
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return data[i].Data.PublishedDate().After(data[j].Data.PublishedDate())
|
||||
})
|
||||
if len(data) > MaxRssItems {
|
||||
return data[0:MaxRssItems]
|
||||
}
|
||||
return data
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package rss
|
||||
|
||||
import (
|
||||
"brainbaking.com/go-jamming/app/mf"
|
||||
"brainbaking.com/go-jamming/common"
|
||||
"brainbaking.com/go-jamming/db"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
cnf = &common.Config{
|
||||
BaseURL: "http://localhost:1337/",
|
||||
Port: 1337,
|
||||
Token: "miauwkes",
|
||||
AllowedWebmentionSources: []string{"brainbaking.com"},
|
||||
Blacklist: []string{},
|
||||
Whitelist: []string{"brainbaking.com"},
|
||||
}
|
||||
repo db.MentionRepo
|
||||
)
|
||||
|
||||
func init() {
|
||||
repo = db.NewMentionRepo(cnf)
|
||||
}
|
||||
func TestHandleGet(t *testing.T) {
|
||||
wmInMod := mf.Mention{
|
||||
Source: "https://infos.by/markdown-v-nauke/",
|
||||
Target: "https://brainbaking.com/post/2021/02/writing-academic-papers-in-markdown/",
|
||||
}
|
||||
wmApproved := mf.Mention{
|
||||
Source: "https://brainbaking.com/post/2022/04/equality-in-game-credits/",
|
||||
Target: "https://brainbaking.com/",
|
||||
}
|
||||
|
||||
repo.InModeration(wmInMod, &mf.IndiewebData{
|
||||
Source: wmInMod.Source,
|
||||
Target: wmInMod.Target,
|
||||
Name: "inmod1",
|
||||
})
|
||||
repo.Save(wmApproved, &mf.IndiewebData{
|
||||
Source: wmApproved.Source,
|
||||
Target: wmApproved.Target,
|
||||
Name: "approved1",
|
||||
})
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/feed/{domain}/{token}", HandleGet(cnf, repo)).Methods("GET")
|
||||
ts := httptest.NewServer(r)
|
||||
|
||||
t.Cleanup(func() {
|
||||
os.Remove("config.json")
|
||||
ts.Close()
|
||||
db.Purge()
|
||||
})
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/feed/%s/%s", ts.URL, cnf.AllowedWebmentionSources[0], cnf.Token), nil)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
contentBytes, _ := ioutil.ReadAll(resp.Body)
|
||||
content := string(contentBytes)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Contains(t, content, "<description>Go-Jamming @ brainbaking.com</description>")
|
||||
assert.Contains(t, content, "<title>To Moderate: inmod1 ()</title>")
|
||||
assert.Contains(t, content, "<title>approved1 ()</title>")
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version='2.0' xmlns:content='http://purl.org/rss/1.0/modules/content/' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:dc='http://purl.org/dc/elements/1.1/'>
|
||||
<channel>
|
||||
<title>Go-Jamming @ {{ .Domain }}</title>
|
||||
<description>Go-Jamming @ {{ .Domain }}</description>
|
||||
<generator>Go-Jamming</generator>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</lastBuildDate>
|
||||
|
||||
{{ range .Items }}
|
||||
<item>
|
||||
<title>{{ if .ApproveURL }}To Moderate: {{ end }}{{ .Data.Name | html }} ({{ .Data.Url }})</title>
|
||||
<link>{{ .Data.Target }}</link>
|
||||
<pubDate>{{ .Data.PublishedDate.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate>
|
||||
<dc:creator>{{ .Data.Author.Name | html }}</dc:creator>
|
||||
<description>
|
||||
<![CDATA[
|
||||
{{ if .ApproveURL }}
|
||||
<a href="{{ .ApproveURL }}">✅ Approve this mention!</a><br/>
|
||||
<a href="{{ .RejectURL }}">❌ Reject this mention!</a><br/><br/>
|
||||
{{ end }}
|
||||
|
||||
Author: {{ .Data.Author }}<br/>
|
||||
Name: {{ .Data.Name }}<br/>
|
||||
Published: {{ .Data.Published }}<br/>
|
||||
Type: {{ .Data.IndiewebType }}<br/>
|
||||
Url: <a href="{{ .Data.Url }}">{{ .Data.Url }}</a><br/><br/>
|
||||
|
||||
Source: <a href="{{ .Data.Source }}">{{ .Data.Source }}</a><br/>
|
||||
Target: <a href="{{ .Data.Target }}">{{ .Data.Target }}</a><br/><br/>
|
||||
|
||||
Content: {{ .Data.Content }}
|
||||
]]>
|
||||
</description>
|
||||
</item>
|
||||
{{ end }}
|
||||
</channel>
|
||||
</rss>
|
Loading…
Reference in new issue