summaryrefslogtreecommitdiff
path: root/internal/processing/workers/fromfediapi.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/processing/workers/fromfediapi.go')
-rw-r--r--internal/processing/workers/fromfediapi.go227
1 files changed, 221 insertions, 6 deletions
diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go
index ac4003f6a..63d1f0d16 100644
--- a/internal/processing/workers/fromfediapi.go
+++ b/internal/processing/workers/fromfediapi.go
@@ -122,11 +122,23 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF
// ACCEPT SOMETHING
case ap.ActivityAccept:
- switch fMsg.APObjectType { //nolint:gocritic
+ switch fMsg.APObjectType {
- // ACCEPT FOLLOW
+ // ACCEPT (pending) FOLLOW
case ap.ActivityFollow:
return p.fediAPI.AcceptFollow(ctx, fMsg)
+
+ // ACCEPT (pending) LIKE
+ case ap.ActivityLike:
+ return p.fediAPI.AcceptLike(ctx, fMsg)
+
+ // ACCEPT (pending) REPLY
+ case ap.ObjectNote:
+ return p.fediAPI.AcceptReply(ctx, fMsg)
+
+ // ACCEPT (pending) ANNOUNCE
+ case ap.ActivityAnnounce:
+ return p.fediAPI.AcceptAnnounce(ctx, fMsg)
}
// DELETE SOMETHING
@@ -216,6 +228,52 @@ func (p *fediAPI) CreateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
return nil
}
+ // If pending approval is true then
+ // status must reply to a LOCAL status
+ // that requires approval for the reply.
+ pendingApproval := util.PtrOrValue(
+ status.PendingApproval,
+ false,
+ )
+
+ switch {
+ case pendingApproval && !status.PreApproved:
+ // If approval is required and status isn't
+ // preapproved, then just notify the account
+ // that's being interacted with: they can
+ // approve or deny the interaction later.
+
+ // Notify *local* account of pending reply.
+ if err := p.surface.notifyPendingReply(ctx, status); err != nil {
+ log.Errorf(ctx, "error notifying pending reply: %v", err)
+ }
+
+ // Return early.
+ return nil
+
+ case pendingApproval && status.PreApproved:
+ // If approval is required and status is
+ // preapproved, that means this is a reply
+ // to one of our statuses with permission
+ // that matched on a following/followers
+ // collection. Do the Accept immediately and
+ // then process everything else as normal.
+
+ // Put approval in the database and
+ // update the status with approvedBy URI.
+ approval, err := p.utils.approveReply(ctx, status)
+ if err != nil {
+ return gtserror.Newf("error pre-approving reply: %w", err)
+ }
+
+ // Send out the approval as Accept.
+ if err := p.federate.AcceptInteraction(ctx, approval); err != nil {
+ return gtserror.Newf("error federating pre-approval of reply: %w", err)
+ }
+
+ // Don't return, just continue as normal.
+ }
+
// Update stats for the remote account.
if err := p.utils.incrementStatusesCount(ctx, fMsg.Requesting, status); err != nil {
log.Errorf(ctx, "error updating account stats: %v", err)
@@ -348,6 +406,52 @@ func (p *fediAPI) CreateLike(ctx context.Context, fMsg *messages.FromFediAPI) er
return gtserror.Newf("error populating status fave: %w", err)
}
+ // If pending approval is true then
+ // fave must target a LOCAL status
+ // that requires approval for the fave.
+ pendingApproval := util.PtrOrValue(
+ fave.PendingApproval,
+ false,
+ )
+
+ switch {
+ case pendingApproval && !fave.PreApproved:
+ // If approval is required and fave isn't
+ // preapproved, then just notify the account
+ // that's being interacted with: they can
+ // approve or deny the interaction later.
+
+ // Notify *local* account of pending fave.
+ if err := p.surface.notifyPendingFave(ctx, fave); err != nil {
+ log.Errorf(ctx, "error notifying pending fave: %v", err)
+ }
+
+ // Return early.
+ return nil
+
+ case pendingApproval && fave.PreApproved:
+ // If approval is required and fave is
+ // preapproved, that means this is a fave
+ // of one of our statuses with permission
+ // that matched on a following/followers
+ // collection. Do the Accept immediately and
+ // then process everything else as normal.
+
+ // Put approval in the database and
+ // update the fave with approvedBy URI.
+ approval, err := p.utils.approveFave(ctx, fave)
+ if err != nil {
+ return gtserror.Newf("error pre-approving fave: %w", err)
+ }
+
+ // Send out the approval as Accept.
+ if err := p.federate.AcceptInteraction(ctx, approval); err != nil {
+ return gtserror.Newf("error federating pre-approval of fave: %w", err)
+ }
+
+ // Don't return, just continue as normal.
+ }
+
if err := p.surface.notifyFave(ctx, fave); err != nil {
log.Errorf(ctx, "error notifying fave: %v", err)
}
@@ -365,8 +469,9 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel)
}
- // Dereference status that this boosts, note
- // that this will handle storing the boost in
+ // Dereference into a boost wrapper status.
+ //
+ // Note: this will handle storing the boost in
// the db, and dereferencing the target status
// ancestors / descendants where appropriate.
var err error
@@ -376,8 +481,10 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
fMsg.Receiving.Username,
)
if err != nil {
- if gtserror.IsUnretrievable(err) {
- // Boosted status domain blocked, nothing to do.
+ if gtserror.IsUnretrievable(err) ||
+ gtserror.NotPermitted(err) {
+ // Boosted status domain blocked, or
+ // otherwise not permitted, nothing to do.
log.Debugf(ctx, "skipping announce: %v", err)
return nil
}
@@ -386,6 +493,52 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg *messages.FromFediAPI
return gtserror.Newf("error dereferencing announce: %w", err)
}
+ // If pending approval is true then
+ // boost must target a LOCAL status
+ // that requires approval for the boost.
+ pendingApproval := util.PtrOrValue(
+ boost.PendingApproval,
+ false,
+ )
+
+ switch {
+ case pendingApproval && !boost.PreApproved:
+ // If approval is required and boost isn't
+ // preapproved, then just notify the account
+ // that's being interacted with: they can
+ // approve or deny the interaction later.
+
+ // Notify *local* account of pending announce.
+ if err := p.surface.notifyPendingAnnounce(ctx, boost); err != nil {
+ log.Errorf(ctx, "error notifying pending boost: %v", err)
+ }
+
+ // Return early.
+ return nil
+
+ case pendingApproval && boost.PreApproved:
+ // If approval is required and status is
+ // preapproved, that means this is a boost
+ // of one of our statuses with permission
+ // that matched on a following/followers
+ // collection. Do the Accept immediately and
+ // then process everything else as normal.
+
+ // Put approval in the database and
+ // update the boost with approvedBy URI.
+ approval, err := p.utils.approveAnnounce(ctx, boost)
+ if err != nil {
+ return gtserror.Newf("error pre-approving boost: %w", err)
+ }
+
+ // Send out the approval as Accept.
+ if err := p.federate.AcceptInteraction(ctx, approval); err != nil {
+ return gtserror.Newf("error federating pre-approval of boost: %w", err)
+ }
+
+ // Don't return, just continue as normal.
+ }
+
// Update stats for the remote account.
if err := p.utils.incrementStatusesCount(ctx, fMsg.Requesting, boost); err != nil {
log.Errorf(ctx, "error updating account stats: %v", err)
@@ -549,6 +702,68 @@ func (p *fediAPI) AcceptFollow(ctx context.Context, fMsg *messages.FromFediAPI)
return nil
}
+func (p *fediAPI) AcceptLike(ctx context.Context, fMsg *messages.FromFediAPI) error {
+ // TODO: Add something here if we ever implement sending out Likes to
+ // followers more broadly and not just the owner of the Liked status.
+ return nil
+}
+
+func (p *fediAPI) AcceptReply(ctx context.Context, fMsg *messages.FromFediAPI) error {
+ status, ok := fMsg.GTSModel.(*gtsmodel.Status)
+ if !ok {
+ return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel)
+ }
+
+ // Update stats for the actor account.
+ if err := p.utils.incrementStatusesCount(ctx, status.Account, status); err != nil {
+ log.Errorf(ctx, "error updating account stats: %v", err)
+ }
+
+ // Timeline and notify the status.
+ if err := p.surface.timelineAndNotifyStatus(ctx, status); err != nil {
+ log.Errorf(ctx, "error timelining and notifying status: %v", err)
+ }
+
+ // Interaction counts changed on the replied-to status;
+ // uncache the prepared version from all timelines.
+ p.surface.invalidateStatusFromTimelines(ctx, status.InReplyToID)
+
+ // Send out the reply again, fully this time.
+ if err := p.federate.CreateStatus(ctx, status); err != nil {
+ log.Errorf(ctx, "error federating announce: %v", err)
+ }
+
+ return nil
+}
+
+func (p *fediAPI) AcceptAnnounce(ctx context.Context, fMsg *messages.FromFediAPI) error {
+ boost, ok := fMsg.GTSModel.(*gtsmodel.Status)
+ if !ok {
+ return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel)
+ }
+
+ // Update stats for the actor account.
+ if err := p.utils.incrementStatusesCount(ctx, boost.Account, boost); err != nil {
+ log.Errorf(ctx, "error updating account stats: %v", err)
+ }
+
+ // Timeline and notify the boost wrapper status.
+ if err := p.surface.timelineAndNotifyStatus(ctx, boost); err != nil {
+ log.Errorf(ctx, "error timelining and notifying status: %v", err)
+ }
+
+ // Interaction counts changed on the boosted status;
+ // uncache the prepared version from all timelines.
+ p.surface.invalidateStatusFromTimelines(ctx, boost.BoostOfID)
+
+ // Send out the boost again, fully this time.
+ if err := p.federate.Announce(ctx, boost); err != nil {
+ log.Errorf(ctx, "error federating announce: %v", err)
+ }
+
+ return nil
+}
+
func (p *fediAPI) UpdateStatus(ctx context.Context, fMsg *messages.FromFediAPI) error {
// Cast the existing Status model attached to msg.
existing, ok := fMsg.GTSModel.(*gtsmodel.Status)