Activity Pub Implementation #58
|
@ -14,6 +14,7 @@ import (
|
|||
"owl-blogs/app/repository"
|
||||
"owl-blogs/config"
|
||||
"owl-blogs/domain/model"
|
||||
entrytypes "owl-blogs/entry_types"
|
||||
"owl-blogs/render"
|
||||
"reflect"
|
||||
"time"
|
||||
|
@ -62,12 +63,17 @@ func NewActivityPubService(
|
|||
followersRepo repository.FollowerRepository,
|
||||
configRepo repository.ConfigRepository,
|
||||
siteConfigServcie *SiteConfigService,
|
||||
bus *EventBus,
|
||||
) *ActivityPubService {
|
||||
return &ActivityPubService{
|
||||
service := &ActivityPubService{
|
||||
followersRepo: followersRepo,
|
||||
configRepo: configRepo,
|
||||
siteConfigServcie: siteConfigServcie,
|
||||
}
|
||||
|
||||
bus.Subscribe(service)
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
func (svc *ActivityPubService) defaultConfig() ActivityPubConfig {
|
||||
|
@ -313,3 +319,69 @@ func (s *ActivityPubService) sendObject(to vocab.Actor, data []byte) error {
|
|||
slog.Info("Retrieved", "status", resp.Status, "body", string(body))
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifiers
|
||||
*/
|
||||
|
||||
func (svc *ActivityPubService) NotifyEntryCreated(entry model.Entry) {
|
||||
// limit to notes for now
|
||||
noteEntry, ok := entry.(*entrytypes.Note)
|
||||
if !ok {
|
||||
slog.Info("not an image")
|
||||
return
|
||||
}
|
||||
|
||||
siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
|
||||
followers, err := svc.AllFollowers()
|
||||
if err != nil {
|
||||
slog.Error("Cannot retrieve followers")
|
||||
}
|
||||
|
||||
note := vocab.Note{
|
||||
ID: vocab.ID(noteEntry.FullUrl(siteCfg)),
|
||||
Type: "Note",
|
||||
To: vocab.ItemCollection{
|
||||
vocab.PublicNS,
|
||||
vocab.IRI(svc.FollowersUrl()),
|
||||
},
|
||||
Published: *noteEntry.PublishedAt(),
|
||||
AttributedTo: vocab.ID(svc.ActorUrl()),
|
||||
Content: vocab.NaturalLanguageValues{
|
||||
{Value: vocab.Content(noteEntry.Content())},
|
||||
},
|
||||
}
|
||||
|
||||
create := vocab.CreateNew(vocab.IRI(noteEntry.FullUrl(siteCfg)), note)
|
||||
create.Actor = note.AttributedTo
|
||||
create.To = note.To
|
||||
create.Published = note.Published
|
||||
data, err := jsonld.WithContext(
|
||||
jsonld.IRI(vocab.ActivityBaseURI),
|
||||
jsonld.Context{
|
||||
jsonld.ContextElement{
|
||||
Term: "toot",
|
||||
IRI: jsonld.IRI("http://joinmastodon.org/ns#"),
|
||||
},
|
||||
},
|
||||
).Marshal(create)
|
||||
if err != nil {
|
||||
slog.Error("marshalling error", "err", err)
|
||||
}
|
||||
|
||||
for _, follower := range followers {
|
||||
actor, err := svc.GetActor(follower)
|
||||
if err != nil {
|
||||
slog.Error("Unable to retrieve follower actor", "err", err)
|
||||
}
|
||||
svc.sendObject(actor, data)
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *ActivityPubService) NotifyEntryUpdated(entry model.Entry) {
|
||||
|
||||
}
|
||||
|
||||
func (svc *ActivityPubService) NotifyEntryDeleted(entry model.Entry) {
|
||||
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ func App(db infra.Database) *web.WebApp {
|
|||
webmentionService := app.NewWebmentionService(
|
||||
siteConfigService, interactionRepo, entryRepo, httpClient, eventBus,
|
||||
)
|
||||
apService := app.NewActivityPubService(followersRepo, configRepo, siteConfigService)
|
||||
apService := app.NewActivityPubService(followersRepo, configRepo, siteConfigService, eventBus)
|
||||
|
||||
// setup render functions
|
||||
render.SiteConfigService = siteConfigService
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -21,6 +22,8 @@ type Entry interface {
|
|||
SetPublishedAt(publishedAt *time.Time)
|
||||
SetMetaData(metaData EntryMetaData)
|
||||
SetAuthorId(authorId string)
|
||||
|
||||
FullUrl(cfg SiteConfig) string
|
||||
}
|
||||
|
||||
type EntryMetaData interface {
|
||||
|
@ -60,3 +63,8 @@ func (e *EntryBase) AuthorId() string {
|
|||
func (e *EntryBase) SetAuthorId(authorId string) {
|
||||
e.authorId = authorId
|
||||
}
|
||||
|
||||
func (e *EntryBase) FullUrl(cfg SiteConfig) string {
|
||||
u, _ := url.JoinPath(cfg.FullUrl, "/posts/", e.ID(), "/")
|
||||
return u
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"owl-blogs/domain/model"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEntryFullUrl(t *testing.T) {
|
||||
|
||||
type testCase struct {
|
||||
Id string
|
||||
Url string
|
||||
Want string
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{Id: "foobar", Url: "https://example.com", Want: "https://example.com/posts/foobar/"},
|
||||
{Id: "foobar", Url: "https://example.com/", Want: "https://example.com/posts/foobar/"},
|
||||
{Id: "foobar", Url: "http://example.com", Want: "http://example.com/posts/foobar/"},
|
||||
{Id: "foobar", Url: "http://example.com/", Want: "http://example.com/posts/foobar/"},
|
||||
{Id: "bi-bar-buz", Url: "https://example.com", Want: "https://example.com/posts/bi-bar-buz/"},
|
||||
{Id: "foobar", Url: "https://example.com/lol/", Want: "https://example.com/lol/posts/foobar/"},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
e := model.EntryBase{}
|
||||
e.SetID(test.Id)
|
||||
cfg := model.SiteConfig{FullUrl: test.Url}
|
||||
require.Equal(t, e.FullUrl(cfg), test.Want)
|
||||
}
|
||||
|
||||
}
|
|
@ -171,7 +171,7 @@ func (s *ActivityPubServer) processUndo(r *http.Request, act *vocab.Activity) er
|
|||
return err
|
||||
}
|
||||
|
||||
// go acpub.Accept(gameName, act)
|
||||
go s.apService.Accept(act)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue