diff --git a/internal/db/pg/statuscontext.go b/internal/db/pg/statuscontext.go index b88ef2e..e907a2d 100644 --- a/internal/db/pg/statuscontext.go +++ b/internal/db/pg/statuscontext.go @@ -1,8 +1,10 @@ package pg import ( + "container/list" + "errors" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" - "sync" ) func (ps *postgresService) StatusParents(status *gtsmodel.Status) ([]*gtsmodel.Status, error) { @@ -26,25 +28,48 @@ func (ps *postgresService) statusParent(status *gtsmodel.Status, foundStatuses * } func (ps *postgresService) StatusChildren(status *gtsmodel.Status) ([]*gtsmodel.Status, error) { + foundStatuses := &list.List{} + foundStatuses.PushFront(status) + ps.statusChildren(status, foundStatuses) + children := []*gtsmodel.Status{} - // ps.statusChildren(status, &children) - + for e := foundStatuses.Front(); e != nil; e = e.Next() { + entry, ok := e.Value.(*gtsmodel.Status) + if !ok { + panic(errors.New("entry in foundStatuses was not a *gtsmodel.Status")) + } + + // only append children, not the overall parent status + if entry.ID != status.ID { + children = append(children, entry) + } + } + return children, nil } -func (ps *postgresService) statusChildren(status *gtsmodel.Status, foundStatuses *sync.Map) { - // immediateChildren := []*gtsmodel.Status{} - - // foundStatuses.Store() +func (ps *postgresService) statusChildren(status *gtsmodel.Status, foundStatuses *list.List) { + immediateChildren := []*gtsmodel.Status{} - // err := ps.conn.Model(&immediateChildren).Where("in_reply_to_id = ?", status.ID).Select() - // if err != nil { - // return - // } + err := ps.conn.Model(&immediateChildren).Where("in_reply_to_id = ?", status.ID).Select() + if err != nil { + return + } - // for _, child := range immediateChildren { - // f[""][0] = child - // } + for _, child := range immediateChildren { + insertLoop: + for e := foundStatuses.Front(); e != nil; e = e.Next() { + entry, ok := e.Value.(*gtsmodel.Status) + if !ok { + panic(errors.New("entry in foundStatuses was not a *gtsmodel.Status")) + } - return + if child.InReplyToAccountID != "" && entry.ID == child.InReplyToID { + foundStatuses.InsertAfter(child, e) + break insertLoop + } + } + + ps.statusChildren(child, foundStatuses) + } } diff --git a/internal/processing/synchronous/status/context.go b/internal/processing/synchronous/status/context.go index 4673982..72b9b56 100644 --- a/internal/processing/synchronous/status/context.go +++ b/internal/processing/synchronous/status/context.go @@ -47,6 +47,10 @@ func (p *processor) Context(account *gtsmodel.Account, targetStatusID string) (* } } + sort.Slice(context.Ancestors, func(i int, j int) bool { + return context.Ancestors[i].ID < context.Ancestors[j].ID + }) + children, err := p.db.StatusChildren(targetStatus) if err != nil { return nil, gtserror.NewErrorInternalError(err) @@ -56,18 +60,10 @@ func (p *processor) Context(account *gtsmodel.Account, targetStatusID string) (* if v, err := p.filter.StatusVisible(status, account); err == nil && v { mastoStatus, err := p.tc.StatusToMasto(status, account) if err == nil { - context.Ancestors = append(context.Ancestors, *mastoStatus) + context.Descendants = append(context.Descendants, *mastoStatus) } } } - sort.Slice(context.Ancestors, func(i int, j int) bool { - return context.Ancestors[i].ID < context.Ancestors[j].ID - }) - - sort.Slice(context.Descendants, func(i int, j int) bool { - return context.Descendants[i].ID < context.Descendants[j].ID - }) - return context, nil } diff --git a/internal/visibility/statushometimelineable.go b/internal/visibility/statushometimelineable.go index 62c0acc..f349b3a 100644 --- a/internal/visibility/statushometimelineable.go +++ b/internal/visibility/statushometimelineable.go @@ -7,18 +7,18 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (f *filter) StatusHometimelineable(targetStatus *gtsmodel.Status, requestingAccount *gtsmodel.Account) (bool, error) { +func (f *filter) StatusHometimelineable(targetStatus *gtsmodel.Status, timelineOwnerAccount *gtsmodel.Account) (bool, error) { l := f.log.WithFields(logrus.Fields{ - "func": "StatusHometimelineable", - "statusID": targetStatus.ID, + "func": "StatusHometimelineable", + "statusID": targetStatus.ID, }) - // status owner should always be able to see their status in their timeline so we can return early if this is the case - if requestingAccount != nil && targetStatus.AccountID == requestingAccount.ID { + // status owner should always be able to see their own status in their timeline so we can return early if this is the case + if timelineOwnerAccount != nil && targetStatus.AccountID == timelineOwnerAccount.ID { return true, nil } - v, err := f.StatusVisible(targetStatus, requestingAccount) + v, err := f.StatusVisible(targetStatus, timelineOwnerAccount) if err != nil { return false, fmt.Errorf("StatusHometimelineable: error checking visibility of status with id %s: %s", targetStatus.ID, err) } @@ -48,10 +48,15 @@ func (f *filter) StatusHometimelineable(targetStatus *gtsmodel.Status, requestin targetStatus.GTSReplyToAccount = ra } - // make sure the requesting account follows the replied-to account - follows, err := f.db.Follows(requestingAccount, targetStatus.GTSReplyToAccount) + // if it's a reply to the timelineOwnerAccount, we don't need to check if the timelineOwnerAccount follows itself, just return true, they can see it + if targetStatus.AccountID == timelineOwnerAccount.ID { + return true, nil + } + + // the replied-to account != timelineOwnerAccount, so make sure the timelineOwnerAccount follows the replied-to account + follows, err := f.db.Follows(timelineOwnerAccount, targetStatus.GTSReplyToAccount) if err != nil { - return false, fmt.Errorf("StatusHometimelineable: error checking follow from account %s to account %s: %s", requestingAccount.ID, targetStatus.InReplyToAccountID, err) + return false, fmt.Errorf("StatusHometimelineable: error checking follow from account %s to account %s: %s", timelineOwnerAccount.ID, targetStatus.InReplyToAccountID, err) } if !follows {