summaryrefslogtreecommitdiff
path: root/internal/message
diff options
context:
space:
mode:
Diffstat (limited to 'internal/message')
-rw-r--r--internal/message/fromclientapiprocess.go25
-rw-r--r--internal/message/fromcommonprocess.go135
-rw-r--r--internal/message/fromfederatorprocess.go38
-rw-r--r--internal/message/notificationsprocess.go24
-rw-r--r--internal/message/processor.go3
-rw-r--r--internal/message/statusprocess.go52
6 files changed, 216 insertions, 61 deletions
diff --git a/internal/message/fromclientapiprocess.go b/internal/message/fromclientapiprocess.go
index b0112152b..12e4bd3c0 100644
--- a/internal/message/fromclientapiprocess.go
+++ b/internal/message/fromclientapiprocess.go
@@ -49,17 +49,17 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
}
return nil
case gtsmodel.ActivityStreamsFollow:
- // CREATE FOLLOW (request)
- follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)
+ // CREATE FOLLOW REQUEST
+ followRequest, ok := clientMsg.GTSModel.(*gtsmodel.FollowRequest)
if !ok {
- return errors.New("follow was not parseable as *gtsmodel.Follow")
+ return errors.New("followrequest was not parseable as *gtsmodel.FollowRequest")
}
- if err := p.notifyFollow(follow); err != nil {
+ if err := p.notifyFollowRequest(followRequest, clientMsg.TargetAccount); err != nil {
return err
}
- return p.federateFollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount)
+ return p.federateFollow(followRequest, clientMsg.OriginAccount, clientMsg.TargetAccount)
case gtsmodel.ActivityStreamsLike:
// CREATE LIKE/FAVE
fave, ok := clientMsg.GTSModel.(*gtsmodel.StatusFave)
@@ -67,7 +67,7 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
return errors.New("fave was not parseable as *gtsmodel.StatusFave")
}
- if err := p.notifyFave(fave); err != nil {
+ if err := p.notifyFave(fave, clientMsg.TargetAccount); err != nil {
return err
}
@@ -84,6 +84,11 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
if !ok {
return errors.New("accept was not parseable as *gtsmodel.Follow")
}
+
+ if err := p.notifyFollow(follow, clientMsg.TargetAccount); err != nil {
+ return err
+ }
+
return p.federateAcceptFollowRequest(follow, clientMsg.OriginAccount, clientMsg.TargetAccount)
}
case gtsmodel.ActivityStreamsUndo:
@@ -107,21 +112,23 @@ 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)
return err
}
-func (p *processor) federateFollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
+func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
// if both accounts are local there's nothing to do here
if originAccount.Domain == "" && targetAccount.Domain == "" {
return nil
}
+ follow := p.tc.FollowRequestToFollow(followRequest)
+
asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount)
if err != nil {
return fmt.Errorf("federateFollow: error converting follow to as format: %s", err)
diff --git a/internal/message/fromcommonprocess.go b/internal/message/fromcommonprocess.go
index 2403a8b72..73d58f1d1 100644
--- a/internal/message/fromcommonprocess.go
+++ b/internal/message/fromcommonprocess.go
@@ -18,16 +18,143 @@
package message
-import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+import (
+ "fmt"
+
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+)
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 := &gtsmodel.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 := &gtsmodel.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},
+ }, &gtsmodel.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 := &gtsmodel.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
+}
+
+func (p *processor) notifyFollowRequest(followRequest *gtsmodel.FollowRequest, receivingAccount *gtsmodel.Account) error {
+ // return if this isn't a local account
+ if receivingAccount.Domain != "" {
+ return nil
+ }
+
+ notif := &gtsmodel.Notification{
+ NotificationType: gtsmodel.NotificationFollowRequest,
+ TargetAccountID: followRequest.TargetAccountID,
+ OriginAccountID: followRequest.AccountID,
+ }
+
+ if err := p.db.Put(notif); err != nil {
+ return fmt.Errorf("notifyFollowRequest: error putting notification in database: %s", err)
+ }
+
return nil
}
-func (p *processor) notifyFollow(follow *gtsmodel.Follow) error {
+func (p *processor) notifyFollow(follow *gtsmodel.Follow, receivingAccount *gtsmodel.Account) error {
+ // return if this isn't a local account
+ if receivingAccount.Domain != "" {
+ return nil
+ }
+
+ // first remove the follow request notification
+ if err := p.db.DeleteWhere([]db.Where{
+ {Key: "notification_type", Value: gtsmodel.NotificationFollowRequest},
+ {Key: "target_account_id", Value: follow.TargetAccountID},
+ {Key: "origin_account_id", Value: follow.AccountID},
+ }, &gtsmodel.Notification{}); err != nil {
+ return fmt.Errorf("notifyFollow: error removing old follow request notification from database: %s", err)
+ }
+
+ // now create the new follow notification
+ notif := &gtsmodel.Notification{
+ NotificationType: gtsmodel.NotificationFollow,
+ TargetAccountID: follow.TargetAccountID,
+ OriginAccountID: follow.AccountID,
+ }
+ if err := p.db.Put(notif); err != nil {
+ return fmt.Errorf("notifyFollow: error putting notification in database: %s", err)
+ }
+
return nil
}
-func (p *processor) notifyFave(fave *gtsmodel.StatusFave) error {
- return nil
+func (p *processor) notifyFave(fave *gtsmodel.StatusFave, receivingAccount *gtsmodel.Account) error {
+ // return if this isn't a local account
+ if receivingAccount.Domain != "" {
+ return nil
+ }
+
+ notif := &gtsmodel.Notification{
+ NotificationType: gtsmodel.NotificationFave,
+ TargetAccountID: fave.TargetAccountID,
+ OriginAccountID: fave.AccountID,
+ StatusID: fave.StatusID,
+ }
+
+ if err := p.db.Put(notif); err != nil {
+ return fmt.Errorf("notifyFave: error putting notification in database: %s", err)
+ }
+
+ return nil
}
diff --git a/internal/message/fromfederatorprocess.go b/internal/message/fromfederatorprocess.go
index d3ebce400..10dbfcf6e 100644
--- a/internal/message/fromfederatorprocess.go
+++ b/internal/message/fromfederatorprocess.go
@@ -74,6 +74,26 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
if err := p.db.UpdateByID(incomingAccount.ID, incomingAccount); err != nil {
return fmt.Errorf("error updating dereferenced account in the db: %s", err)
}
+ case gtsmodel.ActivityStreamsLike:
+ // CREATE A FAVE
+ incomingFave, ok := federatorMsg.GTSModel.(*gtsmodel.StatusFave)
+ if !ok {
+ return errors.New("like was not parseable as *gtsmodel.StatusFave")
+ }
+
+ if err := p.notifyFave(incomingFave, federatorMsg.ReceivingAccount); err != nil {
+ return err
+ }
+ case gtsmodel.ActivityStreamsFollow:
+ // CREATE A FOLLOW REQUEST
+ incomingFollowRequest, ok := federatorMsg.GTSModel.(*gtsmodel.FollowRequest)
+ if !ok {
+ return errors.New("like was not parseable as *gtsmodel.FollowRequest")
+ }
+
+ if err := p.notifyFollowRequest(incomingFollowRequest, federatorMsg.ReceivingAccount); err != nil {
+ return err
+ }
}
case gtsmodel.ActivityStreamsUpdate:
// UPDATE
@@ -106,6 +126,20 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
// DELETE A PROFILE/ACCOUNT
// TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account
}
+ case gtsmodel.ActivityStreamsAccept:
+ // ACCEPT
+ switch federatorMsg.APObjectType {
+ case gtsmodel.ActivityStreamsFollow:
+ // ACCEPT A FOLLOW
+ follow, ok := federatorMsg.GTSModel.(*gtsmodel.Follow)
+ if !ok {
+ return errors.New("follow was not parseable as *gtsmodel.Follow")
+ }
+
+ if err := p.notifyFollow(follow, federatorMsg.ReceivingAccount); err != nil {
+ return err
+ }
+ }
}
return nil
@@ -215,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 := &gtsmodel.Account{}
if err := p.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, targetAccount); err != nil {
diff --git a/internal/message/notificationsprocess.go b/internal/message/notificationsprocess.go
new file mode 100644
index 000000000..64726b75f
--- /dev/null
+++ b/internal/message/notificationsprocess.go
@@ -0,0 +1,24 @@
+package message
+
+import (
+ apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+func (p *processor) NotificationsGet(authed *oauth.Auth, limit int, maxID string) ([]*apimodel.Notification, ErrorWithCode) {
+ notifs, err := p.db.GetNotificationsForAccount(authed.Account.ID, limit, maxID)
+ if err != nil {
+ return nil, NewErrorInternalError(err)
+ }
+
+ mastoNotifs := []*apimodel.Notification{}
+ for _, n := range notifs {
+ mastoNotif, err := p.tc.NotificationToMasto(n)
+ if err != nil {
+ return nil, NewErrorInternalError(err)
+ }
+ mastoNotifs = append(mastoNotifs, mastoNotif)
+ }
+
+ return mastoNotifs, nil
+}
diff --git a/internal/message/processor.go b/internal/message/processor.go
index bcd64d47a..49a4f6f05 100644
--- a/internal/message/processor.go
+++ b/internal/message/processor.go
@@ -106,6 +106,9 @@ type Processor interface {
// MediaUpdate handles the PUT of a media attachment with the given ID and form
MediaUpdate(authed *oauth.Auth, attachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, ErrorWithCode)
+ // NotificationsGet
+ NotificationsGet(authed *oauth.Auth, limit int, maxID string) ([]*apimodel.Notification, ErrorWithCode)
+
// StatusCreate processes the given form to create a new status, returning the api model representation of that status if it's OK.
StatusCreate(authed *oauth.Auth, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, error)
// StatusDelete processes the delete of a given status, returning the deleted status if the delete goes through.
diff --git a/internal/message/statusprocess.go b/internal/message/statusprocess.go
index 6786b2dab..f64c35948 100644
--- a/internal/message/statusprocess.go
+++ b/internal/message/statusprocess.go
@@ -278,54 +278,14 @@ func (p *processor) StatusBoost(authed *oauth.Auth, targetStatusID string) (*api
}
// it's visible! it's boostable! so let's boost the FUCK out of it
- // first we create a new status and add some basic info to it -- this will be the wrapper for the boosted status
-
- // the wrapper won't use the same ID as the boosted status so we generate some new UUIDs
- uris := util.GenerateURIsForAccount(authed.Account.Username, p.config.Protocol, p.config.Host)
- boostWrapperStatusID := uuid.NewString()
- boostWrapperStatusURI := fmt.Sprintf("%s/%s", uris.StatusesURI, boostWrapperStatusID)
- boostWrapperStatusURL := fmt.Sprintf("%s/%s", uris.StatusesURL, boostWrapperStatusID)
-
- boostWrapperStatus := &gtsmodel.Status{
- ID: boostWrapperStatusID,
- URI: boostWrapperStatusURI,
- URL: boostWrapperStatusURL,
-
- // the boosted status is not created now, but the boost certainly is
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- Local: true, // always local since this is being done through the client API
- AccountID: authed.Account.ID,
- CreatedWithApplicationID: authed.Application.ID,
-
- // replies can be boosted, but boosts are never replies
- InReplyToID: "",
- InReplyToAccountID: "",
-
- // these will all be wrapped in the boosted status so set them empty here
- Attachments: []string{},
- Tags: []string{},
- Mentions: []string{},
- Emojis: []string{},
-
- // the below fields will be taken from the target status
- Content: util.HTMLFormat(targetStatus.Content),
- ContentWarning: targetStatus.ContentWarning,
- ActivityStreamsType: targetStatus.ActivityStreamsType,
- Sensitive: targetStatus.Sensitive,
- Language: targetStatus.Language,
- Text: targetStatus.Text,
- BoostOfID: targetStatus.ID,
- Visibility: targetStatus.Visibility,
- VisibilityAdvanced: targetStatus.VisibilityAdvanced,
-
- // attach these here for convenience -- the boosted status/account won't go in the DB
- // but they're needed in the processor and for the frontend. Since we have them, we can
- // attach them so we don't need to fetch them again later (save some DB calls)
- GTSBoostedStatus: targetStatus,
- GTSBoostedAccount: targetAccount,
+ boostWrapperStatus, err := p.tc.StatusToBoost(targetStatus, authed.Account)
+ if err != nil {
+ return nil, NewErrorInternalError(err)
}
+ boostWrapperStatus.CreatedWithApplicationID = authed.Application.ID
+ boostWrapperStatus.GTSBoostedAccount = targetAccount
+
// put the boost in the database
if err := p.db.Put(boostWrapperStatus); err != nil {
return nil, NewErrorInternalError(err)