Implement the API on the roomserver and client API server

This commit is contained in:
Brendan Abolivier 2017-08-18 17:50:41 +01:00
parent 86c2174faf
commit 9b3ecd5cdd
No known key found for this signature in database
GPG key ID: 8EF1500759F70623
4 changed files with 102 additions and 53 deletions

View file

@ -23,7 +23,6 @@ import (
"github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
)
@ -33,59 +32,24 @@ func GetMemberships(
accountDB *accounts.Database, cfg config.Dendrite,
queryAPI api.RoomserverQueryAPI,
) util.JSONResponse {
localpart, _, err := gomatrixserverlib.SplitID('@', device.UserID)
if err != nil {
return httputil.LogThenError(req, err)
queryReq := api.QueryMembershipsForRoomRequest{
RoomID: roomID,
Sender: device.UserID,
}
_, server, err := gomatrixserverlib.SplitID('!', roomID)
if err != nil {
var queryRes api.QueryMembershipsForRoomResponse
if err := queryAPI.QueryMembershipsForRoom(&queryReq, &queryRes); err != nil {
return httputil.LogThenError(req, err)
}
events := []gomatrixserverlib.ClientEvent{}
if server == cfg.Matrix.ServerName {
// TODO: If the user has been in the room before but isn't
// anymore, only send the members list as it was before they left.
membership, err := accountDB.GetMembership(localpart, roomID)
if err != nil {
return httputil.LogThenError(req, err)
if !queryRes.HasBeenInRoom {
return util.JSONResponse{
Code: 403,
JSON: jsonerror.Forbidden("You aren't a member of the room and weren't previously a member of the room."),
}
if membership == nil {
return util.JSONResponse{
Code: 403,
JSON: jsonerror.Forbidden("You aren't a member of the room and weren't previously a member of the room."),
}
}
memberships, err := accountDB.GetMembershipsByRoomID(roomID)
if err != nil {
return httputil.LogThenError(req, err)
}
eventIDs := []string{}
for _, membership := range memberships {
eventIDs = append(eventIDs, membership.EventID)
}
queryReq := api.QueryEventsByIDRequest{
EventIDs: eventIDs,
}
var queryRes api.QueryEventsByIDResponse
if err := queryAPI.QueryEventsByID(&queryReq, &queryRes); err != nil {
return httputil.LogThenError(req, err)
}
for _, event := range queryRes.Events {
ev := gomatrixserverlib.ToClientEvent(event, gomatrixserverlib.FormatAll)
events = append(events, ev)
}
} else {
// TODO: Get memberships from federation
}
return util.JSONResponse{
Code: 200,
JSON: events,
JSON: queryRes.JoinEvents,
}
}

View file

@ -100,6 +100,23 @@ type QueryEventsByIDResponse struct {
Events []gomatrixserverlib.Event `json:"events"`
}
// QueryMembershipsForRoomRequest is a request to QueryMembershipsForRoom
type QueryMembershipsForRoomRequest struct {
// ID of the room to fetch memberships from
RoomID string `json:"room_id"`
// ID of the user sending the request
Sender string `json:"sender"`
}
// QueryMembershipsForRoomResponse is a response to QueryMembershipsForRoom
type QueryMembershipsForRoomResponse struct {
// The "m.room.member" events (of "join" membership) in the client format
JoinEvents []gomatrixserverlib.ClientEvent `json:"join_events"`
// True if the user has been in room before and has either stayed in it or
// left it.
HasBeenInRoom bool `json:"has_been_in_room"`
}
// RoomserverQueryAPI is used to query information from the room server.
type RoomserverQueryAPI interface {
// Query the latest events and state for a room from the room server.
@ -119,6 +136,12 @@ type RoomserverQueryAPI interface {
request *QueryEventsByIDRequest,
response *QueryEventsByIDResponse,
) error
// Query a list of membership events for a room
QueryMembershipsForRoom(
request *QueryMembershipsForRoomRequest,
response *QueryMembershipsForRoomResponse,
) error
}
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
@ -130,6 +153,9 @@ const RoomserverQueryStateAfterEventsPath = "/api/roomserver/queryStateAfterEven
// RoomserverQueryEventsByIDPath is the HTTP path for the QueryEventsByID API.
const RoomserverQueryEventsByIDPath = "/api/roomserver/queryEventsByID"
// RoomserverQueryMembershipsForRoomPath is the HTTP path for the QueryMembershipsForRoom API
const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsForRoom"
// NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API.
// If httpClient is nil then it uses the http.DefaultClient
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
@ -171,6 +197,15 @@ func (h *httpRoomserverQueryAPI) QueryEventsByID(
return postJSON(h.httpClient, apiURL, request, response)
}
// QueryMembershipsForRoom implements RoomserverQueryAPI
func (h *httpRoomserverQueryAPI) QueryMembershipsForRoom(
request *QueryMembershipsForRoomRequest,
response *QueryMembershipsForRoomResponse,
) error {
apiURL := h.roomserverURL + RoomserverQueryMembershipsForRoomPath
return postJSON(h.httpClient, apiURL, request, response)
}
func postJSON(httpClient *http.Client, apiURL string, request, response interface{}) error {
jsonBytes, err := json.Marshal(request)
if err != nil {

View file

@ -52,6 +52,13 @@ type RoomserverQueryAPIDatabase interface {
// Remove a given room alias.
// Returns an error if there was a problem talking to the database.
RemoveRoomAlias(alias string) error
// Lookup the join events for all members in a room as requested by a given
// user. If the user is currently in the room, returns the room's current
// members, if not returns an empty array (TODO: Fix it)
// If the user requesting the list of members has never been in the room,
// returns nil.
// If there was an issue retrieving the events, returns an error.
GetMembershipEvents(roomNID types.RoomNID, requestSenderUserID string) (events []types.Event, err error)
}
// RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI
@ -182,6 +189,37 @@ func (r *RoomserverQueryAPI) loadEvents(eventNIDs []types.EventNID) ([]gomatrixs
return result, nil
}
// QueryMembershipsForRoom implements api.RoomserverQueryAPI
func (r *RoomserverQueryAPI) QueryMembershipsForRoom(
request *api.QueryMembershipsForRoomRequest,
response *api.QueryMembershipsForRoomResponse,
) error {
roomNID, err := r.DB.RoomNID(request.RoomID)
if err != nil {
return err
}
events, err := r.DB.GetMembershipEvents(roomNID, request.Sender)
if err != nil {
return nil
}
if events == nil {
response.HasBeenInRoom = false
response.JoinEvents = nil
return nil
}
response.HasBeenInRoom = true
response.JoinEvents = []gomatrixserverlib.ClientEvent{}
for _, event := range events {
clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll)
response.JoinEvents = append(response.JoinEvents, clientEvent)
}
return nil
}
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
servMux.Handle(
@ -226,4 +264,18 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
return util.JSONResponse{Code: 200, JSON: &response}
}),
)
servMux.Handle(
api.RoomserverQueryMembershipsForRoomPath,
common.MakeAPI("queryMembershipsForRoom", func(req *http.Request) util.JSONResponse {
var request api.QueryMembershipsForRoomRequest
var response api.QueryMembershipsForRoomResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := r.QueryMembershipsForRoom(&request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: 200, JSON: &response}
}),
)
}

View file

@ -508,18 +508,13 @@ func (u *membershipUpdater) SetToLeave(senderUserID string, eventID string) ([]s
return inviteEventIDs, nil
}
// GetMembershipEvents returns an array containing the join events for all
// members in a room as requested by a given user. If the user is currently in
// the room, returns the room's current members, if not returns an empty array
// TODO: in this case, send the list of members as it was when the user left
// If the user requesting the list of members has never been in the room, returns
// nil.
// If there was an issue retrieving the events, returns an error.
// GetMembershipEvents implements query.RoomserverQueryAPIDB
func (d *Database) GetMembershipEvents(roomNID types.RoomNID, requestSenderUserID string) (events []types.Event, err error) {
txn, err := d.db.Begin()
if err != nil {
return
}
defer txn.Commit()
requestSenderUserNID, err := d.assignStateKeyNID(txn, requestSenderUserID)
if err != nil {
@ -550,6 +545,9 @@ func (d *Database) GetMembershipEvents(roomNID types.RoomNID, requestSenderUserI
// only stores the latest join event NID for a given target user.
// The solution would be to build the state of a room after before
// the leave event and extract a members list from it.
// For now, we return an empty slice so we know the user has been
// in the room before.
events = []types.Event{}
}
return