Activity Pub Implementation #58

Merged
h4kor merged 13 commits from activity_pub into main 2024-05-18 14:31:11 +00:00
2 changed files with 102 additions and 52 deletions
Showing only changes of commit 3c924ac8a4 - Show all commits

View File

@ -63,6 +63,7 @@ type ActivityPubService struct {
interactionRepository repository.InteractionRepository
entryService *EntryService
siteConfigServcie *SiteConfigService
binService *BinaryService
}
func NewActivityPubService(
@ -71,6 +72,7 @@ func NewActivityPubService(
interactionRepository repository.InteractionRepository,
entryService *EntryService,
siteConfigServcie *SiteConfigService,
binService *BinaryService,
bus *EventBus,
) *ActivityPubService {
service := &ActivityPubService{
@ -78,6 +80,7 @@ func NewActivityPubService(
configRepo: configRepo,
interactionRepository: interactionRepository,
entryService: entryService,
binService: binService,
siteConfigServcie: siteConfigServcie,
}
@ -458,50 +461,20 @@ func (s *ActivityPubService) sendObject(to vocab.Actor, data []byte) error {
func (svc *ActivityPubService) NotifyEntryCreated(entry model.Entry) {
slog.Info("Processing Entry Create for ActivityPub")
// limit to notes for now
noteEntry, ok := entry.(*entrytypes.Note)
if !ok {
slog.Info("not a note")
return
}
siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
followers, err := svc.AllFollowers()
if err != nil {
slog.Error("Cannot retrieve followers")
}
content := noteEntry.Content()
r := regexp.MustCompile("#[a-z0-9_]+")
matches := r.FindAllString(string(content), -1)
tags := vocab.ItemCollection{}
for _, hashtag := range matches {
tags.Append(vocab.Object{
ID: vocab.ID(svc.HashtagId(hashtag)),
Name: vocab.NaturalLanguageValues{{Value: vocab.Content(hashtag)}},
})
object, err := svc.entryToObject(entry)
if err != nil {
slog.Error("Cannot convert object", "err", err)
}
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(content)},
},
Tag: tags,
}
create := vocab.CreateNew(vocab.IRI(noteEntry.FullUrl(siteCfg)), note)
create.Actor = note.AttributedTo
create.To = note.To
create.Published = note.Published
create := vocab.CreateNew(object.ID, object)
create.Actor = object.AttributedTo
create.To = object.To
create.Published = object.Published
data, err := jsonld.WithContext(
jsonld.IRI(vocab.ActivityBaseURI),
jsonld.Context{
@ -529,28 +502,20 @@ func (svc *ActivityPubService) NotifyEntryUpdated(entry model.Entry) {
}
func (svc *ActivityPubService) NotifyEntryDeleted(entry model.Entry) {
slog.Info("Processing Entry Delete for ActivityPub")
// limit to notes for now
noteEntry, ok := entry.(*entrytypes.Note)
if !ok {
slog.Info("not a note")
obj, err := svc.entryToObject(entry)
if err != nil {
slog.Error("error converting to object", "err", err)
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",
}
delete := vocab.DeleteNew(vocab.IRI(noteEntry.FullUrl(siteCfg)), note)
delete.Actor = note.AttributedTo
delete.To = note.To
delete := vocab.DeleteNew(obj.ID, obj)
delete.Actor = obj.AttributedTo
delete.To = obj.To
delete.Published = time.Now()
data, err := jsonld.WithContext(
jsonld.IRI(vocab.ActivityBaseURI),
@ -568,3 +533,88 @@ func (svc *ActivityPubService) NotifyEntryDeleted(entry model.Entry) {
}
}
func (svc *ActivityPubService) entryToObject(entry model.Entry) (vocab.Object, error) {
// limit to notes for now
if noteEntry, ok := entry.(*entrytypes.Note); ok {
return svc.noteToObject(noteEntry), nil
}
if imageEntry, ok := entry.(*entrytypes.Image); ok {
return svc.imageToObject(imageEntry), nil
}
slog.Warn("entry type not yet supported for activity pub")
return vocab.Object{}, errors.New("entry type not supported")
}
func (svc *ActivityPubService) noteToObject(noteEntry *entrytypes.Note) vocab.Object {
siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
content := noteEntry.Content()
r := regexp.MustCompile("#[a-z0-9_]+")
matches := r.FindAllString(string(content), -1)
tags := vocab.ItemCollection{}
for _, hashtag := range matches {
tags.Append(vocab.Object{
ID: vocab.ID(svc.HashtagId(hashtag)),
Name: vocab.NaturalLanguageValues{{Value: vocab.Content(hashtag)}},
})
}
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(content)},
},
Tag: tags,
}
return note
}
func (svc *ActivityPubService) imageToObject(imageEntry *entrytypes.Image) vocab.Object {
siteCfg, _ := svc.siteConfigServcie.GetSiteConfig()
content := imageEntry.Content()
imgPath := imageEntry.ImageUrl()
fullImageUrl, _ := url.JoinPath(siteCfg.FullUrl, imgPath)
binaryFile, err := svc.binService.FindById(imageEntry.MetaData().(*entrytypes.ImageMetaData).ImageId)
if err != nil {
slog.Error("cannot get image file")
}
attachments := vocab.ItemCollection{}
attachments = append(attachments, vocab.Document{
Type: vocab.DocumentType,
MediaType: vocab.MimeType(binaryFile.Mime()),
URL: vocab.ID(fullImageUrl),
})
image := vocab.Note{
ID: vocab.ID(imageEntry.FullUrl(siteCfg)),
Type: "Note",
To: vocab.ItemCollection{
vocab.PublicNS,
vocab.IRI(svc.FollowersUrl()),
},
Published: *imageEntry.PublishedAt(),
AttributedTo: vocab.ID(svc.ActorUrl()),
Name: vocab.NaturalLanguageValues{
{Value: vocab.Content(imageEntry.Title())},
},
Content: vocab.NaturalLanguageValues{
{Value: vocab.Content(content)},
},
Attachment: attachments,
// Tag: tags,
}
return image
}

View File

@ -70,7 +70,7 @@ func App(db infra.Database) *web.WebApp {
)
apService := app.NewActivityPubService(
followersRepo, configRepo, interactionRepo,
entryService, siteConfigService,
entryService, siteConfigService, binaryService,
eventBus,
)