worky worky quite contrerky

This commit is contained in:
tsmethurst 2021-05-11 20:33:16 +02:00
commit eb57c95c14
25 changed files with 544 additions and 216 deletions

View file

@ -25,6 +25,7 @@ import (
"errors"
"fmt"
"net/url"
"time"
"github.com/go-fed/activity/pub"
)
@ -56,6 +57,79 @@ func extractName(i withDisplayName) (string, error) {
return "", errors.New("activityStreamsName not found")
}
func extractInReplyToURI(i withInReplyTo) (*url.URL, error) {
inReplyToProp := i.GetActivityStreamsInReplyTo()
for i := inReplyToProp.Begin(); i != inReplyToProp.End(); i = i.Next() {
if i.IsIRI() {
if i.GetIRI() != nil {
return i.GetIRI(), nil
}
}
}
return nil, errors.New("couldn't find iri for in reply to")
}
func extractTos(i withTo) ([]*url.URL, error) {
to := []*url.URL{}
toProp := i.GetActivityStreamsTo()
for i := toProp.Begin(); i != toProp.End(); i = i.Next() {
if i.IsIRI() {
if i.GetIRI() != nil {
to = append(to, i.GetIRI())
}
}
}
if len(to) == 0 {
return nil, errors.New("found no to entries")
}
return to, nil
}
func extractCCs(i withCC) ([]*url.URL, error) {
cc := []*url.URL{}
ccProp := i.GetActivityStreamsCc()
for i := ccProp.Begin(); i != ccProp.End(); i = i.Next() {
if i.IsIRI() {
if i.GetIRI() != nil {
cc = append(cc, i.GetIRI())
}
}
}
if len(cc) == 0 {
return nil, errors.New("found no cc entries")
}
return cc, nil
}
func extractAttributedTo(i withAttributedTo) (*url.URL, error) {
attributedToProp := i.GetActivityStreamsAttributedTo()
for aIter := attributedToProp.Begin(); aIter != attributedToProp.End(); aIter = aIter.Next() {
if aIter.IsIRI() {
if aIter.GetIRI() != nil {
return aIter.GetIRI(), nil
}
}
}
return nil, errors.New("couldn't find iri for attributed to")
}
func extractPublished(i withPublished) (time.Time, error) {
publishedProp := i.GetActivityStreamsPublished()
if publishedProp == nil {
return time.Time{}, errors.New("published prop was nil")
}
if !publishedProp.IsXMLSchemaDateTime() {
return time.Time{}, errors.New("published prop was not date time")
}
t := publishedProp.Get()
if t.IsZero() {
return time.Time{}, errors.New("published time was zero")
}
return t, nil
}
// extractIconURL extracts a URL to a supported image file from something like:
// "icon": {
// "mediaType": "image/jpeg",

View file

