[bugfix] more robust list timeline invalidation (#1995)

This commit is contained in:
kim 2023-07-18 09:43:17 +01:00 committed by GitHub
commit f4319740ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 254 additions and 226 deletions

View file

@ -82,6 +82,7 @@ func (p *Processor) BookmarksGet(ctx context.Context, requestingAccount *gtsmode
if bookmark.ID < nextMaxIDValue {
nextMaxIDValue = bookmark.ID // Lowest ID (for paging down).
}
if bookmark.ID > prevMinIDValue {
prevMinIDValue = bookmark.ID // Highest ID (for paging up).
}

View file

@ -93,28 +93,21 @@ func (p *Processor) StatusesGet(
}
var (
items = make([]interface{}, 0, count)
nextMaxIDValue string
prevMinIDValue string
)
items = make([]interface{}, 0, count)
for i, s := range filtered {
// Set next + prev values before filtering and API
// converting, so caller can still page properly.
if i == count-1 {
nextMaxIDValue = s.ID
}
if i == 0 {
prevMinIDValue = s.ID
}
nextMaxIDValue = filtered[count-1].ID
prevMinIDValue = filtered[0].ID
)
for _, s := range filtered {
// Convert filtered statuses to API statuses.
item, err := p.tc.StatusToAPIStatus(ctx, s, requestingAccount)
if err != nil {
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
log.Errorf(ctx, "error convering to api status: %v", err)
continue
}
items = append(items, item)
}
@ -171,23 +164,20 @@ func (p *Processor) WebStatusesGet(ctx context.Context, targetAccountID string,
}
var (
items = make([]interface{}, 0, count)
nextMaxIDValue string
)
items = make([]interface{}, 0, count)
for i, s := range statuses {
// Set next value before API converting,
// so caller can still page properly.
if i == count-1 {
nextMaxIDValue = s.ID
}
nextMaxIDValue = statuses[count-1].ID
)
for _, s := range statuses {
// Convert fetched statuses to API statuses.
item, err := p.tc.StatusToAPIStatus(ctx, s, nil)
if err != nil {
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
log.Errorf(ctx, "error convering to api status: %v", err)
continue
}
items = append(items, item)
}

View file

@ -54,22 +54,14 @@ func (p *Processor) ReportsGet(
count := len(reports)
items := make([]interface{}, 0, count)
nextMaxIDValue := ""
prevMinIDValue := ""
for i, r := range reports {
nextMaxIDValue := reports[count-1].ID
prevMinIDValue := reports[0].ID
for _, r := range reports {
item, err := p.tc.ReportToAdminAPIReport(ctx, r, account)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err))
}
if i == count-1 {
nextMaxIDValue = item.ID
}
if i == 0 {
prevMinIDValue = item.ID
}
items = append(items, item)
}

View file

@ -27,7 +27,8 @@ import (
// Delete deletes one list for the given account.
func (p *Processor) Delete(ctx context.Context, account *gtsmodel.Account, id string) gtserror.WithCode {
list, errWithCode := p.getList(
// Ensure list exists + is owned by requesting account.
_, errWithCode := p.getList(
// Use barebones ctx; no embedded
// structs necessary for this call.
gtscontext.SetBarebones(ctx),
@ -38,7 +39,7 @@ func (p *Processor) Delete(ctx context.Context, account *gtsmodel.Account, id st
return errWithCode
}
if err := p.state.DB.DeleteListByID(ctx, list.ID); err != nil {
if err := p.state.DB.DeleteListByID(ctx, id); err != nil {
return gtserror.NewErrorInternalError(err)
}

View file

@ -87,7 +87,14 @@ func (p *Processor) GetListAccounts(
limit int,
) (*apimodel.PageableResponse, gtserror.WithCode) {
// Ensure list exists + is owned by requesting account.
if _, errWithCode := p.getList(ctx, account.ID, listID); errWithCode != nil {
_, errWithCode := p.getList(
// Use barebones ctx; no embedded
// structs necessary for this call.
gtscontext.SetBarebones(ctx),
account.ID,
listID,
)
if errWithCode != nil {
return nil, errWithCode
}
@ -106,9 +113,12 @@ func (p *Processor) GetListAccounts(
}
var (
items = make([]interface{}, count)
nextMaxIDValue string
prevMinIDValue string
items = make([]interface{}, 0, count)
// Set next + prev values before filtering and API
// converting, so caller can still page properly.
nextMaxIDValue = listEntries[count-1].ID
prevMinIDValue = listEntries[0].ID
)
// For each list entry, we want the account it points to.
@ -117,37 +127,29 @@ func (p *Processor) GetListAccounts(
// from that follow.
//
// We do paging not by account ID, but by list entry ID.
for i, listEntry := range listEntries {
if i == count-1 {
nextMaxIDValue = listEntry.ID
}
if i == 0 {
prevMinIDValue = listEntry.ID
}
for _, listEntry := range listEntries {
if err := p.state.DB.PopulateListEntry(ctx, listEntry); err != nil {
log.Debugf(ctx, "skipping list entry because of error populating it: %q", err)
log.Errorf(ctx, "error populating list entry: %v", err)
continue
}
if err := p.state.DB.PopulateFollow(ctx, listEntry.Follow); err != nil {
log.Debugf(ctx, "skipping list entry because of error populating follow: %q", err)
log.Errorf(ctx, "error populating follow: %v", err)
continue
}
apiAccount, err := p.tc.AccountToAPIAccountPublic(ctx, listEntry.Follow.TargetAccount)
if err != nil {
log.Debugf(ctx, "skipping list entry because of error converting follow target account: %q", err)
log.Errorf(ctx, "error converting to public api account: %v", err)
continue
}
items[i] = apiAccount
items = append(items, apiAccount)
}
return util.PackagePageableResponse(util.PageableResponseParams{
Items: items,
Path: "api/v1/lists/" + listID + "/accounts",
Path: "/api/v1/lists/" + listID + "/accounts",
NextMaxIDValue: nextMaxIDValue,
PrevMinIDValue: prevMinIDValue,
Limit: limit,

View file

@ -19,6 +19,7 @@ package report
import (
"context"
"errors"
"fmt"
"strconv"
@ -64,31 +65,24 @@ func (p *Processor) GetMultiple(
limit int,
) (*apimodel.PageableResponse, gtserror.WithCode) {
reports, err := p.state.DB.GetReports(ctx, resolved, account.ID, targetAccountID, maxID, sinceID, minID, limit)
if err != nil {
if err == db.ErrNoEntries {
return util.EmptyPageableResponse(), nil
}
if err != nil && !errors.Is(err, db.ErrNoEntries) {
return nil, gtserror.NewErrorInternalError(err)
}
count := len(reports)
if count == 0 {
return util.EmptyPageableResponse(), nil
}
items := make([]interface{}, 0, count)
nextMaxIDValue := ""
prevMinIDValue := ""
for i, r := range reports {
nextMaxIDValue := reports[count-1].ID
prevMinIDValue := reports[0].ID
for _, r := range reports {
item, err := p.tc.ReportToAPIReport(ctx, r)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err))
}
if i == count-1 {
nextMaxIDValue = item.ID
}
if i == 0 {
prevMinIDValue = item.ID
}
items = append(items, item)
}

View file

@ -46,7 +46,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *oauth.Auth, ma
for _, s := range statuses {
visible, err := p.filter.StatusVisible(ctx, authed.Account, s)
if err != nil {
log.Debugf(ctx, "skipping status %s because of an error checking status visibility: %s", s.ID, err)
log.Errorf(ctx, "error checking status visibility: %v", err)
continue
}
@ -56,7 +56,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *oauth.Auth, ma
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
if err != nil {
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
log.Errorf(ctx, "error convering to api status: %v", err)
continue
}
@ -65,7 +65,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *oauth.Auth, ma
return util.PackagePageableResponse(util.PageableResponseParams{
Items: items,
Path: "api/v1/favourites",
Path: "/api/v1/favourites",
NextMaxIDValue: nextMaxID,
PrevMinIDValue: prevMinID,
Limit: limit,

View file

@ -116,25 +116,17 @@ func (p *Processor) HomeTimelineGet(ctx context.Context, authed *oauth.Auth, max
var (
items = make([]interface{}, count)
nextMaxIDValue string
prevMinIDValue string
nextMaxIDValue = statuses[count-1].GetID()
prevMinIDValue = statuses[0].GetID()
)
for i, item := range statuses {
if i == count-1 {
nextMaxIDValue = item.GetID()
}
if i == 0 {
prevMinIDValue = item.GetID()
}
items[i] = item
for i := range statuses {
items[i] = statuses[i]
}
return util.PackagePageableResponse(util.PageableResponseParams{
Items: items,
Path: "api/v1/timelines/home",
Path: "/api/v1/timelines/home",
NextMaxIDValue: nextMaxIDValue,
PrevMinIDValue: prevMinIDValue,
Limit: limit,

View file

@ -142,25 +142,17 @@ func (p *Processor) ListTimelineGet(ctx context.Context, authed *oauth.Auth, lis
var (
items = make([]interface{}, count)
nextMaxIDValue string
prevMinIDValue string
nextMaxIDValue = statuses[count-1].GetID()
prevMinIDValue = statuses[0].GetID()
)
for i, item := range statuses {
if i == count-1 {
nextMaxIDValue = item.GetID()
}
if i == 0 {
prevMinIDValue = item.GetID()
}
items[i] = item
for i := range statuses {
items[i] = statuses[i]
}
return util.PackagePageableResponse(util.PageableResponseParams{
Items: items,
Path: "api/v1/timelines/list/" + listID,
Path: "/api/v1/timelines/list/" + listID,
NextMaxIDValue: nextMaxIDValue,
PrevMinIDValue: prevMinIDValue,
Limit: limit,

View file

@ -43,25 +43,18 @@ func (p *Processor) PublicTimelineGet(ctx context.Context, authed *oauth.Auth, m
}
var (
items = make([]interface{}, 0, count)
nextMaxIDValue string
prevMinIDValue string
)
items = make([]interface{}, 0, count)
for i, s := range statuses {
// Set next + prev values before filtering and API
// converting, so caller can still page properly.
if i == count-1 {
nextMaxIDValue = s.ID
}
if i == 0 {
prevMinIDValue = s.ID
}
nextMaxIDValue = statuses[count-1].ID
prevMinIDValue = statuses[0].ID
)
for _, s := range statuses {
timelineable, err := p.filter.StatusPublicTimelineable(ctx, authed.Account, s)
if err != nil {
log.Debugf(ctx, "skipping status %s because of an error checking StatusPublicTimelineable: %s", s.ID, err)
log.Errorf(ctx, "error checking status visibility: %v", err)
continue
}
@ -71,7 +64,7 @@ func (p *Processor) PublicTimelineGet(ctx context.Context, authed *oauth.Auth, m
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
if err != nil {
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
log.Errorf(ctx, "error convert to api status: %v", err)
continue
}
@ -80,7 +73,7 @@ func (p *Processor) PublicTimelineGet(ctx context.Context, authed *oauth.Auth, m
return util.PackagePageableResponse(util.PageableResponseParams{
Items: items,
Path: "api/v1/timelines/public",
Path: "/api/v1/timelines/public",
NextMaxIDValue: nextMaxIDValue,
PrevMinIDValue: prevMinIDValue,
Limit: limit,