Compare commits
3 Commits
e35bf9af5d
...
5e77fdd33b
Author | SHA1 | Date |
---|---|---|
Niko Abeler | 5e77fdd33b | |
Niko Abeler | 5f49754b71 | |
Niko Abeler | 34e4984af9 |
5
go.mod
5
go.mod
|
@ -15,8 +15,12 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee // indirect
|
||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea // indirect
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.16.3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
|
@ -31,6 +35,7 @@ require (
|
|||
github.com/tinylib/msgp v1.1.8 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.47.0 // indirect
|
||||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
11
go.sum
11
go.sum
|
@ -1,8 +1,16 @@
|
|||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee h1:1OMBlmSzLXftIj5z/D1s1Xr3FanVKtLFZPtdIFslh1A=
|
||||
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee/go.mod h1:qw0WNf+PTG69Xu6mVqUluDuKl1VwVYdgntOZQFBZQ48=
|
||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea h1:ywGtLGVjJjMrq4mu35Qmu+NtlhlTk/gTayE6Bb4tQZk=
|
||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea/go.mod h1:SaTNjEEkp0q+w3pUS1ccyEL/lUrHteORlDq/e21mCc8=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gofiber/fiber/v2 v2.47.0 h1:EN5lHVCc+Pyqh5OEsk8fzRiifgwpbrP0rulQ4iNf3fs=
|
||||
|
@ -53,6 +61,9 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
|||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
|
||||
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
|
@ -35,7 +35,22 @@
|
|||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<a href="/editor/edit/{{.Entry.ID}}/" role="button" class="secondary outline">Edit</a>
|
||||
<h3>Actions</h3>
|
||||
<div class="grid">
|
||||
<a href="/editor/edit/{{.Entry.ID}}/" role="button" class="secondary outline">Edit</a>
|
||||
</div>
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
<form method="post" action="/editor/delete/{{.Entry.ID}}/" class="grid">
|
||||
<label for="confirm">
|
||||
Confirm deletion
|
||||
<input type="checkbox" name="confirm" id="confirm" required />
|
||||
</label>
|
||||
<input type="submit" class="secondary outline" value="Delete" />
|
||||
</form>
|
||||
|
||||
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"owl-blogs/app"
|
||||
"owl-blogs/app/repository"
|
||||
"owl-blogs/config"
|
||||
"owl-blogs/domain/model"
|
||||
|
||||
vocab "github.com/go-ap/activitypub"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
const ACT_PUB_CONF_NAME = "activity_pub"
|
||||
|
||||
type ActivityPubServer struct {
|
||||
configRepo repository.ConfigRepository
|
||||
configRepo repository.ConfigRepository
|
||||
entryService *app.EntryService
|
||||
}
|
||||
|
||||
type ActivityPubConfig struct {
|
||||
|
@ -21,48 +26,20 @@ type ActivityPubConfig struct {
|
|||
}
|
||||
|
||||
type WebfingerResponse struct {
|
||||
Subject string `json:"subject"`
|
||||
Links []ActivityPubLink `json:"links"`
|
||||
Subject string `json:"subject"`
|
||||
Links []WebfingerLink `json:"links"`
|
||||
}
|
||||
|
||||
type ActivityPubLink struct {
|
||||
type WebfingerLink struct {
|
||||
Rel string `json:"rel"`
|
||||
Type string `json:"type"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
type ActivityPubActor struct {
|
||||
Context []string `json:"@context"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
PreferredUsername string `json:"preferredUsername"`
|
||||
Inbox string `json:"inbox"`
|
||||
Oubox string `json:"outbox"`
|
||||
Followers string `json:"followers"`
|
||||
|
||||
PublicKey ActivityPubPublicKey `json:"publicKey"`
|
||||
}
|
||||
|
||||
type ActivityPubPublicKey struct {
|
||||
ID string `json:"id"`
|
||||
Owner string `json:"owner"`
|
||||
PublicKeyPem string `json:"publicKeyPem"`
|
||||
}
|
||||
|
||||
type ActivityPubOrderedCollection struct {
|
||||
Context []string `json:"@context"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
TotalItems int `json:"totalItems"`
|
||||
First string `json:"first"`
|
||||
Last string `json:"last"`
|
||||
}
|
||||
|
||||
func NewActivityPubServer(configRepo repository.ConfigRepository) *ActivityPubServer {
|
||||
func NewActivityPubServer(configRepo repository.ConfigRepository, entryService *app.EntryService) *ActivityPubServer {
|
||||
return &ActivityPubServer{
|
||||
configRepo: configRepo,
|
||||
configRepo: configRepo,
|
||||
entryService: entryService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +52,7 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
|
|||
webfinger := WebfingerResponse{
|
||||
Subject: ctx.Query("resource"),
|
||||
|
||||
Links: []ActivityPubLink{
|
||||
Links: []WebfingerLink{
|
||||
{
|
||||
Rel: "self",
|
||||
Type: "application/activity+json",
|
||||
|
@ -90,6 +67,7 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
|
|||
|
||||
func (s *ActivityPubServer) Router(router fiber.Router) {
|
||||
router.Get("/actor", s.HandleActor)
|
||||
router.Get("/outbox", s.HandleOutbox)
|
||||
}
|
||||
|
||||
func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error {
|
||||
|
@ -98,25 +76,57 @@ func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error {
|
|||
s.configRepo.Get(ACT_PUB_CONF_NAME, &apConfig)
|
||||
s.configRepo.Get(config.SITE_CONFIG, &siteConfig)
|
||||
|
||||
actor := ActivityPubActor{
|
||||
Context: []string{
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
},
|
||||
|
||||
ID: siteConfig.FullUrl + "/activitypub/actor",
|
||||
Type: "Person",
|
||||
PreferredUsername: apConfig.PreferredUsername,
|
||||
Inbox: siteConfig.FullUrl + "/activitypub/inbox",
|
||||
Oubox: siteConfig.FullUrl + "/activitypub/outbox",
|
||||
Followers: siteConfig.FullUrl + "/activitypub/followers",
|
||||
|
||||
PublicKey: ActivityPubPublicKey{
|
||||
ID: siteConfig.FullUrl + "/activitypub/actor#main-key",
|
||||
Owner: siteConfig.FullUrl + "/activitypub/actor",
|
||||
PublicKeyPem: apConfig.PublicKeyPem,
|
||||
},
|
||||
actor := vocab.PersonNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"))
|
||||
actor.PreferredUsername = vocab.NaturalLanguageValues{{Value: vocab.Content(apConfig.PreferredUsername)}}
|
||||
actor.Inbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/inbox")
|
||||
actor.Outbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox")
|
||||
actor.Followers = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers")
|
||||
actor.PublicKey = vocab.PublicKey{
|
||||
ID: vocab.ID(siteConfig.FullUrl + "/activitypub/actor#main-key"),
|
||||
Owner: vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"),
|
||||
PublicKeyPem: apConfig.PublicKeyPem,
|
||||
}
|
||||
|
||||
return ctx.JSON(actor)
|
||||
data, err := actor.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Set("Content-Type", "application/activity+json")
|
||||
return ctx.Send(data)
|
||||
}
|
||||
|
||||
func (s *ActivityPubServer) HandleOutbox(ctx *fiber.Ctx) error {
|
||||
siteConfig := model.SiteConfig{}
|
||||
apConfig := ActivityPubConfig{}
|
||||
s.configRepo.Get(ACT_PUB_CONF_NAME, &apConfig)
|
||||
s.configRepo.Get(config.SITE_CONFIG, &siteConfig)
|
||||
|
||||
entries, err := s.entryService.FindAllByType(nil, true, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
items := make([]vocab.Item, len(entries))
|
||||
for i, entry := range entries {
|
||||
url, _ := url.JoinPath(siteConfig.FullUrl, "/posts/"+entry.ID()+"/")
|
||||
items[i] = *vocab.ActivityNew(vocab.IRI(url), vocab.CreateType, vocab.Object{
|
||||
ID: vocab.ID(url),
|
||||
Type: vocab.ArticleType,
|
||||
Content: vocab.NaturalLanguageValues{
|
||||
{Value: vocab.Content(entry.Content())},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
outbox := vocab.OrderedCollectionNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox"))
|
||||
outbox.TotalItems = uint(len(items))
|
||||
outbox.OrderedItems = items
|
||||
|
||||
data, err := outbox.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Set("Content-Type", "application/activity+json")
|
||||
return ctx.Send(data)
|
||||
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ func NewWebApp(
|
|||
editor.Post("/new/:editor/", editorHandler.HandlePostNew)
|
||||
editor.Get("/edit/:id/", editorHandler.HandleGetEdit)
|
||||
editor.Post("/edit/:id/", editorHandler.HandlePostEdit)
|
||||
editor.Post("/delete/:id/", editorHandler.HandlePostDelete)
|
||||
|
||||
// SiteConfig
|
||||
siteConfig := app.Group("/site-config")
|
||||
|
@ -117,10 +118,10 @@ func NewWebApp(
|
|||
app.Get("/sitemap.xml", NewSiteMapHandler(entryService, configRepo).Handle)
|
||||
|
||||
// ActivityPub
|
||||
// activityPubServer := NewActivityPubServer(configRepo)
|
||||
activityPubServer := NewActivityPubServer(configRepo, entryService)
|
||||
configRegister.Register(ACT_PUB_CONF_NAME, &ActivityPubConfig{})
|
||||
// app.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger)
|
||||
// app.Route("/activitypub", activityPubServer.Router)
|
||||
app.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger)
|
||||
app.Route("/activitypub", activityPubServer.Router)
|
||||
|
||||
// Webmention
|
||||
// app.Post("/webmention/", userWebmentionHandler(repo))
|
||||
|
|
|
@ -127,3 +127,24 @@ func (h *EditorHandler) HandlePostEdit(c *fiber.Ctx) error {
|
|||
}
|
||||
return c.Redirect("/posts/" + entry.ID() + "/")
|
||||
}
|
||||
|
||||
func (h *EditorHandler) HandlePostDelete(c *fiber.Ctx) error {
|
||||
c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
|
||||
|
||||
id := c.Params("id")
|
||||
entry, err := h.entrySvc.FindById(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
confirm := c.FormValue("confirm")
|
||||
if confirm != "on" {
|
||||
return c.Redirect("/posts/" + entry.ID() + "/")
|
||||
}
|
||||
|
||||
err = h.entrySvc.Delete(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Redirect("/")
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ func (h *MediaHandler) Handle(c *fiber.Ctx) error {
|
|||
return err
|
||||
}
|
||||
binary, err := h.binaryService.FindById(id)
|
||||
c.Set("Content-Type", binary.Mime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue