Add clientapi route for /unstable/notifications.

This commit is contained in:
Tommie Gannert 2021-10-27 17:55:46 +02:00
parent 74b74bf6d6
commit bbf4b7066d
6 changed files with 138 additions and 0 deletions

View file

@ -0,0 +1,64 @@
// Copyright 2021 Dan Peleg <dan@globekeeper.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routing
import (
"net/http"
"strconv"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
pushserverapi "github.com/matrix-org/dendrite/pushserver/api"
userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
)
// GetNotifications handles /_matrix/client/r0/notifications
func GetNotifications(
req *http.Request, device *userapi.Device,
psAPI pushserverapi.PushserverInternalAPI,
) util.JSONResponse {
var limit int64
if limitStr := req.URL.Query().Get("limit"); limitStr != "" {
var err error
limit, err = strconv.ParseInt(limitStr, 10, 64)
if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("ParseInt(limit) failed")
return jsonerror.InternalServerError()
}
}
var queryRes pushserverapi.QueryNotificationsResponse
localpart, _, err := gomatrixserverlib.SplitID('@', device.UserID)
if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("SplitID failed")
return jsonerror.InternalServerError()
}
err = psAPI.QueryNotifications(req.Context(), &pushserverapi.QueryNotificationsRequest{
Localpart: localpart,
From: req.URL.Query().Get("from"),
Limit: int(limit),
Only: req.URL.Query().Get("only"),
}, &queryRes)
if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("QueryNotifications failed")
return jsonerror.InternalServerError()
}
util.GetLogger(req.Context()).WithField("from", req.URL.Query().Get("from")).WithField("limit", limit).WithField("only", req.URL.Query().Get("only")).WithField("next", queryRes.NextToken).Infof("QueryNotifications: len %d", len(queryRes.Notifications))
return util.JSONResponse{
Code: http.StatusOK,
JSON: queryRes,
}
}

View file

@ -951,6 +951,12 @@ func Setup(
}),
).Methods(http.MethodPost, http.MethodOptions)
unstableMux.Handle("/notifications",
httputil.MakeAuthAPI("get_notifications", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return GetNotifications(req, device, psAPI)
}),
).Methods(http.MethodGet, http.MethodOptions)
r0mux.Handle("/pushers",
httputil.MakeAuthAPI("get_pushers", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return GetPushers(req, device, psAPI)

View file

@ -14,6 +14,8 @@ type PushserverInternalAPI interface {
PerformPushRulesPut(ctx context.Context, req *PerformPushRulesPutRequest, res *struct{}) error
QueryPushRules(ctx context.Context, req *QueryPushRulesRequest, res *QueryPushRulesResponse) error
QueryNotifications(ctx context.Context, req *QueryNotificationsRequest, res *QueryNotificationsResponse) error
}
type QueryPushersRequest struct {
@ -69,6 +71,18 @@ type QueryPushRulesResponse struct {
RuleSets *pushrules.AccountRuleSets `json:"rule_sets"`
}
type QueryNotificationsRequest struct {
Localpart string `json:"localpart"` // Required.
From string `json:"from,omitempty"`
Limit int `json:"limit,omitempty"`
Only string `json:"only,omitempty"`
}
type QueryNotificationsResponse struct {
NextToken string `json:"next_token"`
Notifications []*Notification `json:"notifications"` // Required.
}
type Notification struct {
Actions []*pushrules.Action `json:"actions"` // Required.
Event gomatrixserverlib.ClientEvent `json:"event"` // Required.

View file

@ -4,12 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
"github.com/matrix-org/dendrite/internal/pushrules"
"github.com/matrix-org/dendrite/pushserver/api"
"github.com/matrix-org/dendrite/pushserver/producers"
"github.com/matrix-org/dendrite/pushserver/storage"
"github.com/matrix-org/dendrite/pushserver/storage/tables"
"github.com/matrix-org/dendrite/setup/config"
uapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
@ -37,6 +39,38 @@ func NewPushserverAPI(
return a
}
func (a *PushserverInternalAPI) QueryNotifications(ctx context.Context, req *api.QueryNotificationsRequest, res *api.QueryNotificationsResponse) error {
if req.Limit == 0 || req.Limit > 1000 {
req.Limit = 1000
}
var fromID int64
var err error
if req.From != "" {
fromID, err = strconv.ParseInt(req.From, 10, 64)
if err != nil {
return fmt.Errorf("QueryNotifications: parsing 'from': %w", err)
}
}
var filter storage.NotificationFilter = tables.AllNotifications
if req.Only == "highlight" {
filter = tables.HighlightNotifications
}
notifs, lastID, err := a.DB.GetNotifications(ctx, req.Localpart, fromID, req.Limit, filter)
if err != nil {
return err
}
if notifs == nil {
// This ensures empty is JSON-encoded as [] instead of null.
notifs = []*api.Notification{}
}
res.Notifications = notifs
if lastID >= 0 {
res.NextToken = strconv.FormatInt(lastID+1, 10)
}
return nil
}
func (a *PushserverInternalAPI) PerformPusherSet(ctx context.Context, req *api.PerformPusherSetRequest, res *struct{}) error {
util.GetLogger(ctx).WithFields(logrus.Fields{
"localpart": req.Localpart,

View file

@ -41,6 +41,13 @@ func NewPushserverClient(
}, nil
}
func (h *httpPushserverInternalAPI) QueryNotifications(ctx context.Context, req *api.QueryNotificationsRequest, res *api.QueryNotificationsResponse) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryNotifications")
defer span.Finish()
return httputil.PostJSON(ctx, span, h.httpClient, h.pushserverURL+QueryNotificationsPath, req, res)
}
func (h *httpPushserverInternalAPI) PerformPusherSet(
ctx context.Context,
request *api.PerformPusherSetRequest,

View file

@ -13,6 +13,19 @@ import (
// AddRoutes adds the PushserverInternalAPI handlers to the http.ServeMux.
// nolint: gocyclo
func AddRoutes(r api.PushserverInternalAPI, internalAPIMux *mux.Router) {
internalAPIMux.Handle(QueryNotificationsPath,
httputil.MakeInternalAPI("queryNotifications", func(req *http.Request) util.JSONResponse {
var request api.QueryNotificationsRequest
var response api.QueryNotificationsResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.MessageResponse(http.StatusBadRequest, err.Error())
}
if err := r.QueryNotifications(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
internalAPIMux.Handle(PerformPusherSetPath,
httputil.MakeInternalAPI("performPusherSet", func(req *http.Request) util.JSONResponse {