diff --git a/app/activity_pub_service.go b/app/activity_pub_service.go
index 1f06ec9..1bad4e0 100644
--- a/app/activity_pub_service.go
+++ b/app/activity_pub_service.go
@@ -498,7 +498,41 @@ func (svc *ActivityPubService) NotifyEntryCreated(entry model.Entry) {
}
func (svc *ActivityPubService) NotifyEntryUpdated(entry model.Entry) {
+ slog.Info("Processing Entry Create for ActivityPub")
+ followers, err := svc.AllFollowers()
+ if err != nil {
+ slog.Error("Cannot retrieve followers")
+ }
+ object, err := svc.entryToObject(entry)
+ if err != nil {
+ slog.Error("Cannot convert object", "err", err)
+ }
+
+ update := vocab.UpdateNew(object.ID, object)
+ update.Actor = object.AttributedTo
+ update.To = object.To
+ update.Published = object.Published
+ data, err := jsonld.WithContext(
+ jsonld.IRI(vocab.ActivityBaseURI),
+ jsonld.Context{
+ jsonld.ContextElement{
+ Term: "toot",
+ IRI: jsonld.IRI("http://joinmastodon.org/ns#"),
+ },
+ },
+ ).Marshal(update)
+ 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) NotifyEntryDeleted(entry model.Entry) {
@@ -543,6 +577,13 @@ func (svc *ActivityPubService) entryToObject(entry model.Entry) (vocab.Object, e
if imageEntry, ok := entry.(*entrytypes.Image); ok {
return svc.imageToObject(imageEntry), nil
}
+ if articleEntry, ok := entry.(*entrytypes.Article); ok {
+ return svc.articleToObject(articleEntry), nil
+ }
+ if recipeEntry, ok := entry.(*entrytypes.Recipe); ok {
+ return svc.recipeToObject(recipeEntry), nil
+ }
+
slog.Warn("entry type not yet supported for activity pub")
return vocab.Object{}, errors.New("entry type not supported")
}
@@ -595,11 +636,14 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
Type: vocab.DocumentType,
MediaType: vocab.MimeType(binaryFile.Mime()),
URL: vocab.ID(fullImageUrl),
+ Name: vocab.NaturalLanguageValues{
+ {Value: vocab.Content(content)},
+ },
})
- image := vocab.Note{
+ image := vocab.Image{
ID: vocab.ID(imageEntry.FullUrl(siteCfg)),
- Type: "Note",
+ Type: "Image",
To: vocab.ItemCollection{
vocab.PublicNS,
vocab.IRI(svc.FollowersUrl()),
@@ -610,7 +654,7 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
{Value: vocab.Content(imageEntry.Title())},
},
Content: vocab.NaturalLanguageValues{
- {Value: vocab.Content(content)},
+ {Value: vocab.Content(imageEntry.Title() + "
" + string(content))},
},
Attachment: attachments,
// Tag: tags,
@@ -618,3 +662,51 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
return image
}
+
+func (svc *ActivityPubService) articleToObject(articleEntry *entrytypes.Article) vocab.Object {
+ siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
+ content := articleEntry.Content()
+
+ image := vocab.Article{
+ ID: vocab.ID(articleEntry.FullUrl(siteCfg)),
+ Type: "Article",
+ To: vocab.ItemCollection{
+ vocab.PublicNS,
+ vocab.IRI(svc.FollowersUrl()),
+ },
+ Published: *articleEntry.PublishedAt(),
+ AttributedTo: vocab.ID(svc.ActorUrl()),
+ Name: vocab.NaturalLanguageValues{
+ {Value: vocab.Content(articleEntry.Title())},
+ },
+ Content: vocab.NaturalLanguageValues{
+ {Value: vocab.Content(string(content))},
+ },
+ }
+ return image
+
+}
+
+func (svc *ActivityPubService) recipeToObject(recipeEntry *entrytypes.Recipe) vocab.Object {
+ siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
+ content := recipeEntry.Content()
+
+ image := vocab.Article{
+ ID: vocab.ID(recipeEntry.FullUrl(siteCfg)),
+ Type: "Article",
+ To: vocab.ItemCollection{
+ vocab.PublicNS,
+ vocab.IRI(svc.FollowersUrl()),
+ },
+ Published: *recipeEntry.PublishedAt(),
+ AttributedTo: vocab.ID(svc.ActorUrl()),
+ Name: vocab.NaturalLanguageValues{
+ {Value: vocab.Content(recipeEntry.Title())},
+ },
+ Content: vocab.NaturalLanguageValues{
+ {Value: vocab.Content(string(content))},
+ },
+ }
+ return image
+
+}
diff --git a/app/entry_service.go b/app/entry_service.go
index 26a2053..7f3e87a 100644
--- a/app/entry_service.go
+++ b/app/entry_service.go
@@ -48,7 +48,13 @@ func (s *EntryService) Create(entry model.Entry) error {
if err != nil {
return err
}
- s.Bus.NotifyCreated(entry)
+ // only notify if the publishing date is set
+ // otherwise this is a draft.
+ // listeners might publish the entry to other services/platforms
+ // this should only happen for publshed content
+ if entry.PublishedAt() != nil && !entry.PublishedAt().IsZero() {
+ s.Bus.NotifyCreated(entry)
+ }
return nil
}
@@ -57,7 +63,13 @@ func (s *EntryService) Update(entry model.Entry) error {
if err != nil {
return err
}
- s.Bus.NotifyUpdated(entry)
+ // only notify if the publishing date is set
+ // otherwise this is a draft.
+ // listeners might publish the entry to other services/platforms
+ // this should only happen for publshed content
+ if entry.PublishedAt() != nil && !entry.PublishedAt().IsZero() {
+ s.Bus.NotifyUpdated(entry)
+ }
return nil
}
@@ -66,6 +78,9 @@ func (s *EntryService) Delete(entry model.Entry) error {
if err != nil {
return err
}
+ // deletes should always be notfied
+ // a published entry might be converted to a draft before deletion
+ // omitting the deletion in this case would prevent deletion on other platforms
s.Bus.NotifyDeleted(entry)
return nil
}
diff --git a/app/entry_service_test.go b/app/entry_service_test.go
index ec7cd78..41cafc4 100644
--- a/app/entry_service_test.go
+++ b/app/entry_service_test.go
@@ -14,7 +14,9 @@ func setupService() *app.EntryService {
register := app.NewEntryTypeRegistry()
register.Register(&test.MockEntry{})
repo := infra.NewEntryRepository(db, register)
- service := app.NewEntryService(repo, nil, app.NewEventBus())
+ cfgRepo := infra.NewConfigRepo(db)
+ cfgService := app.NewSiteConfigService(cfgRepo)
+ service := app.NewEntryService(repo, cfgService, app.NewEventBus())
return service
}