mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-18 05:06:29 +00:00
[feature] Add support for the exclude_types[] parameter on the notifications endpoint (#784)
* Add support for the exclude_types[] parameter on the notifications endpoint * Add swagger docs to notifications
This commit is contained in:
parent
f01492ae48
commit
ecb97f4e0b
11 changed files with 172 additions and 12 deletions
|
@ -1401,6 +1401,36 @@ definitions:
|
|||
type: object
|
||||
x-go-name: Nodeinfo
|
||||
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
|
||||
notification:
|
||||
properties:
|
||||
account:
|
||||
$ref: '#/definitions/account'
|
||||
created_at:
|
||||
description: The timestamp of the notification (ISO 8601 Datetime)
|
||||
type: string
|
||||
x-go-name: CreatedAt
|
||||
id:
|
||||
description: The id of the notification in the database.
|
||||
type: string
|
||||
x-go-name: ID
|
||||
status:
|
||||
$ref: '#/definitions/status'
|
||||
type:
|
||||
description: |-
|
||||
The type of event that resulted in the notification.
|
||||
follow = Someone followed you
|
||||
follow_request = Someone requested to follow you
|
||||
mention = Someone mentioned you in their status
|
||||
reblog = Someone boosted one of your statuses
|
||||
favourite = Someone favourited one of your statuses
|
||||
poll = A poll you have voted in or created has ended
|
||||
status = Someone you enabled notifications for has posted a status
|
||||
type: string
|
||||
x-go-name: Type
|
||||
title: Notification represents a notification of an event relevant to the user.
|
||||
type: object
|
||||
x-go-name: Notification
|
||||
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
|
||||
oauthToken:
|
||||
properties:
|
||||
access_token:
|
||||
|
@ -3422,6 +3452,61 @@ paths:
|
|||
summary: Update a media attachment.
|
||||
tags:
|
||||
- media
|
||||
/api/v1/notifications:
|
||||
get:
|
||||
description: The notifications will be returned in descending chronological
|
||||
order (newest first), with sequential IDs (bigger = newer).
|
||||
operationId: notifications
|
||||
parameters:
|
||||
- default: 20
|
||||
description: Number of notifications to return.
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- description: Array of types of notifications to exclude (follow, favourite,
|
||||
reblog, mention, poll, follow_request)
|
||||
in: query
|
||||
items:
|
||||
type: string
|
||||
name: exclude_types
|
||||
type: array
|
||||
- description: |-
|
||||
Return only notifications *OLDER* than the given max status ID.
|
||||
The status with the specified ID will not be included in the response.
|
||||
in: query
|
||||
name: max_id
|
||||
type: string
|
||||
- description: |-
|
||||
Return only notifications *NEWER* than the given since status ID.
|
||||
The status with the specified ID will not be included in the response.
|
||||
in: query
|
||||
name: since_id
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Array of notifications.
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/notification'
|
||||
type: array
|
||||
"400":
|
||||
description: bad request
|
||||
"401":
|
||||
description: unauthorized
|
||||
"404":
|
||||
description: not found
|
||||
"406":
|
||||
description: not acceptable
|
||||
"500":
|
||||
description: internal server error
|
||||
security:
|
||||
- OAuth2 Bearer:
|
||||
- read:notifications
|
||||
summary: Get notifications for currently authorized user.
|
||||
tags:
|
||||
- notifications
|
||||
/api/v1/search:
|
||||
get:
|
||||
description: If statuses are in the result, they will be returned in descending
|
||||
|
@ -4341,6 +4426,7 @@ securityDefinitions:
|
|||
read:accounts: grants read access to accounts
|
||||
read:blocks: grant read access to blocks
|
||||
read:media: grant read access to media
|
||||
read:notifications: grants read access to notifications
|
||||
read:search: grant read access to searches
|
||||
read:statuses: grants read access to statuses
|
||||
read:streaming: grants read access to streaming api
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
// read:statuses: grants read access to statuses
|
||||
// read:streaming: grants read access to streaming api
|
||||
// read:user: grants read access to user-level info
|
||||
// read:notifications: grants read access to notifications
|
||||
// write: grants write access to everything
|
||||
// write:accounts: grants write access to accounts
|
||||
// write:blocks: grants write access to blocks
|
||||
|
|
|
@ -36,6 +36,8 @@ const (
|
|||
BasePathWithID = BasePath + "/:" + IDKey
|
||||
BasePathWithClear = BasePath + "/clear"
|
||||
|
||||
// ExcludeTypes is an array specifying notification types to exclude
|
||||
ExcludeTypesKey = "exclude_types[]"
|
||||
// MaxIDKey is the url query for setting a max notification ID to return
|
||||
MaxIDKey = "max_id"
|
||||
// LimitKey is for specifying maximum number of notifications to return.
|
||||
|
|
|
@ -29,7 +29,70 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
)
|
||||
|
||||
// NotificationsGETHandler serves a list of notifications to the caller, with the desired query parameters
|
||||
// NotificationsGETHandler swagger:operation GET /api/v1/notifications notifications
|
||||
//
|
||||
// Get notifications for currently authorized user.
|
||||
//
|
||||
// The notifications will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer).
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - notifications
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// - name: limit
|
||||
// type: integer
|
||||
// description: Number of notifications to return.
|
||||
// default: 20
|
||||
// in: query
|
||||
// required: false
|
||||
// - name: exclude_types
|
||||
// type: array
|
||||
// items:
|
||||
// type: string
|
||||
// description: Array of types of notifications to exclude (follow, favourite, reblog, mention, poll, follow_request)
|
||||
// in: query
|
||||
// required: false
|
||||
// - name: max_id
|
||||
// type: string
|
||||
// description: |-
|
||||
// Return only notifications *OLDER* than the given max status ID.
|
||||
// The status with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// required: false
|
||||
// - name: since_id
|
||||
// type: string
|
||||
// description: |-
|
||||
// Return only notifications *NEWER* than the given since status ID.
|
||||
// The status with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// required: false
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - read:notifications
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// name: notifications
|
||||
// description: Array of notifications.
|
||||
// schema:
|
||||
// type: array
|
||||
// items:
|
||||
// "$ref": "#/definitions/notification"
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '404':
|
||||
// description: not found
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) NotificationsGETHandler(c *gin.Context) {
|
||||
authed, err := oauth.Authed(c, true, true, true, true)
|
||||
if err != nil {
|
||||
|
@ -66,7 +129,9 @@ func (m *Module) NotificationsGETHandler(c *gin.Context) {
|
|||
sinceID = sinceIDString
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.NotificationsGet(c.Request.Context(), authed, limit, maxID, sinceID)
|
||||
excludeTypes := c.QueryArray(ExcludeTypesKey)
|
||||
|
||||
resp, errWithCode := m.processor.NotificationsGet(c.Request.Context(), authed, excludeTypes, limit, maxID, sinceID)
|
||||
if errWithCode != nil {
|
||||
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
|
||||
return
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package model
|
||||
|
||||
// Notification represents a notification of an event relevant to the user.
|
||||
//
|
||||
// swagger:model notification
|
||||
type Notification struct {
|
||||
// REQUIRED
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ func (n *notificationDB) GetNotification(ctx context.Context, id string) (*gtsmo
|
|||
return &dst, nil
|
||||
}
|
||||
|
||||
func (n *notificationDB) GetNotifications(ctx context.Context, accountID string, limit int, maxID string, sinceID string) ([]*gtsmodel.Notification, db.Error) {
|
||||
func (n *notificationDB) GetNotifications(ctx context.Context, accountID string, excludeTypes []string, limit int, maxID string, sinceID string) ([]*gtsmodel.Notification, db.Error) {
|
||||
// Ensure reasonable
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
|
@ -78,6 +78,10 @@ func (n *notificationDB) GetNotifications(ctx context.Context, accountID string,
|
|||
q = q.Where("id > ?", sinceID)
|
||||
}
|
||||
|
||||
for _, excludeType := range excludeTypes {
|
||||
q = q.Where("notification_type != ?", excludeType)
|
||||
}
|
||||
|
||||
q = q.
|
||||
Where("target_account_id = ?", accountID).
|
||||
Order("id DESC")
|
||||
|
|
|
@ -91,7 +91,7 @@ func (suite *NotificationTestSuite) TestGetNotificationsWithSpam() {
|
|||
suite.spamNotifs()
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
before := time.Now()
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, []string{}, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
suite.NoError(err)
|
||||
timeTaken := time.Since(before)
|
||||
fmt.Printf("\n\n\n withSpam: got %d notifications in %s\n\n\n", len(notifications), timeTaken)
|
||||
|
@ -105,7 +105,7 @@ func (suite *NotificationTestSuite) TestGetNotificationsWithSpam() {
|
|||
func (suite *NotificationTestSuite) TestGetNotificationsWithoutSpam() {
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
before := time.Now()
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, []string{}, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
suite.NoError(err)
|
||||
timeTaken := time.Since(before)
|
||||
fmt.Printf("\n\n\n withoutSpam: got %d notifications in %s\n\n\n", len(notifications), timeTaken)
|
||||
|
@ -125,7 +125,7 @@ func (suite *NotificationTestSuite) TestClearNotificationsWithSpam() {
|
|||
err := suite.db.ClearNotifications(context.Background(), testAccount.ID)
|
||||
suite.NoError(err)
|
||||
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, []string{}, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
suite.NoError(err)
|
||||
suite.NotNil(notifications)
|
||||
suite.Empty(notifications)
|
||||
|
@ -137,7 +137,7 @@ func (suite *NotificationTestSuite) TestClearNotificationsWithTwoAccounts() {
|
|||
err := suite.db.ClearNotifications(context.Background(), testAccount.ID)
|
||||
suite.NoError(err)
|
||||
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
notifications, err := suite.db.GetNotifications(context.Background(), testAccount.ID, []string{}, 20, "ZZZZZZZZZZZZZZZZZZZZZZZZZZ", "00000000000000000000000000")
|
||||
suite.NoError(err)
|
||||
suite.NotNil(notifications)
|
||||
suite.Empty(notifications)
|
||||
|
|
|
@ -29,7 +29,7 @@ type Notification interface {
|
|||
// GetNotifications returns a slice of notifications that pertain to the given accountID.
|
||||
//
|
||||
// Returned notifications will be ordered ID descending (ie., highest/newest to lowest/oldest).
|
||||
GetNotifications(ctx context.Context, accountID string, limit int, maxID string, sinceID string) ([]*gtsmodel.Notification, Error)
|
||||
GetNotifications(ctx context.Context, accountID string, excludeTypes []string, limit int, maxID string, sinceID string) ([]*gtsmodel.Notification, Error)
|
||||
// GetNotification returns one notification according to its id.
|
||||
GetNotification(ctx context.Context, id string) (*gtsmodel.Notification, Error)
|
||||
// ClearNotifications deletes every notification that pertain to the given accountID.
|
||||
|
|
|
@ -29,8 +29,8 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
func (p *processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, limit int, maxID string, sinceID string) (*apimodel.TimelineResponse, gtserror.WithCode) {
|
||||
notifs, err := p.db.GetNotifications(ctx, authed.Account.ID, limit, maxID, sinceID)
|
||||
func (p *processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, excludeTypes []string, limit int, maxID string, sinceID string) (*apimodel.TimelineResponse, gtserror.WithCode) {
|
||||
notifs, err := p.db.GetNotifications(ctx, authed.Account.ID, excludeTypes, limit, maxID, sinceID)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ type NotificationTestSuite struct {
|
|||
// get a notification where someone has liked our status
|
||||
func (suite *NotificationTestSuite) TestGetNotifications() {
|
||||
receivingAccount := suite.testAccounts["local_account_1"]
|
||||
notifsResponse, err := suite.processor.NotificationsGet(context.Background(), suite.testAutheds["local_account_1"], 10, "", "")
|
||||
notifsResponse, err := suite.processor.NotificationsGet(context.Background(), suite.testAutheds["local_account_1"], []string{}, 10, "", "")
|
||||
suite.NoError(err)
|
||||
suite.Len(notifsResponse.Items, 1)
|
||||
notif, ok := notifsResponse.Items[0].(*apimodel.Notification)
|
||||
|
|
|
@ -154,7 +154,7 @@ type Processor interface {
|
|||
MediaUpdate(ctx context.Context, authed *oauth.Auth, attachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode)
|
||||
|
||||
// NotificationsGet
|
||||
NotificationsGet(ctx context.Context, authed *oauth.Auth, limit int, maxID string, sinceID string) (*apimodel.TimelineResponse, gtserror.WithCode)
|
||||
NotificationsGet(ctx context.Context, authed *oauth.Auth, excludeTypes []string, limit int, maxID string, sinceID string) (*apimodel.TimelineResponse, gtserror.WithCode)
|
||||
// NotificationsClear
|
||||
NotificationsClear(ctx context.Context, authed *oauth.Auth) gtserror.WithCode
|
||||
|
||||
|
|
Loading…
Reference in a new issue