summaryrefslogtreecommitdiff
path: root/internal/typeutils
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2023-10-04 13:09:42 +0100
committerLibravatar GitHub <noreply@github.com>2023-10-04 13:09:42 +0100
commitc6e00afc7c23df994b70eee89d2d392718e6a321 (patch)
treecee98c1a78e36ba6a0e8183afa0b2796765fe7f6 /internal/typeutils
parent[chore] internal/ap: add pollable AS types, code reformatting, general niceti... (diff)
downloadgotosocial-c6e00afc7c23df994b70eee89d2d392718e6a321.tar.xz
[feature] tentatively start adding polls support (#2249)
Diffstat (limited to 'internal/typeutils')
-rw-r--r--internal/typeutils/astointernal.go50
-rw-r--r--internal/typeutils/internaltoas.go24
-rw-r--r--internal/typeutils/wrap.go83
-rw-r--r--internal/typeutils/wrap_test.go4
4 files changed, 100 insertions, 61 deletions
diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go
index 81dbc6f40..92465c790 100644
--- a/internal/typeutils/astointernal.go
+++ b/internal/typeutils/astointernal.go
@@ -216,40 +216,10 @@ func (c *Converter) ASRepresentationToAccount(ctx context.Context, accountable a
return acct, nil
}
-func (c *Converter) extractAttachments(i ap.WithAttachment) []*gtsmodel.MediaAttachment {
- attachmentProp := i.GetActivityStreamsAttachment()
- if attachmentProp == nil {
- return nil
- }
-
- attachments := make([]*gtsmodel.MediaAttachment, 0, attachmentProp.Len())
-
- for iter := attachmentProp.Begin(); iter != attachmentProp.End(); iter = iter.Next() {
- t := iter.GetType()
- if t == nil {
- continue
- }
-
- attachmentable, ok := t.(ap.Attachmentable)
- if !ok {
- log.Error(nil, "ap attachment was not attachmentable")
- continue
- }
-
- attachment, err := ap.ExtractAttachment(attachmentable)
- if err != nil {
- log.Errorf(nil, "error extracting attachment: %s", err)
- continue
- }
-
- attachments = append(attachments, attachment)
- }
-
- return attachments
-}
-
// ASStatus converts a remote activitystreams 'status' representation into a gts model status.
func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusable) (*gtsmodel.Status, error) {
+ var err error
+
status := new(gtsmodel.Status)
// status.URI
@@ -281,7 +251,19 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
// status.Attachments
//
// Media attachments for later dereferencing.
- status.Attachments = c.extractAttachments(statusable)
+ status.Attachments, err = ap.ExtractAttachments(statusable)
+ if err != nil {
+ l.Warnf("error(s) extracting attachments: %v", err)
+ }
+
+ // status.Poll
+ //
+ // Attached poll information (the statusable will actually
+ // be a Pollable, as a Question is a subset of our Status).
+ if pollable, ok := ap.ToPollable(statusable); ok {
+ // TODO: handle decoding poll data
+ _ = pollable
+ }
// status.Hashtags
//
@@ -341,7 +323,7 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
// error if we don't.
attributedTo, err := ap.ExtractAttributedToURI(statusable)
if err != nil {
- return nil, gtserror.Newf("%w", err)
+ return nil, gtserror.Newf("error extracting attributed to uri: %w", err)
}
accountURI := attributedTo.String()
diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go
index d82fe8e04..b920d9a0e 100644
--- a/internal/typeutils/internaltoas.go
+++ b/internal/typeutils/internaltoas.go
@@ -29,6 +29,7 @@ import (
"github.com/superseriousbusiness/activity/pub"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
+ "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -403,21 +404,15 @@ func (c *Converter) AccountToASMinimal(ctx context.Context, a *gtsmodel.Account)
return person, nil
}
-// StatusToAS converts a gts model status into an activity streams note, suitable for federation
-func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (vocab.ActivityStreamsNote, error) {
- // ensure prerequisites here before we get stuck in
-
- // check if author account is already attached to status and attach it if not
- // if we can't retrieve this, bail here already because we can't attribute the status to anyone
- if s.Account == nil {
- a, err := c.state.DB.GetAccountByID(ctx, s.AccountID)
- if err != nil {
- return nil, gtserror.Newf("error retrieving author account from db: %w", err)
- }
- s.Account = a
+// StatusToAS converts a gts model status into an ActivityStreams Statusable implementation, suitable for federation
+func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Statusable, error) {
+ // Ensure the status model is fully populated.
+ // The status and poll models are REQUIRED so nothing to do if this fails.
+ if err := c.state.DB.PopulateStatus(ctx, s); err != nil {
+ return nil, gtserror.Newf("error populating status: %w", err)
}
- // create the Note!
+ // We convert it as an AS Note.
status := streams.NewActivityStreamsNote()
// id
@@ -529,7 +524,6 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (vocab.A
}
tagProp.AppendTootHashtag(asHashtag)
}
-
status.SetActivityStreamsTag(tagProp)
// parse out some URIs we need here
@@ -1419,7 +1413,7 @@ func (c *Converter) StatusesToASOutboxPage(ctx context.Context, outboxID string,
return nil, err
}
- create, err := c.WrapNoteInCreate(note, true)
+ create, err := c.WrapStatusableInCreate(note, true)
if err != nil {
return nil, err
}
diff --git a/internal/typeutils/wrap.go b/internal/typeutils/wrap.go
index 67d3c2b5c..128c4ef15 100644
--- a/internal/typeutils/wrap.go
+++ b/internal/typeutils/wrap.go
@@ -44,7 +44,6 @@ func (c *Converter) WrapPersonInUpdate(person vocab.ActivityStreamsPerson, origi
update.SetActivityStreamsActor(actorProp)
// set the ID
-
newID, err := id.NewRandomULID()
if err != nil {
return nil, err
@@ -85,26 +84,29 @@ func (c *Converter) WrapPersonInUpdate(person vocab.ActivityStreamsPerson, origi
return update, nil
}
-// WrapNoteInCreate wraps a Note with a Create activity.
+// WrapNoteInCreate wraps a Statusable with a Create activity.
//
// If objectIRIOnly is set to true, then the function won't put the *entire* note in the Object field of the Create,
// but just the AP URI of the note. This is useful in cases where you want to give a remote server something to dereference,
// and still have control over whether or not they're allowed to actually see the contents.
-func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOnly bool) (vocab.ActivityStreamsCreate, error) {
+func (c *Converter) WrapStatusableInCreate(status ap.Statusable, objectIRIOnly bool) (vocab.ActivityStreamsCreate, error) {
create := streams.NewActivityStreamsCreate()
// Object property
objectProp := streams.NewActivityStreamsObjectProperty()
if objectIRIOnly {
- objectProp.AppendIRI(note.GetJSONLDId().GetIRI())
+ // Only append the object IRI to objectProp.
+ objectProp.AppendIRI(status.GetJSONLDId().GetIRI())
} else {
- objectProp.AppendActivityStreamsNote(note)
+ // Our statusable's are always note types.
+ asNote := status.(vocab.ActivityStreamsNote)
+ objectProp.AppendActivityStreamsNote(asNote)
}
create.SetActivityStreamsObject(objectProp)
// ID property
idProp := streams.NewJSONLDIdProperty()
- createID := note.GetJSONLDId().GetIRI().String() + "/activity"
+ createID := status.GetJSONLDId().GetIRI().String() + "/activity"
createIDIRI, err := url.Parse(createID)
if err != nil {
return nil, err
@@ -114,7 +116,7 @@ func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOn
// Actor Property
actorProp := streams.NewActivityStreamsActorProperty()
- actorIRI, err := ap.ExtractAttributedToURI(note)
+ actorIRI, err := ap.ExtractAttributedToURI(status)
if err != nil {
return nil, gtserror.Newf("couldn't extract AttributedTo: %w", err)
}
@@ -123,7 +125,7 @@ func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOn
// Published Property
publishedProp := streams.NewActivityStreamsPublishedProperty()
- published, err := ap.ExtractPublished(note)
+ published, err := ap.ExtractPublished(status)
if err != nil {
return nil, gtserror.Newf("couldn't extract Published: %w", err)
}
@@ -132,7 +134,7 @@ func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOn
// To Property
toProp := streams.NewActivityStreamsToProperty()
- if toURIs := ap.ExtractToURIs(note); len(toURIs) != 0 {
+ if toURIs := ap.ExtractToURIs(status); len(toURIs) != 0 {
for _, toURI := range toURIs {
toProp.AppendIRI(toURI)
}
@@ -141,7 +143,7 @@ func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOn
// Cc Property
ccProp := streams.NewActivityStreamsCcProperty()
- if ccURIs := ap.ExtractCcURIs(note); len(ccURIs) != 0 {
+ if ccURIs := ap.ExtractCcURIs(status); len(ccURIs) != 0 {
for _, ccURI := range ccURIs {
ccProp.AppendIRI(ccURI)
}
@@ -150,3 +152,64 @@ func (c *Converter) WrapNoteInCreate(note vocab.ActivityStreamsNote, objectIRIOn
return create, nil
}
+
+// WrapStatusableInUpdate wraps a Statusable with an Update activity.
+//
+// If objectIRIOnly is set to true, then the function won't put the *entire* note in the Object field of the Create,
+// but just the AP URI of the note. This is useful in cases where you want to give a remote server something to dereference,
+// and still have control over whether or not they're allowed to actually see the contents.
+func (c *Converter) WrapStatusableInUpdate(status ap.Statusable, objectIRIOnly bool) (vocab.ActivityStreamsUpdate, error) {
+ update := streams.NewActivityStreamsUpdate()
+
+ // Object property
+ objectProp := streams.NewActivityStreamsObjectProperty()
+ if objectIRIOnly {
+ objectProp.AppendIRI(status.GetJSONLDId().GetIRI())
+ } else if _, ok := status.(ap.Pollable); ok {
+ asQuestion := status.(vocab.ActivityStreamsQuestion)
+ objectProp.AppendActivityStreamsQuestion(asQuestion)
+ } else {
+ asNote := status.(vocab.ActivityStreamsNote)
+ objectProp.AppendActivityStreamsNote(asNote)
+ }
+ update.SetActivityStreamsObject(objectProp)
+
+ // ID property
+ idProp := streams.NewJSONLDIdProperty()
+ createID := status.GetJSONLDId().GetIRI().String() + "/activity"
+ createIDIRI, err := url.Parse(createID)
+ if err != nil {
+ return nil, err
+ }
+ idProp.SetIRI(createIDIRI)
+ update.SetJSONLDId(idProp)
+
+ // Actor Property
+ actorProp := streams.NewActivityStreamsActorProperty()
+ actorIRI, err := ap.ExtractAttributedToURI(status)
+ if err != nil {
+ return nil, gtserror.Newf("couldn't extract AttributedTo: %w", err)
+ }
+ actorProp.AppendIRI(actorIRI)
+ update.SetActivityStreamsActor(actorProp)
+
+ // To Property
+ toProp := streams.NewActivityStreamsToProperty()
+ if toURIs := ap.ExtractToURIs(status); len(toURIs) != 0 {
+ for _, toURI := range toURIs {
+ toProp.AppendIRI(toURI)
+ }
+ update.SetActivityStreamsTo(toProp)
+ }
+
+ // Cc Property
+ ccProp := streams.NewActivityStreamsCcProperty()
+ if ccURIs := ap.ExtractCcURIs(status); len(ccURIs) != 0 {
+ for _, ccURI := range ccURIs {
+ ccProp.AppendIRI(ccURI)
+ }
+ update.SetActivityStreamsCc(ccProp)
+ }
+
+ return update, nil
+}
diff --git a/internal/typeutils/wrap_test.go b/internal/typeutils/wrap_test.go
index 46d28f5c4..51f67f455 100644
--- a/internal/typeutils/wrap_test.go
+++ b/internal/typeutils/wrap_test.go
@@ -36,7 +36,7 @@ func (suite *WrapTestSuite) TestWrapNoteInCreateIRIOnly() {
note, err := suite.typeconverter.StatusToAS(context.Background(), testStatus)
suite.NoError(err)
- create, err := suite.typeconverter.WrapNoteInCreate(note, true)
+ create, err := suite.typeconverter.WrapStatusableInCreate(note, true)
suite.NoError(err)
suite.NotNil(create)
@@ -64,7 +64,7 @@ func (suite *WrapTestSuite) TestWrapNoteInCreate() {
note, err := suite.typeconverter.StatusToAS(context.Background(), testStatus)
suite.NoError(err)
- create, err := suite.typeconverter.WrapNoteInCreate(note, false)
+ create, err := suite.typeconverter.WrapStatusableInCreate(note, false)
suite.NoError(err)
suite.NotNil(create)