mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[bugfix] Fix no notification if mention edited into status (#4102)
This pull request adds mention notifications if a mention was edited into a status after its initial publication. Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3869 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4102 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
@@ -19,9 +19,11 @@ package processing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/config"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/db"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/federation"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
@@ -100,7 +102,29 @@ func GetParseMentionFunc(state *state.State, federator *federation.Federator) gt
|
||||
}
|
||||
}
|
||||
|
||||
// Return mention with useful populated fields,
|
||||
// Check if the mention was
|
||||
// in the database already.
|
||||
if statusID != "" {
|
||||
mention, err := state.DB.GetMentionByTargetAcctStatus(ctx, targetAcct.ID, statusID)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return nil, fmt.Errorf(
|
||||
"db error checking for existing mention: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if mention != nil {
|
||||
// We had it, return this rather
|
||||
// than creating a new one.
|
||||
mention.NameString = namestring
|
||||
mention.OriginAccountURI = originAcct.URI
|
||||
mention.TargetAccountURI = targetAcct.URI
|
||||
mention.TargetAccountURL = targetAcct.URL
|
||||
return mention, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Return new mention with useful populated fields,
|
||||
// but *don't* store it in the database; that's
|
||||
// up to the calling function to do, if they want.
|
||||
return >smodel.Mention{
|
||||
@@ -114,6 +138,10 @@ func GetParseMentionFunc(state *state.State, federator *federation.Federator) gt
|
||||
TargetAccountURL: targetAcct.URL,
|
||||
TargetAccount: targetAcct,
|
||||
NameString: namestring,
|
||||
|
||||
// Mention wasn't
|
||||
// stored in the db.
|
||||
IsNew: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
@@ -729,6 +729,25 @@ func (p *clientAPI) UpdateStatus(ctx context.Context, cMsg *messages.FromClientA
|
||||
}
|
||||
}
|
||||
|
||||
// Notify any *new* mentions added
|
||||
// to this status by the editor.
|
||||
for _, mention := range status.Mentions {
|
||||
// Check if we've seen
|
||||
// this mention already.
|
||||
if !mention.IsNew {
|
||||
// Already seen
|
||||
// it, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
// Haven't seen this mention
|
||||
// yet, notify it if necessary.
|
||||
mention.Status = status
|
||||
if err := p.surface.notifyMention(ctx, mention); err != nil {
|
||||
log.Errorf(ctx, "error notifying mention: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Push message that the status has been edited to streams.
|
||||
if err := p.surface.timelineStatusUpdate(ctx, status); err != nil {
|
||||
log.Errorf(ctx, "error streaming status edit: %v", err)
|
||||
|
@@ -89,6 +89,7 @@ func (suite *FromClientAPITestSuite) newStatus(
|
||||
OriginAccountID: account.ID,
|
||||
OriginAccountURI: account.URI,
|
||||
TargetAccountID: replyToStatus.AccountID,
|
||||
IsNew: true,
|
||||
}
|
||||
|
||||
if err := state.DB.PutMention(ctx, mention); err != nil {
|
||||
@@ -117,6 +118,7 @@ func (suite *FromClientAPITestSuite) newStatus(
|
||||
TargetAccountID: mentionedAccount.ID,
|
||||
TargetAccount: mentionedAccount,
|
||||
Silent: util.Ptr(false),
|
||||
IsNew: true,
|
||||
}
|
||||
|
||||
newStatus.Mentions = append(newStatus.Mentions, newMention)
|
||||
|
@@ -996,7 +996,26 @@ func (p *fediAPI) UpdateStatus(ctx context.Context, fMsg *messages.FromFediAPI)
|
||||
log.Errorf(ctx, "error streaming status edit: %v", err)
|
||||
}
|
||||
|
||||
// Status representation was refetched, uncache from timelines.
|
||||
// Notify any *new* mentions added
|
||||
// to this status by the editor.
|
||||
for _, mention := range status.Mentions {
|
||||
// Check if we've seen
|
||||
// this mention already.
|
||||
if !mention.IsNew {
|
||||
// Already seen
|
||||
// it, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
// Haven't seen this mention
|
||||
// yet, notify it if necessary.
|
||||
mention.Status = status
|
||||
if err := p.surface.notifyMention(ctx, mention); err != nil {
|
||||
log.Errorf(ctx, "error notifying mention: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Status representation changed, uncache from timelines.
|
||||
p.surface.invalidateStatusFromTimelines(status.ID)
|
||||
|
||||
return nil
|
||||
|
@@ -99,56 +99,77 @@ func (s *Surface) notifyMentions(
|
||||
|
||||
for _, mention := range status.Mentions {
|
||||
// Set status on the mention (stops
|
||||
// the below function populating it).
|
||||
// notifyMention having to populate it).
|
||||
mention.Status = status
|
||||
|
||||
// Beforehand, ensure the passed mention is fully populated.
|
||||
if err := s.State.DB.PopulateMention(ctx, mention); err != nil {
|
||||
errs.Appendf("error populating mention %s: %w", mention.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if mention.TargetAccount.IsRemote() {
|
||||
// no need to notify
|
||||
// remote accounts.
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure thread not muted
|
||||
// by mentioned account.
|
||||
muted, err := s.State.DB.IsThreadMutedByAccount(
|
||||
ctx,
|
||||
status.ThreadID,
|
||||
mention.TargetAccountID,
|
||||
)
|
||||
if err != nil {
|
||||
errs.Appendf("error checking status thread mute %s: %w", status.ThreadID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if muted {
|
||||
// This mentioned account
|
||||
// has muted the thread.
|
||||
// Don't pester them.
|
||||
continue
|
||||
}
|
||||
|
||||
// notify mentioned
|
||||
// by status author.
|
||||
if err := s.Notify(ctx,
|
||||
gtsmodel.NotificationMention,
|
||||
mention.TargetAccount,
|
||||
mention.OriginAccount,
|
||||
mention.StatusID,
|
||||
); err != nil {
|
||||
errs.Appendf("error notifying mention target %s: %w", mention.TargetAccountID, err)
|
||||
continue
|
||||
// Do the thing.
|
||||
if err := s.notifyMention(ctx, mention); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
return errs.Combine()
|
||||
}
|
||||
|
||||
// notifyMention notifies the target
|
||||
// of the given mention that they've
|
||||
// been mentioned in a status.
|
||||
func (s *Surface) notifyMention(
|
||||
ctx context.Context,
|
||||
mention *gtsmodel.Mention,
|
||||
) error {
|
||||
// Beforehand, ensure the passed mention is fully populated.
|
||||
if err := s.State.DB.PopulateMention(ctx, mention); err != nil {
|
||||
return gtserror.Newf(
|
||||
"error populating mention %s: %w",
|
||||
mention.ID, err,
|
||||
)
|
||||
}
|
||||
|
||||
if mention.TargetAccount.IsRemote() {
|
||||
// no need to notify
|
||||
// remote accounts.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure thread not muted
|
||||
// by mentioned account.
|
||||
muted, err := s.State.DB.IsThreadMutedByAccount(
|
||||
ctx,
|
||||
mention.Status.ThreadID,
|
||||
mention.TargetAccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf(
|
||||
"error checking status thread mute %s: %w",
|
||||
mention.Status.ThreadID, err,
|
||||
)
|
||||
}
|
||||
|
||||
if muted {
|
||||
// This mentioned account
|
||||
// has muted the thread.
|
||||
// Don't pester them.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Notify mentioned
|
||||
// by status author.
|
||||
if err := s.Notify(ctx,
|
||||
gtsmodel.NotificationMention,
|
||||
mention.TargetAccount,
|
||||
mention.OriginAccount,
|
||||
mention.StatusID,
|
||||
); err != nil {
|
||||
return gtserror.Newf(
|
||||
"error notifying mention target %s: %w",
|
||||
mention.TargetAccountID, err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// notifyFollowRequest notifies the target of the given
|
||||
// follow request that they have a new follow request.
|
||||
func (s *Surface) notifyFollowRequest(
|
||||
|
Reference in New Issue
Block a user