2022-10-13 13:50:52 +00:00
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// 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/util"
"github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/api"
2023-04-27 11:54:20 +00:00
rstypes "github.com/matrix-org/dendrite/roomserver/types"
2022-10-13 13:50:52 +00:00
"github.com/matrix-org/dendrite/syncapi/internal"
"github.com/matrix-org/dendrite/syncapi/storage"
2023-04-04 17:16:53 +00:00
"github.com/matrix-org/dendrite/syncapi/synctypes"
2022-10-13 13:50:52 +00:00
"github.com/matrix-org/dendrite/syncapi/types"
userapi "github.com/matrix-org/dendrite/userapi/api"
2023-05-09 22:46:49 +00:00
"github.com/matrix-org/gomatrixserverlib/spec"
2022-10-13 13:50:52 +00:00
)
type RelationsResponse struct {
2023-04-04 17:16:53 +00:00
Chunk [ ] synctypes . ClientEvent ` json:"chunk" `
NextBatch string ` json:"next_batch,omitempty" `
PrevBatch string ` json:"prev_batch,omitempty" `
2022-10-13 13:50:52 +00:00
}
// nolint:gocyclo
func Relations (
req * http . Request , device * userapi . Device ,
syncDB storage . Database ,
rsAPI api . SyncRoomserverAPI ,
2023-08-15 11:37:04 +00:00
rawRoomID , eventID , relType , eventType string ,
2022-10-13 13:50:52 +00:00
) util . JSONResponse {
2023-08-15 11:37:04 +00:00
roomID , err := spec . NewRoomID ( rawRoomID )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . InvalidParam ( "invalid room ID" ) ,
}
}
userID , err := spec . NewUserID ( device . UserID , true )
if err != nil {
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "device.UserID invalid" )
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . Unknown ( "internal server error" ) ,
}
}
2022-10-13 13:50:52 +00:00
var from , to types . StreamPosition
var limit int
dir := req . URL . Query ( ) . Get ( "dir" )
if f := req . URL . Query ( ) . Get ( "from" ) ; f != "" {
if from , err = types . NewStreamPositionFromString ( f ) ; err != nil {
return util . ErrorResponse ( err )
}
}
if t := req . URL . Query ( ) . Get ( "to" ) ; t != "" {
if to , err = types . NewStreamPositionFromString ( t ) ; err != nil {
return util . ErrorResponse ( err )
}
}
if l := req . URL . Query ( ) . Get ( "limit" ) ; l != "" {
if limit , err = strconv . Atoi ( l ) ; err != nil {
return util . ErrorResponse ( err )
}
}
if limit == 0 || limit > 50 {
limit = 50
}
if dir == "" {
dir = "b"
}
if dir != "b" && dir != "f" {
return util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . MissingParam ( "Bad or missing dir query parameter (should be either 'b' or 'f')" ) ,
2022-10-13 13:50:52 +00:00
}
}
snapshot , err := syncDB . NewDatabaseSnapshot ( req . Context ( ) )
if err != nil {
logrus . WithError ( err ) . Error ( "Failed to get snapshot for relations" )
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2022-10-13 13:50:52 +00:00
}
var succeeded bool
defer sqlutil . EndTransactionWithCheck ( snapshot , & succeeded , & err )
res := & RelationsResponse {
2023-04-04 17:16:53 +00:00
Chunk : [ ] synctypes . ClientEvent { } ,
2022-10-13 13:50:52 +00:00
}
var events [ ] types . StreamEvent
events , res . PrevBatch , res . NextBatch , err = snapshot . RelationsFor (
2023-08-15 11:37:04 +00:00
req . Context ( ) , roomID . String ( ) , eventID , relType , eventType , from , to , dir == "b" , limit ,
2022-10-13 13:50:52 +00:00
)
if err != nil {
return util . ErrorResponse ( err )
}
2023-04-27 11:54:20 +00:00
headeredEvents := make ( [ ] * rstypes . HeaderedEvent , 0 , len ( events ) )
2022-10-13 13:50:52 +00:00
for _ , event := range events {
headeredEvents = append ( headeredEvents , event . HeaderedEvent )
}
// Apply history visibility to the result events.
2023-08-15 11:37:04 +00:00
filteredEvents , err := internal . ApplyHistoryVisibilityFilter ( req . Context ( ) , snapshot , rsAPI , headeredEvents , nil , * userID , "relations" )
2023-06-14 14:23:46 +00:00
if err != nil {
return util . ErrorResponse ( err )
}
2022-10-13 13:50:52 +00:00
// Convert the events into client events, and optionally filter based on the event
// type if it was specified.
2023-04-04 17:16:53 +00:00
res . Chunk = make ( [ ] synctypes . ClientEvent , 0 , len ( filteredEvents ) )
2022-10-13 13:50:52 +00:00
for _ , event := range filteredEvents {
2023-09-15 15:25:09 +00:00
clientEvent , err := synctypes . ToClientEvent ( event . PDU , synctypes . FormatAll , func ( roomID spec . RoomID , senderID spec . SenderID ) ( * spec . UserID , error ) {
return rsAPI . QueryUserIDForSender ( req . Context ( ) , roomID , senderID )
} )
if err != nil {
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . WithField ( "senderID" , events [ 0 ] . SenderID ( ) ) . WithField ( "roomID" , * roomID ) . Error ( "Failed converting to ClientEvent" )
continue
2023-06-12 11:19:25 +00:00
}
2022-10-13 13:50:52 +00:00
res . Chunk = append (
res . Chunk ,
2023-09-15 15:25:09 +00:00
* clientEvent ,
2022-10-13 13:50:52 +00:00
)
}
succeeded = true
return util . JSONResponse {
Code : http . StatusOK ,
JSON : res ,
}
}