Compare commits

...

3 Commits

Author SHA1 Message Date
Niko Abeler 5e77fdd33b WIP minimal AP 2023-07-26 21:28:57 +02:00
Niko Abeler 5f49754b71 deletion 2023-07-25 21:49:09 +02:00
Niko Abeler 34e4984af9 content type for media 2023-07-25 21:39:57 +02:00
7 changed files with 123 additions and 59 deletions

5
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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 }}

View File

@ -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)
}

View File

@ -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))

View File

@ -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("/")
}

View File

@ -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
}