summaryrefslogtreecommitdiff
path: root/internal/federation
diff options
context:
space:
mode:
Diffstat (limited to 'internal/federation')
-rw-r--r--internal/federation/dereferencing/announce.go125
-rw-r--r--internal/federation/federatingdb/announce_test.go12
2 files changed, 91 insertions, 46 deletions
diff --git a/internal/federation/dereferencing/announce.go b/internal/federation/dereferencing/announce.go
index 22c33685a..8e880dad5 100644
--- a/internal/federation/dereferencing/announce.go
+++ b/internal/federation/dereferencing/announce.go
@@ -20,66 +20,107 @@ package dereferencing
import (
"context"
"errors"
- "fmt"
"net/url"
"github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+ "github.com/superseriousbusiness/gotosocial/internal/id"
)
-func (d *Dereferencer) DereferenceAnnounce(ctx context.Context, announce *gtsmodel.Status, requestingUsername string) error {
- if announce.BoostOf == nil {
- // we can't do anything unfortunately
- return errors.New("DereferenceAnnounce: no URI to dereference")
+// EnrichAnnounce enriches the given boost wrapper status
+// by either fetching from the DB or dereferencing the target
+// status, populating the boost wrapper's fields based on the
+// target status, and then storing the wrapper in the database.
+// The wrapper is then returned to the caller.
+//
+// The provided boost wrapper status must have BoostOfURI set.
+func (d *Dereferencer) EnrichAnnounce(
+ ctx context.Context,
+ boost *gtsmodel.Status,
+ requestUser string,
+) (*gtsmodel.Status, error) {
+ targetURI := boost.BoostOfURI
+ if targetURI == "" {
+ // We can't do anything.
+ return nil, gtserror.Newf("no URI to dereference")
}
- // Parse the boosted status' URI
- boostedURI, err := url.Parse(announce.BoostOf.URI)
+ // Parse the boost target status URI.
+ targetURIObj, err := url.Parse(targetURI)
if err != nil {
- return fmt.Errorf("DereferenceAnnounce: couldn't parse boosted status URI %s: %s", announce.BoostOf.URI, err)
+ return nil, gtserror.Newf(
+ "couldn't parse boost target status URI %s: %w",
+ targetURI, err,
+ )
}
- // Check whether the originating status is from a blocked host
- if blocked, err := d.state.DB.IsDomainBlocked(ctx, boostedURI.Host); blocked || err != nil {
- return fmt.Errorf("DereferenceAnnounce: domain %s is blocked", boostedURI.Host)
+ // Fetch/deref status being boosted.
+ var target *gtsmodel.Status
+
+ if targetURIObj.Host == config.GetHost() {
+ // This is a local status, fetch from the database
+ target, err = d.state.DB.GetStatusByURI(ctx, targetURI)
+ } else {
+ // This is a remote status, we need to dereference it.
+ //
+ // d.GetStatusByURI will handle domain block checking for us,
+ // so we don't try to deref an announce target on a blocked host.
+ target, _, err = d.GetStatusByURI(ctx, requestUser, targetURIObj)
}
- var boostedStatus *gtsmodel.Status
+ if err != nil {
+ return nil, gtserror.Newf(
+ "error getting boost target status %s: %w",
+ targetURI, err,
+ )
+ }
- if boostedURI.Host == config.GetHost() {
- // This is a local status, fetch from the database
- status, err := d.state.DB.GetStatusByURI(ctx, boostedURI.String())
- if err != nil {
- return fmt.Errorf("DereferenceAnnounce: error fetching local status %q: %v", announce.BoostOf.URI, err)
- }
+ // Generate an ID for the boost wrapper status.
+ boost.ID, err = id.NewULIDFromTime(boost.CreatedAt)
+ if err != nil {
+ return nil, gtserror.Newf("error generating id: %w", err)
+ }
- // Set boosted status
- boostedStatus = status
- } else {
- // This is a boost of a remote status, we need to dereference it.
- status, _, err := d.GetStatusByURI(ctx, requestingUsername, boostedURI)
+ // Populate remaining fields on
+ // the boost wrapper using target.
+ boost.Content = target.Content
+ boost.ContentWarning = target.ContentWarning
+ boost.ActivityStreamsType = target.ActivityStreamsType
+ boost.Sensitive = target.Sensitive
+ boost.Language = target.Language
+ boost.Text = target.Text
+ boost.BoostOfID = target.ID
+ boost.BoostOf = target
+ boost.BoostOfAccountID = target.AccountID
+ boost.BoostOfAccount = target.Account
+ boost.Visibility = target.Visibility
+ boost.Federated = target.Federated
+ boost.Boostable = target.Boostable
+ boost.Replyable = target.Replyable
+ boost.Likeable = target.Likeable
+
+ // Store the boost wrapper status.
+ switch err = d.state.DB.PutStatus(ctx, boost); {
+ case err == nil:
+ // All good baby.
+
+ case errors.Is(err, db.ErrAlreadyExists):
+ // DATA RACE! We likely lost out to another goroutine
+ // in a call to db.Put(Status). Look again in DB by URI.
+ boost, err = d.state.DB.GetStatusByURI(ctx, boost.URI)
if err != nil {
- return fmt.Errorf("DereferenceAnnounce: error dereferencing remote status with id %s: %s", announce.BoostOf.URI, err)
+ err = gtserror.Newf(
+ "error getting boost wrapper status %s from database after race: %w",
+ boost.URI, err,
+ )
}
- // Set boosted status
- boostedStatus = status
+ default:
+ // Proper database error.
+ err = gtserror.Newf("db error inserting status: %w", err)
}
- announce.Content = boostedStatus.Content
- announce.ContentWarning = boostedStatus.ContentWarning
- announce.ActivityStreamsType = boostedStatus.ActivityStreamsType
- announce.Sensitive = boostedStatus.Sensitive
- announce.Language = boostedStatus.Language
- announce.Text = boostedStatus.Text
- announce.BoostOfID = boostedStatus.ID
- announce.BoostOfAccountID = boostedStatus.AccountID
- announce.Visibility = boostedStatus.Visibility
- announce.Federated = boostedStatus.Federated
- announce.Boostable = boostedStatus.Boostable
- announce.Replyable = boostedStatus.Replyable
- announce.Likeable = boostedStatus.Likeable
- announce.BoostOf = boostedStatus
-
- return nil
+ return boost, err
}
diff --git a/internal/federation/federatingdb/announce_test.go b/internal/federation/federatingdb/announce_test.go
index ae5213f66..d8de2e49c 100644
--- a/internal/federation/federatingdb/announce_test.go
+++ b/internal/federation/federatingdb/announce_test.go
@@ -50,8 +50,10 @@ func (suite *AnnounceTestSuite) TestNewAnnounce() {
suite.True(ok)
suite.Equal(announcingAccount.ID, boost.AccountID)
- // only the URI will be set on the boosted status because it still needs to be dereferenced
- suite.NotEmpty(boost.BoostOf.URI)
+ // only the URI will be set for the boosted status
+ // because it still needs to be dereferenced
+ suite.Nil(boost.BoostOf)
+ suite.Equal("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1", boost.BoostOfURI)
}
func (suite *AnnounceTestSuite) TestAnnounceTwice() {
@@ -81,8 +83,10 @@ func (suite *AnnounceTestSuite) TestAnnounceTwice() {
return nil
})
- // only the URI will be set on the boosted status because it still needs to be dereferenced
- suite.NotEmpty(boost.BoostOf.URI)
+ // only the URI will be set for the boosted status
+ // because it still needs to be dereferenced
+ suite.Nil(boost.BoostOf)
+ suite.Equal("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1", boost.BoostOfURI)
ctx2 := createTestContext(receivingAccount2, announcingAccount)
announce2 := suite.testActivities["announce_forwarded_1_turtle"]