@ -25,6 +25,7 @@ import "github.com/go-fed/activity/streams/vocab"
type Accountable interface {
withJSONLDId
withGetTypeName
withPreferredUsername
withIcon
withDisplayName
@ -40,6 +41,27 @@ type Accountable interface {
withFeatured
}
// Statusable represents the minimum activitypub interface for representing a 'status'.
// This interface is fulfilled by: Article, Document, Image, Video, Note, Page, Event, Place, Mention, Profile
type Statusable interface {
withJSONLDId
withGetTypeName
withSummary
withInReplyTo
withPublished
withURL
withAttributedTo
withTo
withCC
withSensitive
withConversation
withContent
withAttachment
withTag
withReplies
}
type withJSONLDId interface {
GetJSONLDId() vocab.JSONLDIdProperty
}
@ -99,3 +121,47 @@ type withFollowers interface {
type withFeatured interface {
GetTootFeatured() vocab.TootFeaturedProperty
}
type withAttributedTo interface {
GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
}
type withAttachment interface {
GetActivityStreamsAttachment() vocab.ActivityStreamsAttachmentProperty
}
type withTo interface {
GetActivityStreamsTo() vocab.ActivityStreamsToProperty
}
type withInReplyTo interface {
GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
}
type withCC interface {
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
}
type withSensitive interface {
// TODO
}
type withConversation interface {
// TODO
}
type withContent interface {
GetActivityStreamsContent() vocab.ActivityStreamsContentProperty
}
type withPublished interface {
GetActivityStreamsPublished() vocab.ActivityStreamsPublishedProperty
}
type withTag interface {
GetActivityStreamsTag() vocab.ActivityStreamsTagProperty
}
type withReplies interface {
GetActivityStreamsReplies() vocab.ActivityStreamsRepliesProperty
}

View file

@ -157,3 +157,49 @@ func (c *converter) ASRepresentationToAccount(accountable Accountable) (*gtsmode
return acct, nil
}
func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, error) {
status := &gtsmodel.Status{}
uriProp := statusable.GetJSONLDId()
if uriProp == nil || !uriProp.IsIRI() {
return nil, errors.New("no id property found, or id was not an iri")
}
status.URI = uriProp.GetIRI().String()
cw, err := extractSummary(statusable)
if err == nil && cw != "" {
status.ContentWarning = cw
}
inReplyToURI, err := extractInReplyToURI(statusable)
if err == nil {
inReplyToStatus := &gtsmodel.Status{}
if err := c.db.GetWhere("uri", inReplyToURI.String(), inReplyToStatus); err == nil {
status.InReplyToID = inReplyToStatus.ID
}
}
published, err := extractPublished(statusable)
if err == nil {
status.CreatedAt = published
}
statusURL, err := extractURL(statusable)
if err == nil {
status.URL = statusURL.String()
}
attributedTo, err := extractAttributedTo(statusable)
if err != nil {
return nil, errors.New("attributedTo was empty")
}
statusOwner := &gtsmodel.Status{}
if err := c.db.GetWhere("uri", attributedTo.String(), statusOwner); err != nil {
return nil, fmt.Errorf("cannot attribute %s to an account we know: %s", attributedTo.String(), err)
}
status.AccountID = statusOwner.ID
return nil, nil
}

View file

@ -90,6 +90,8 @@ type TypeConverter interface {
// ASPersonToAccount converts a remote account/person/application representation into a gts model account
ASRepresentationToAccount(accountable Accountable) (*gtsmodel.Account, error)
// ASStatus converts a remote activitystreams 'status' representation into a gts model status.
ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, error)
/*
INTERNAL (gts) MODEL TO ACTIVITYSTREAMS MODEL

View file

@ -200,15 +200,15 @@ func (c *converter) AccountToAS(a *gtsmodel.Account) (vocab.ActivityStreamsPerso
// icon
// Used as profile avatar.
if a.AvatarMediaAttachmentID != "" {
iconProperty := streams.NewActivityStreamsIconProperty()
iconImage := streams.NewActivityStreamsImage()
avatar := &gtsmodel.MediaAttachment{}
if err := c.db.GetByID(a.AvatarMediaAttachmentID, avatar); err != nil {
return nil, err
}
iconProperty := streams.NewActivityStreamsIconProperty()
iconImage := streams.NewActivityStreamsImage()
mediaType := streams.NewActivityStreamsMediaTypeProperty()
mediaType.Set(avatar.File.ContentType)
iconImage.SetActivityStreamsMediaType(mediaType)
@ -228,15 +228,15 @@ func (c *converter) AccountToAS(a *gtsmodel.Account) (vocab.ActivityStreamsPerso
// image
// Used as profile header.
if a.HeaderMediaAttachmentID != "" {
headerProperty := streams.NewActivityStreamsImageProperty()
headerImage := streams.NewActivityStreamsImage()
header := &gtsmodel.MediaAttachment{}
if err := c.db.GetByID(a.HeaderMediaAttachmentID, header); err != nil {
return nil, err
}
headerProperty := streams.NewActivityStreamsImageProperty()
headerImage := streams.NewActivityStreamsImage()
mediaType := streams.NewActivityStreamsMediaTypeProperty()
mediaType.Set(header.File.ContentType)
headerImage.SetActivityStreamsMediaType(mediaType)