commit 8b1e2288d80a723a0c51770f0427fb6c7e07a366
parent fdd2487cfb584255b632cbee7f8d976cb4cc308a
Author: tobi <31960611+tsmethurst@users.noreply.github.com>
Date: Sat, 29 Apr 2023 18:29:51 +0200
[feature] Add GET endpoint for single notification (#1719)
Diffstat:
4 files changed, 145 insertions(+), 0 deletions(-)
diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml
@@ -4535,6 +4535,32 @@ paths:
summary: Update a media attachment.
tags:
- media
+ /api/v1/notification/{id}:
+ get:
+ operationId: notification
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: Requested notification.
+ schema:
+ $ref: '#/definitions/notification'
+ "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 a single notification with the given ID.
+ tags:
+ - notifications
/api/v1/notifications:
get:
description: |-
diff --git a/internal/api/client/notifications/notificationget.go b/internal/api/client/notifications/notificationget.go
@@ -0,0 +1,87 @@
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package notifications
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+// NotificationGETHandler swagger:operation GET /api/v1/notification/{id} notification
+//
+// Get a single notification with the given ID.
+//
+// ---
+// tags:
+// - notifications
+//
+// produces:
+// - application/json
+//
+// security:
+// - OAuth2 Bearer:
+// - read:notifications
+//
+// responses:
+// '200':
+// name: notifications
+// description: Requested notification.
+// schema:
+// "$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) NotificationGETHandler(c *gin.Context) {
+ authed, err := oauth.Authed(c, true, true, true, true)
+ if err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ targetNotifID := c.Param(IDKey)
+ if targetNotifID == "" {
+ err := errors.New("no notification id specified")
+ apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ resp, errWithCode := m.processor.NotificationGet(c.Request.Context(), authed.Account, targetNotifID)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ c.JSON(http.StatusOK, resp)
+}
diff --git a/internal/api/client/notifications/notifications.go b/internal/api/client/notifications/notifications.go
@@ -56,5 +56,6 @@ func New(processor *processing.Processor) *Module {
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.NotificationsGETHandler)
+ attachHandler(http.MethodGet, BasePathWithID, m.NotificationGETHandler)
attachHandler(http.MethodPost, BasePathWithClear, m.NotificationsClearPOSTHandler)
}
diff --git a/internal/processing/notification.go b/internal/processing/notification.go
@@ -20,10 +20,12 @@ package processing
import (
"context"
"errors"
+ "fmt"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/util"
@@ -72,6 +74,35 @@ func (p *Processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, ex
})
}
+func (p *Processor) NotificationGet(ctx context.Context, account *gtsmodel.Account, targetNotifID string) (*apimodel.Notification, gtserror.WithCode) {
+ notif, err := p.state.DB.GetNotificationByID(ctx, targetNotifID)
+ if err != nil {
+ if errors.Is(err, db.ErrNoEntries) {
+ return nil, gtserror.NewErrorNotFound(err)
+ }
+
+ // Real error.
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
+ if notifTargetAccountID := notif.TargetAccountID; notifTargetAccountID != account.ID {
+ err = fmt.Errorf("account %s does not have permission to view notification belong to account %s", account.ID, notifTargetAccountID)
+ return nil, gtserror.NewErrorNotFound(err)
+ }
+
+ apiNotif, err := p.tc.NotificationToAPINotification(ctx, notif)
+ if err != nil {
+ if errors.Is(err, db.ErrNoEntries) {
+ return nil, gtserror.NewErrorNotFound(err)
+ }
+
+ // Real error.
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
+ return apiNotif, nil
+}
+
func (p *Processor) NotificationsClear(ctx context.Context, authed *oauth.Auth) gtserror.WithCode {
// Delete all notifications of all types that target the authorized account.
if err := p.state.DB.DeleteNotifications(ctx, nil, authed.Account.ID, ""); err != nil && !errors.Is(err, db.ErrNoEntries) {