diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index b5ac8de..16c00ca 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -80,7 +80,7 @@ type Status struct { */ // Account that created this status - GTSAccount *Account `pg:"-"` + GTSAuthorAccount *Account `pg:"-"` // Mentions created in this status GTSMentions []*Mention `pg:"-"` // Hashtags used in this status diff --git a/internal/message/fromclientapiprocess.go b/internal/message/fromclientapiprocess.go index ef6beb1..12e4bd3 100644 --- a/internal/message/fromclientapiprocess.go +++ b/internal/message/fromclientapiprocess.go @@ -112,9 +112,9 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error { return fmt.Errorf("federateStatus: error converting status to as format: %s", err) } - outboxIRI, err := url.Parse(status.GTSAccount.OutboxURI) + outboxIRI, err := url.Parse(status.GTSAuthorAccount.OutboxURI) if err != nil { - return fmt.Errorf("federateStatus: error parsing outboxURI %s: %s", status.GTSAccount.OutboxURI, err) + return fmt.Errorf("federateStatus: error parsing outboxURI %s: %s", status.GTSAuthorAccount.OutboxURI, err) } _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asStatus) diff --git a/internal/message/fromcommonprocess.go b/internal/message/fromcommonprocess.go index cfc3fd2..73d58f1 100644 --- a/internal/message/fromcommonprocess.go +++ b/internal/message/fromcommonprocess.go @@ -26,6 +26,69 @@ import ( ) func (p *processor) notifyStatus(status *gtsmodel.Status) error { + // if there are no mentions in this status then just bail + if len(status.Mentions) == 0 { + return nil + } + + if status.GTSMentions == nil { + // there are mentions but they're not fully populated on the status yet so do this + menchies := []*gtsmodel.Mention{} + for _, m := range status.Mentions { + gtsm := >smodel.Mention{} + if err := p.db.GetByID(m, gtsm); err != nil { + return fmt.Errorf("notifyStatus: error getting mention with id %s from the db: %s", m, err) + } + menchies = append(menchies, gtsm) + } + status.GTSMentions = menchies + } + + // now we have mentions as full gtsmodel.Mention structs on the status we can continue + for _, m := range status.GTSMentions { + // make sure this is a local account, otherwise we don't need to create a notification for it + if m.GTSAccount == nil { + a := >smodel.Account{} + if err := p.db.GetByID(m.TargetAccountID, a); err != nil { + // we don't have the account or there's been an error + return fmt.Errorf("notifyStatus: error getting account with id %s from the db: %s", m.TargetAccountID, err) + } + m.GTSAccount = a + } + if m.GTSAccount.Domain != "" { + // not a local account so skip it + continue + } + + // make sure a notif doesn't already exist for this mention + err := p.db.GetWhere([]db.Where{ + {Key: "notification_type", Value: gtsmodel.NotificationMention}, + {Key: "target_account_id", Value: m.TargetAccountID}, + {Key: "origin_account_id", Value: status.AccountID}, + {Key: "status_id", Value: status.ID}, + }, >smodel.Notification{}) + if err == nil { + // notification exists already so just continue + continue + } + if _, ok := err.(db.ErrNoEntries); !ok { + // there's a real error in the db + return fmt.Errorf("notifyStatus: error checking existence of notification for mention with id %s : %s", m.ID, err) + } + + // if we've reached this point we know the mention is for a local account, and the notification doesn't exist, so create it + notif := >smodel.Notification{ + NotificationType: gtsmodel.NotificationMention, + TargetAccountID: m.TargetAccountID, + OriginAccountID: status.AccountID, + StatusID: status.ID, + } + + if err := p.db.Put(notif); err != nil { + return fmt.Errorf("notifyStatus: error putting notification in database: %s", err) + } + } + return nil } diff --git a/internal/message/fromfederatorprocess.go b/internal/message/fromfederatorprocess.go index 26b74a6..10dbfcf 100644 --- a/internal/message/fromfederatorprocess.go +++ b/internal/message/fromfederatorprocess.go @@ -249,8 +249,8 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error { } m.StatusID = status.ID - m.OriginAccountID = status.GTSAccount.ID - m.OriginAccountURI = status.GTSAccount.URI + m.OriginAccountID = status.GTSAuthorAccount.ID + m.OriginAccountURI = status.GTSAuthorAccount.URI targetAccount := >smodel.Account{} if err := p.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, targetAccount); err != nil { diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go index 0458292..0fee13b 100644 --- a/internal/typeutils/astointernal.go +++ b/internal/typeutils/astointernal.go @@ -226,7 +226,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e return nil, fmt.Errorf("couldn't get status owner from db: %s", err) } status.AccountID = statusOwner.ID - status.GTSAccount = statusOwner + status.GTSAuthorAccount = statusOwner // check if there's a post that this is a reply to inReplyToURI, err := extractInReplyToURI(statusable) diff --git a/internal/typeutils/converter.go b/internal/typeutils/converter.go index f2bf358..cf94faf 100644 --- a/internal/typeutils/converter.go +++ b/internal/typeutils/converter.go @@ -65,7 +65,7 @@ type TypeConverter interface { // TagToMasto converts a gts model tag into its mastodon (frontend) representation for serialization on the API. TagToMasto(t *gtsmodel.Tag) (model.Tag, error) // StatusToMasto converts a gts model status into its mastodon (frontend) representation for serialization on the API. - StatusToMasto(s *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, boostOfAccount *gtsmodel.Account, replyToAccount *gtsmodel.Account, reblogOfStatus *gtsmodel.Status) (*model.Status, error) + StatusToMasto(s *gtsmodel.Status, statusAuthor *gtsmodel.Account, requestingAccount *gtsmodel.Account, boostOfAccount *gtsmodel.Account, replyToAccount *gtsmodel.Account, reblogOfStatus *gtsmodel.Status) (*model.Status, error) // VisToMasto converts a gts visibility into its mastodon equivalent VisToMasto(m gtsmodel.Visibility) model.Visibility // InstanceToMasto converts a gts instance into its mastodon equivalent for serving at /api/v1/instance diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index 821720e..805f69a 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -262,12 +262,12 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e // check if author account is already attached to status and attach it if not // if we can't retrieve this, bail here already because we can't attribute the status to anyone - if s.GTSAccount == nil { + if s.GTSAuthorAccount == nil { a := >smodel.Account{} if err := c.db.GetByID(s.AccountID, a); err != nil { return nil, fmt.Errorf("StatusToAS: error retrieving author account from db: %s", err) } - s.GTSAccount = a + s.GTSAuthorAccount = a } // create the Note! @@ -328,9 +328,9 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e } // attributedTo - authorAccountURI, err := url.Parse(s.GTSAccount.URI) + authorAccountURI, err := url.Parse(s.GTSAuthorAccount.URI) if err != nil { - return nil, fmt.Errorf("StatusToAS: error parsing url %s: %s", s.GTSAccount.URI, err) + return nil, fmt.Errorf("StatusToAS: error parsing url %s: %s", s.GTSAuthorAccount.URI, err) } attributedToProp := streams.NewActivityStreamsAttributedToProperty() attributedToProp.AppendIRI(authorAccountURI) @@ -357,9 +357,9 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e status.SetActivityStreamsTag(tagProp) // parse out some URIs we need here - authorFollowersURI, err := url.Parse(s.GTSAccount.FollowersURI) + authorFollowersURI, err := url.Parse(s.GTSAuthorAccount.FollowersURI) if err != nil { - return nil, fmt.Errorf("StatusToAS: error parsing url %s: %s", s.GTSAccount.FollowersURI, err) + return nil, fmt.Errorf("StatusToAS: error parsing url %s: %s", s.GTSAuthorAccount.FollowersURI, err) } publicURI, err := url.Parse(asPublicURI) diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index 1861fba..de3b94e 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -270,7 +270,7 @@ func (c *converter) TagToMasto(t *gtsmodel.Tag) (model.Tag, error) { func (c *converter) StatusToMasto( s *gtsmodel.Status, - targetAccount *gtsmodel.Account, + statusAuthor *gtsmodel.Account, requestingAccount *gtsmodel.Account, boostOfAccount *gtsmodel.Account, replyToAccount *gtsmodel.Account, @@ -382,7 +382,7 @@ func (c *converter) StatusToMasto( } } - mastoTargetAccount, err := c.AccountToMastoPublic(targetAccount) + mastoAuthorAccount, err := c.AccountToMastoPublic(statusAuthor) if err != nil { return nil, fmt.Errorf("error parsing account of status author: %s", err) } @@ -520,7 +520,7 @@ func (c *converter) StatusToMasto( Content: s.Content, Reblog: mastoRebloggedStatus, Application: mastoApplication, - Account: mastoTargetAccount, + Account: mastoAuthorAccount, MediaAttachments: mastoAttachments, Mentions: mastoMentions, Tags: mastoTags, @@ -639,8 +639,16 @@ func (c *converter) NotificationToMasto(n *gtsmodel.Notification) (*model.Notifi replyToAccount = r } + if n.GTSStatus.GTSAuthorAccount == nil { + if n.GTSStatus.AccountID == n.GTSTargetAccount.ID { + n.GTSStatus.GTSAuthorAccount = n.GTSTargetAccount + } else if n.GTSStatus.AccountID == n.GTSOriginAccount.ID { + n.GTSStatus.GTSAuthorAccount = n.GTSOriginAccount + } + } + var err error - mastoStatus, err = c.StatusToMasto(n.GTSStatus, n.GTSTargetAccount, n.GTSTargetAccount, nil, replyToAccount, nil) + mastoStatus, err = c.StatusToMasto(n.GTSStatus, n.GTSStatus.GTSAuthorAccount, n.GTSTargetAccount, nil, replyToAccount, nil) if err != nil { return nil, fmt.Errorf("NotificationToMasto: error converting status to masto: %s", err) }