prevent publishing of drafts + support for recipes
This commit is contained in:
parent
3c924ac8a4
commit
5c05f48be3
|
@ -498,7 +498,41 @@ func (svc *ActivityPubService) NotifyEntryCreated(entry model.Entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *ActivityPubService) NotifyEntryUpdated(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) {
|
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 {
|
if imageEntry, ok := entry.(*entrytypes.Image); ok {
|
||||||
return svc.imageToObject(imageEntry), nil
|
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")
|
slog.Warn("entry type not yet supported for activity pub")
|
||||||
return vocab.Object{}, errors.New("entry type not supported")
|
return vocab.Object{}, errors.New("entry type not supported")
|
||||||
}
|
}
|
||||||
|
@ -595,11 +636,14 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
|
||||||
Type: vocab.DocumentType,
|
Type: vocab.DocumentType,
|
||||||
MediaType: vocab.MimeType(binaryFile.Mime()),
|
MediaType: vocab.MimeType(binaryFile.Mime()),
|
||||||
URL: vocab.ID(fullImageUrl),
|
URL: vocab.ID(fullImageUrl),
|
||||||
|
Name: vocab.NaturalLanguageValues{
|
||||||
|
{Value: vocab.Content(content)},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
image := vocab.Note{
|
image := vocab.Image{
|
||||||
ID: vocab.ID(imageEntry.FullUrl(siteCfg)),
|
ID: vocab.ID(imageEntry.FullUrl(siteCfg)),
|
||||||
Type: "Note",
|
Type: "Image",
|
||||||
To: vocab.ItemCollection{
|
To: vocab.ItemCollection{
|
||||||
vocab.PublicNS,
|
vocab.PublicNS,
|
||||||
vocab.IRI(svc.FollowersUrl()),
|
vocab.IRI(svc.FollowersUrl()),
|
||||||
|
@ -610,7 +654,7 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
|
||||||
{Value: vocab.Content(imageEntry.Title())},
|
{Value: vocab.Content(imageEntry.Title())},
|
||||||
},
|
},
|
||||||
Content: vocab.NaturalLanguageValues{
|
Content: vocab.NaturalLanguageValues{
|
||||||
{Value: vocab.Content(content)},
|
{Value: vocab.Content(imageEntry.Title() + "<br><br>" + string(content))},
|
||||||
},
|
},
|
||||||
Attachment: attachments,
|
Attachment: attachments,
|
||||||
// Tag: tags,
|
// Tag: tags,
|
||||||
|
@ -618,3 +662,51 @@ func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab
|
||||||
return image
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,13 @@ func (s *EntryService) Create(entry model.Entry) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +63,13 @@ func (s *EntryService) Update(entry model.Entry) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +78,9 @@ func (s *EntryService) Delete(entry model.Entry) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
s.Bus.NotifyDeleted(entry)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ func setupService() *app.EntryService {
|
||||||
register := app.NewEntryTypeRegistry()
|
register := app.NewEntryTypeRegistry()
|
||||||
register.Register(&test.MockEntry{})
|
register.Register(&test.MockEntry{})
|
||||||
repo := infra.NewEntryRepository(db, register)
|
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
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue