summaryrefslogtreecommitdiff
path: root/internal/processing/status
diff options
context:
space:
mode:
Diffstat (limited to 'internal/processing/status')
-rw-r--r--internal/processing/status/pin.go56
1 files changed, 52 insertions, 4 deletions
diff --git a/internal/processing/status/pin.go b/internal/processing/status/pin.go
index 9a4a4b266..d0688331b 100644
--- a/internal/processing/status/pin.go
+++ b/internal/processing/status/pin.go
@@ -82,18 +82,26 @@ func (p *Processor) PinCreate(ctx context.Context, requestingAccount *gtsmodel.A
return nil, errWithCode
}
+ // Get a lock on this account.
+ unlock := p.state.AccountLocks.Lock(requestingAccount.URI)
+ defer unlock()
+
if !targetStatus.PinnedAt.IsZero() {
err := errors.New("status already pinned")
return nil, gtserror.NewErrorUnprocessableEntity(err, err.Error())
}
- pinnedCount, err := p.state.DB.CountAccountPinned(ctx, requestingAccount.ID)
- if err != nil {
- return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking number of pinned statuses: %w", err))
+ // Ensure account stats populated.
+ if requestingAccount.Stats == nil {
+ if err := p.state.DB.PopulateAccountStats(ctx, requestingAccount); err != nil {
+ err = gtserror.Newf("db error getting account stats: %w", err)
+ return nil, gtserror.NewErrorInternalError(err)
+ }
}
+ pinnedCount := *requestingAccount.Stats.StatusesPinnedCount
if pinnedCount >= allowedPinnedCount {
- err = fmt.Errorf("status pin limit exceeded, you've already pinned %d status(es) out of %d", pinnedCount, allowedPinnedCount)
+ err := fmt.Errorf("status pin limit exceeded, you've already pinned %d status(es) out of %d", pinnedCount, allowedPinnedCount)
return nil, gtserror.NewErrorUnprocessableEntity(err, err.Error())
}
@@ -103,6 +111,17 @@ func (p *Processor) PinCreate(ctx context.Context, requestingAccount *gtsmodel.A
return nil, gtserror.NewErrorInternalError(err)
}
+ // Update account stats.
+ *requestingAccount.Stats.StatusesPinnedCount++
+ if err := p.state.DB.UpdateAccountStats(
+ ctx,
+ requestingAccount.Stats,
+ "statuses_pinned_count",
+ ); err != nil {
+ err = gtserror.Newf("db error updating stats: %w", err)
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
if err := p.c.InvalidateTimelinedStatus(ctx, requestingAccount.ID, targetStatusID); err != nil {
err = gtserror.Newf("error invalidating status from timelines: %w", err)
return nil, gtserror.NewErrorInternalError(err)
@@ -128,16 +147,45 @@ func (p *Processor) PinRemove(ctx context.Context, requestingAccount *gtsmodel.A
return nil, errWithCode
}
+ // Get a lock on this account.
+ unlock := p.state.AccountLocks.Lock(requestingAccount.URI)
+ defer unlock()
+
if targetStatus.PinnedAt.IsZero() {
+ // Status already not pinned.
return p.c.GetAPIStatus(ctx, requestingAccount, targetStatus)
}
+ // Ensure account stats populated.
+ if requestingAccount.Stats == nil {
+ if err := p.state.DB.PopulateAccountStats(ctx, requestingAccount); err != nil {
+ err = gtserror.Newf("db error getting account stats: %w", err)
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+ }
+
targetStatus.PinnedAt = time.Time{}
if err := p.state.DB.UpdateStatus(ctx, targetStatus, "pinned_at"); err != nil {
err = gtserror.Newf("db error unpinning status: %w", err)
return nil, gtserror.NewErrorInternalError(err)
}
+ // Update account stats.
+ //
+ // Clamp to 0 to avoid funny business.
+ *requestingAccount.Stats.StatusesPinnedCount--
+ if *requestingAccount.Stats.StatusesPinnedCount < 0 {
+ *requestingAccount.Stats.StatusesPinnedCount = 0
+ }
+ if err := p.state.DB.UpdateAccountStats(
+ ctx,
+ requestingAccount.Stats,
+ "statuses_pinned_count",
+ ); err != nil {
+ err = gtserror.Newf("db error updating stats: %w", err)
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
if err := p.c.InvalidateTimelinedStatus(ctx, requestingAccount.ID, targetStatusID); err != nil {
err = gtserror.Newf("error invalidating status from timelines: %w", err)
return nil, gtserror.NewErrorInternalError(err)