diff options
| author | 2023-10-04 13:09:42 +0100 | |
|---|---|---|
| committer | 2023-10-04 13:09:42 +0100 | |
| commit | c6e00afc7c23df994b70eee89d2d392718e6a321 (patch) | |
| tree | cee98c1a78e36ba6a0e8183afa0b2796765fe7f6 /internal/typeutils | |
| parent | [chore] internal/ap: add pollable AS types, code reformatting, general niceti... (diff) | |
| download | gotosocial-c6e00afc7c23df994b70eee89d2d392718e6a321.tar.xz | |
[feature] tentatively start adding polls support (#2249)
Diffstat (limited to 'internal/typeutils')
| -rw-r--r-- | internal/typeutils/astointernal.go | 50 | ||||
| -rw-r--r-- | internal/typeutils/internaltoas.go | 24 | ||||
| -rw-r--r-- | internal/typeutils/wrap.go | 83 | ||||
| -rw-r--r-- | internal/typeutils/wrap_test.go | 4 | 
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)  | 
