[feature] Receive notification when followed account posts (if desired) (#1680)

* start working on notifs for new posts

* tidy up a bit

* update swagger

* carry over show reblogs + notify from follow req

* test notify on status post

* update column slice

* dedupe update logic + add tests

* fix own boosts not being timelined

* avoid type check, passing unnecessary accounts

* remove unnecessary 'inReplyToID' check

* add a couple todo's for future db functions
This commit is contained in:
tobi 2023-04-10 21:56:02 +02:00 committed by GitHub
commit 093cf2ab12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 788 additions and 448 deletions

View file

@ -48,6 +48,31 @@ func (n *notificationDB) GetNotificationByID(ctx context.Context, id string) (*g
}, id)
}
func (n *notificationDB) GetNotification(
ctx context.Context,
notificationType gtsmodel.NotificationType,
targetAccountID string,
originAccountID string,
statusID string,
) (*gtsmodel.Notification, db.Error) {
return n.state.Caches.GTS.Notification().Load("NotificationType.TargetAccountID.OriginAccountID.StatusID", func() (*gtsmodel.Notification, error) {
var notif gtsmodel.Notification
q := n.conn.NewSelect().
Model(&notif).
Where("? = ?", bun.Ident("notification_type"), notificationType).
Where("? = ?", bun.Ident("target_account_id"), targetAccountID).
Where("? = ?", bun.Ident("origin_account_id"), originAccountID).
Where("? = ?", bun.Ident("status_id"), statusID)
if err := q.Scan(ctx); err != nil {
return nil, n.conn.ProcessError(err)
}
return &notif, nil
}, notificationType, targetAccountID, originAccountID, statusID)
}
func (n *notificationDB) GetAccountNotifications(ctx context.Context, accountID string, excludeTypes []string, limit int, maxID string, sinceID string) ([]*gtsmodel.Notification, db.Error) {
// Ensure reasonable
if limit < 0 {

View file

@ -21,6 +21,7 @@ import (
"context"
"errors"
"fmt"
"time"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
@ -189,6 +190,26 @@ func (r *relationshipDB) PutFollow(ctx context.Context, follow *gtsmodel.Follow)
return nil
}
func (r *relationshipDB) UpdateFollow(ctx context.Context, follow *gtsmodel.Follow, columns ...string) error {
follow.UpdatedAt = time.Now()
if len(columns) > 0 {
// If we're updating by column, ensure "updated_at" is included.
columns = append(columns, "updated_at")
}
return r.state.Caches.GTS.Follow().Store(follow, func() error {
if _, err := r.conn.NewUpdate().
Model(follow).
Where("? = ?", bun.Ident("follow.id"), follow.ID).
Column(columns...).
Exec(ctx); err != nil {
return r.conn.ProcessError(err)
}
return nil
})
}
func (r *relationshipDB) DeleteFollowByID(ctx context.Context, id string) error {
if _, err := r.conn.NewDelete().
Table("follows").

View file

@ -21,6 +21,7 @@ import (
"context"
"errors"
"fmt"
"time"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
@ -167,6 +168,26 @@ func (r *relationshipDB) PutFollowRequest(ctx context.Context, follow *gtsmodel.
return nil
}
func (r *relationshipDB) UpdateFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest, columns ...string) error {
followRequest.UpdatedAt = time.Now()
if len(columns) > 0 {
// If we're updating by column, ensure "updated_at" is included.
columns = append(columns, "updated_at")
}
return r.state.Caches.GTS.FollowRequest().Store(followRequest, func() error {
if _, err := r.conn.NewUpdate().
Model(followRequest).
Where("? = ?", bun.Ident("follow_request.id"), followRequest.ID).
Column(columns...).
Exec(ctx); err != nil {
return r.conn.ProcessError(err)
}
return nil
})
}
func (r *relationshipDB) AcceptFollowRequest(ctx context.Context, sourceAccountID string, targetAccountID string) (*gtsmodel.Follow, db.Error) {
// Get original follow request.
followReq, err := r.GetFollowRequest(ctx, sourceAccountID, targetAccountID)
@ -183,6 +204,8 @@ func (r *relationshipDB) AcceptFollowRequest(ctx context.Context, sourceAccountI
TargetAccountID: targetAccountID,
TargetAccount: followReq.TargetAccount,
URI: followReq.URI,
ShowReblogs: followReq.ShowReblogs,
Notify: followReq.Notify,
}
// If the follow already exists, just

View file

@ -28,6 +28,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/id"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type RelationshipTestSuite struct {
@ -861,6 +862,32 @@ func (suite *RelationshipTestSuite) TestUnfollowRequestNotExisting() {
suite.Nil(followRequest)
}
func (suite *RelationshipTestSuite) TestUpdateFollow() {
ctx := context.Background()
follow := &gtsmodel.Follow{}
*follow = *suite.testFollows["local_account_1_admin_account"]
follow.Notify = testrig.TrueBool()
if err := suite.db.UpdateFollow(ctx, follow, "notify"); err != nil {
suite.FailNow(err.Error())
}
dbFollow, err := suite.db.GetFollowByID(ctx, follow.ID)
if err != nil {
suite.FailNow(err.Error())
}
suite.True(*dbFollow.Notify)
relationship, err := suite.db.GetRelationship(ctx, follow.AccountID, follow.TargetAccountID)
if err != nil {
suite.FailNow(err.Error())
}
suite.True(relationship.Notifying)
}
func TestRelationshipTestSuite(t *testing.T) {
suite.Run(t, new(RelationshipTestSuite))
}

View file

@ -33,6 +33,10 @@ type Notification interface {
// GetNotification returns one notification according to its id.
GetNotificationByID(ctx context.Context, id string) (*gtsmodel.Notification, Error)
// GetNotification gets one notification according to the provided parameters, if it exists.
// Since not all notifications are about a status, statusID can be an empty string.
GetNotification(ctx context.Context, notificationType gtsmodel.NotificationType, targetAccountID string, originAccountID string, statusID string) (*gtsmodel.Notification, Error)
// PutNotification will insert the given notification into the database.
PutNotification(ctx context.Context, notif *gtsmodel.Notification) error

View file

@ -85,9 +85,15 @@ type Relationship interface {
// PutFollow attempts to place the given account follow in the database.
PutFollow(ctx context.Context, follow *gtsmodel.Follow) error
// UpdateFollow updates one follow by ID.
UpdateFollow(ctx context.Context, follow *gtsmodel.Follow, columns ...string) error
// PutFollowRequest attempts to place the given account follow request in the database.
PutFollowRequest(ctx context.Context, follow *gtsmodel.FollowRequest) error
// UpdateFollowRequest updates one follow request by ID.
UpdateFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest, columns ...string) error
// DeleteFollowByID deletes a follow from the database with the given ID.
DeleteFollowByID(ctx context.Context, id string) error