summaryrefslogtreecommitdiff
path: root/internal/federation/dereferencing/status.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/federation/dereferencing/status.go')
-rw-r--r--internal/federation/dereferencing/status.go241
1 files changed, 136 insertions, 105 deletions
diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go
index add12c31f..406534457 100644
--- a/internal/federation/dereferencing/status.go
+++ b/internal/federation/dereferencing/status.go
@@ -33,7 +33,6 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/id"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/media"
- "github.com/superseriousbusiness/gotosocial/internal/transport"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
@@ -536,12 +535,12 @@ func (d *Dereferencer) enrichStatus(
}
// Ensure the status' media attachments are populated, passing in existing to check for changes.
- if err := d.fetchStatusAttachments(ctx, tsport, status, latestStatus); err != nil {
+ if err := d.fetchStatusAttachments(ctx, requestUser, status, latestStatus); err != nil {
return nil, nil, gtserror.Newf("error populating attachments for status %s: %w", uri, err)
}
- // Ensure the status' emoji attachments are populated, (changes are expected / okay).
- if err := d.fetchStatusEmojis(ctx, requestUser, latestStatus); err != nil {
+ // Ensure the status' emoji attachments are populated, passing in existing to check for changes.
+ if err := d.fetchStatusEmojis(ctx, status, latestStatus); err != nil {
return nil, nil, gtserror.Newf("error populating emojis for status %s: %w", uri, err)
}
@@ -643,79 +642,12 @@ func (d *Dereferencer) isPermittedStatus(
return onFail()
}
-// populateMentionTarget tries to populate the given
-// mention with the correct TargetAccount and (if not
-// yet set) TargetAccountURI, returning the populated
-// mention.
-//
-// Will check on the existing status if the mention
-// is already there and populated; if so, existing
-// mention will be returned along with `true`.
-//
-// Otherwise, this function will try to parse first
-// the Href of the mention, and then the namestring,
-// to see who it targets, and go fetch that account.
-func (d *Dereferencer) populateMentionTarget(
+func (d *Dereferencer) fetchStatusMentions(
ctx context.Context,
- mention *gtsmodel.Mention,
requestUser string,
- existing, status *gtsmodel.Status,
-) (
- *gtsmodel.Mention,
- bool, // True if mention already exists in the DB.
- error,
-) {
- // Mentions can be created using Name or Href.
- // Prefer Href (TargetAccountURI), fall back to Name.
- if mention.TargetAccountURI != "" {
- // Look for existing mention with this URI.
- // If we already have it we can return early.
- existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI)
- if ok && existingMention.ID != "" {
- return existingMention, true, nil
- }
-
- // Ensure that mention account URI is parseable.
- accountURI, err := url.Parse(mention.TargetAccountURI)
- if err != nil {
- err = gtserror.Newf("invalid account uri %q: %w", mention.TargetAccountURI, err)
- return nil, false, err
- }
-
- // Ensure we have the account of the mention target dereferenced.
- mention.TargetAccount, _, err = d.getAccountByURI(ctx, requestUser, accountURI)
- if err != nil {
- err = gtserror.Newf("failed to dereference account %s: %w", accountURI, err)
- return nil, false, err
- }
- } else {
- // Href wasn't set. Find the target account using namestring.
- username, domain, err := util.ExtractNamestringParts(mention.NameString)
- if err != nil {
- err = gtserror.Newf("failed to parse namestring %s: %w", mention.NameString, err)
- return nil, false, err
- }
-
- mention.TargetAccount, _, err = d.getAccountByUsernameDomain(ctx, requestUser, username, domain)
- if err != nil {
- err = gtserror.Newf("failed to dereference account %s: %w", mention.NameString, err)
- return nil, false, err
- }
-
- // Look for existing mention with this URI.
- mention.TargetAccountURI = mention.TargetAccount.URI
- existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI)
- if ok && existingMention.ID != "" {
- return existingMention, true, nil
- }
- }
-
- // At this point, mention.TargetAccountURI
- // and mention.TargetAccount must be set.
- return mention, false, nil
-}
-
-func (d *Dereferencer) fetchStatusMentions(ctx context.Context, requestUser string, existing, status *gtsmodel.Status) error {
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+) error {
// Allocate new slice to take the yet-to-be created mention IDs.
status.MentionIDs = make([]string, len(status.Mentions))
@@ -728,10 +660,10 @@ func (d *Dereferencer) fetchStatusMentions(ctx context.Context, requestUser stri
mention, alreadyExists, err = d.populateMentionTarget(
ctx,
- mention,
requestUser,
existing,
status,
+ mention,
)
if err != nil {
log.Errorf(ctx, "failed to derive mention: %v", err)
@@ -845,7 +777,11 @@ func (d *Dereferencer) threadStatus(ctx context.Context, status *gtsmodel.Status
return nil
}
-func (d *Dereferencer) fetchStatusTags(ctx context.Context, existing, status *gtsmodel.Status) error {
+func (d *Dereferencer) fetchStatusTags(
+ ctx context.Context,
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+) error {
// Allocate new slice to take the yet-to-be determined tag IDs.
status.TagIDs = make([]string, len(status.Tags))
@@ -900,7 +836,11 @@ func (d *Dereferencer) fetchStatusTags(ctx context.Context, existing, status *gt
return nil
}
-func (d *Dereferencer) fetchStatusPoll(ctx context.Context, existing, status *gtsmodel.Status) error {
+func (d *Dereferencer) fetchStatusPoll(
+ ctx context.Context,
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+) error {
var (
// insertStatusPoll generates ID and inserts the poll attached to status into the database.
insertStatusPoll = func(ctx context.Context, status *gtsmodel.Status) error {
@@ -990,19 +930,24 @@ func (d *Dereferencer) fetchStatusPoll(ctx context.Context, existing, status *gt
}
}
-func (d *Dereferencer) fetchStatusAttachments(ctx context.Context, tsport transport.Transport, existing, status *gtsmodel.Status) error {
+func (d *Dereferencer) fetchStatusAttachments(
+ ctx context.Context,
+ requestUser string,
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+) error {
// Allocate new slice to take the yet-to-be fetched attachment IDs.
status.AttachmentIDs = make([]string, len(status.Attachments))
for i := range status.Attachments {
- attachment := status.Attachments[i]
+ placeholder := status.Attachments[i]
// Look for existing media attachment with remote URL first.
- existing, ok := existing.GetAttachmentByRemoteURL(attachment.RemoteURL)
+ existing, ok := existing.GetAttachmentByRemoteURL(placeholder.RemoteURL)
if ok && existing.ID != "" {
// Ensure the existing media attachment is up-to-date and cached.
- existing, err := d.updateAttachment(ctx, tsport, existing, attachment)
+ existing, err := d.updateAttachment(ctx, requestUser, existing, placeholder)
if err != nil {
log.Errorf(ctx, "error updating existing attachment: %v", err)
@@ -1019,25 +964,25 @@ func (d *Dereferencer) fetchStatusAttachments(ctx context.Context, tsport transp
}
// Load this new media attachment.
- attachment, err := d.loadAttachment(
+ attachment, err := d.GetMedia(
ctx,
- tsport,
+ requestUser,
status.AccountID,
- attachment.RemoteURL,
- &media.AdditionalMediaInfo{
+ placeholder.RemoteURL,
+ media.AdditionalMediaInfo{
StatusID: &status.ID,
- RemoteURL: &attachment.RemoteURL,
- Description: &attachment.Description,
- Blurhash: &attachment.Blurhash,
+ RemoteURL: &placeholder.RemoteURL,
+ Description: &placeholder.Description,
+ Blurhash: &placeholder.Blurhash,
},
)
- if err != nil && attachment == nil {
- log.Errorf(ctx, "error loading attachment: %v", err)
- continue
- }
-
if err != nil {
- // A non-fatal error occurred during loading.
+ if attachment == nil {
+ log.Errorf(ctx, "error loading attachment %s: %v", placeholder.RemoteURL, err)
+ continue
+ }
+
+ // non-fatal error occurred during loading, still use it.
log.Warnf(ctx, "partially loaded attachment: %v", err)
}
@@ -1061,22 +1006,108 @@ func (d *Dereferencer) fetchStatusAttachments(ctx context.Context, tsport transp
return nil
}
-func (d *Dereferencer) fetchStatusEmojis(ctx context.Context, requestUser string, status *gtsmodel.Status) error {
- // Fetch the full-fleshed-out emoji objects for our status.
- emojis, err := d.populateEmojis(ctx, status.Emojis, requestUser)
+func (d *Dereferencer) fetchStatusEmojis(
+ ctx context.Context,
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+) error {
+ // Fetch the updated emojis for our status.
+ emojis, changed, err := d.fetchEmojis(ctx,
+ existing.Emojis,
+ status.Emojis,
+ )
if err != nil {
- return gtserror.Newf("failed to populate emojis: %w", err)
+ return gtserror.Newf("error fetching emojis: %w", err)
}
- // Iterate over and get their IDs.
- emojiIDs := make([]string, 0, len(emojis))
- for _, e := range emojis {
- emojiIDs = append(emojiIDs, e.ID)
+ if !changed {
+ // Use existing status emoji objects.
+ status.EmojiIDs = existing.EmojiIDs
+ status.Emojis = existing.Emojis
+ return nil
}
- // Set known emoji details.
+ // Set latest emojis.
status.Emojis = emojis
- status.EmojiIDs = emojiIDs
+
+ // Iterate over and set changed emoji IDs.
+ status.EmojiIDs = make([]string, len(emojis))
+ for i, emoji := range emojis {
+ status.EmojiIDs[i] = emoji.ID
+ }
return nil
}
+
+// populateMentionTarget tries to populate the given
+// mention with the correct TargetAccount and (if not
+// yet set) TargetAccountURI, returning the populated
+// mention.
+//
+// Will check on the existing status if the mention
+// is already there and populated; if so, existing
+// mention will be returned along with `true`.
+//
+// Otherwise, this function will try to parse first
+// the Href of the mention, and then the namestring,
+// to see who it targets, and go fetch that account.
+func (d *Dereferencer) populateMentionTarget(
+ ctx context.Context,
+ requestUser string,
+ existing *gtsmodel.Status,
+ status *gtsmodel.Status,
+ mention *gtsmodel.Mention,
+) (
+ *gtsmodel.Mention,
+ bool, // True if mention already exists in the DB.
+ error,
+) {
+ // Mentions can be created using Name or Href.
+ // Prefer Href (TargetAccountURI), fall back to Name.
+ if mention.TargetAccountURI != "" {
+ // Look for existing mention with this URI.
+ // If we already have it we can return early.
+ existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI)
+ if ok && existingMention.ID != "" {
+ return existingMention, true, nil
+ }
+
+ // Ensure that mention account URI is parseable.
+ accountURI, err := url.Parse(mention.TargetAccountURI)
+ if err != nil {
+ err = gtserror.Newf("invalid account uri %q: %w", mention.TargetAccountURI, err)
+ return nil, false, err
+ }
+
+ // Ensure we have the account of the mention target dereferenced.
+ mention.TargetAccount, _, err = d.getAccountByURI(ctx, requestUser, accountURI)
+ if err != nil {
+ err = gtserror.Newf("failed to dereference account %s: %w", accountURI, err)
+ return nil, false, err
+ }
+ } else {
+ // Href wasn't set. Find the target account using namestring.
+ username, domain, err := util.ExtractNamestringParts(mention.NameString)
+ if err != nil {
+ err = gtserror.Newf("failed to parse namestring %s: %w", mention.NameString, err)
+ return nil, false, err
+ }
+
+ mention.TargetAccount, _, err = d.getAccountByUsernameDomain(ctx, requestUser, username, domain)
+ if err != nil {
+ err = gtserror.Newf("failed to dereference account %s: %w", mention.NameString, err)
+ return nil, false, err
+ }
+
+ // Look for existing mention with this URI.
+ mention.TargetAccountURI = mention.TargetAccount.URI
+ existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI)
+ if ok && existingMention.ID != "" {
+ return existingMention, true, nil
+ }
+ }
+
+ // At this point, mention.TargetAccountURI
+ // and mention.TargetAccount must be set.
+ return mention, false, nil
+}