From 584ebe772567a967886a976e1ca78897a447288b Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Tue, 8 Aug 2017 19:44:41 +0100 Subject: [PATCH] Add API and retrieval and update of visibility for a single room --- .../dendrite/roomserver/api/public_room.go | 141 ++++++++++++++++ .../roomserver/publicroom/public_room.go | 158 ++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 src/github.com/matrix-org/dendrite/roomserver/api/public_room.go create mode 100644 src/github.com/matrix-org/dendrite/roomserver/publicroom/public_room.go diff --git a/src/github.com/matrix-org/dendrite/roomserver/api/public_room.go b/src/github.com/matrix-org/dendrite/roomserver/api/public_room.go new file mode 100644 index 000000000..ba8ec7421 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/roomserver/api/public_room.go @@ -0,0 +1,141 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 api + +import ( + "net/http" +) + +// SetRoomVisibilityRequest is a request to SetRoomVisibility +type SetRoomVisibilityRequest struct { + // ID of the room of which the visibility will be updated + RoomID string `json:"room_id"` + // The new visibility of the room. Either "public" or "private" + Visibility string `json:"visibility"` +} + +// SetRoomVisibilityResponse is a response to SetRoomVisibility +type SetRoomVisibilityResponse struct{} + +// GetRoomVisibilityRequest is a request to GetRoomVisibility +type GetRoomVisibilityRequest struct { + // ID of the room to get the visibility of + RoomID string `json:"room_id"` +} + +// GetRoomVisibilityResponse is a response to GetRoomVisibility +type GetRoomVisibilityResponse struct { + // Visibility of the room. Either "public" or "private" + Visibility string `json:"visibility"` +} + +// GetPublicRoomsRequest is a request to GetPublicRooms +type GetPublicRoomsRequest struct { + Limit int16 `json:"limit"` + Since string `json:"since"` +} + +// GetPublicRoomsResponse is a response to GetPublicRooms +type GetPublicRoomsResponse struct { + Chunk []PublicRoomsChunk `json:"chunk"` + NextBatch string `json:"next_batch"` + PrevBatch string `json:"prev_batch"` + TotalRoomCountEstimate int64 `json:"total_room_count_estimate"` +} + +// PublicRoomsChunk implements the PublicRoomsChunk structure from the Matrix spec +type PublicRoomsChunk struct { + RoomID string `json:"room_id"` + Aliases []string `json:"aliases"` + CanonicalAlias string `json:"canonical_alias"` + Name string `json:"name"` + Topic string `json:"topic"` + AvatarURL string `json:"avatar_url"` + JoinedMembers int64 `json:"num_joined_members"` + WorldReadable bool `json:"world_readable"` + GuestCanJoin bool `json:"guest_can_join"` +} + +// RoomserverPublicRoomAPI is used to update or retrieve the visibility setting +// of a room, or to retrieve all of the public rooms +type RoomserverPublicRoomAPI interface { + // Set the visibility for a room + SetRoomVisibility( + req *SetRoomVisibilityRequest, + response *SetRoomVisibilityResponse, + ) error + + // Get the visibility for a room + GetRoomVisibility( + req *GetRoomVisibilityRequest, + response *GetRoomVisibilityResponse, + ) error + + // Get all rooms publicly visible rooms on the server + GetPublicRooms( + req *GetPublicRoomsRequest, + response *GetPublicRoomsResponse, + ) error +} + +// RoomserverSetRoomVisibilityPath is the HTTP path for the SetRoomVisibility API +const RoomserverSetRoomVisibilityPath = "/api/roomserver/setRoomVisibility" + +// RoomserverGetRoomVisibilityPath is the HTTP path for the GetRoomVisibility API +const RoomserverGetRoomVisibilityPath = "/api/roomserver/getRoomVisibility" + +// RoomserverGetPublicRoomsPath is the HTTP path for the GetPublicRooms API +const RoomserverGetPublicRoomsPath = "/api/roomserver/getPublicRooms" + +// NewRoomserverPublicRoomAPIHTTP creates a RoomserverPublicRoomAPI implemented by talking to a HTTP POST API. +// If httpClient is nil then it uses the http.DefaultClient +func NewRoomserverPublicRoomAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverPublicRoomAPI { + if httpClient == nil { + httpClient = http.DefaultClient + } + return &httpRoomserverPublicRoomAPI{roomserverURL, httpClient} +} + +type httpRoomserverPublicRoomAPI struct { + roomserverURL string + httpClient *http.Client +} + +// SetRoomVisibility implements RoomserverPublicRoomAPI +func (h *httpRoomserverPublicRoomAPI) SetRoomVisibility( + request *SetRoomVisibilityRequest, + response *SetRoomVisibilityResponse, +) error { + apiURL := h.roomserverURL + RoomserverSetRoomVisibilityPath + return postJSON(h.httpClient, apiURL, request, response) +} + +// GetRoomVisibility implements RoomserverPublicRoomAPI +func (h *httpRoomserverPublicRoomAPI) GetRoomVisibility( + request *GetRoomVisibilityRequest, + response *GetRoomVisibilityResponse, +) error { + apiURL := h.roomserverURL + RoomserverGetRoomVisibilityPath + return postJSON(h.httpClient, apiURL, request, response) +} + +// GetPublicRooms implements RoomserverPublicRoomAPI +func (h *httpRoomserverPublicRoomAPI) GetPublicRooms( + request *GetPublicRoomsRequest, + response *GetPublicRoomsResponse, +) error { + apiURL := h.roomserverURL + RoomserverGetPublicRoomsPath + return postJSON(h.httpClient, apiURL, request, response) +} diff --git a/src/github.com/matrix-org/dendrite/roomserver/publicroom/public_room.go b/src/github.com/matrix-org/dendrite/roomserver/publicroom/public_room.go new file mode 100644 index 000000000..a318489a6 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/roomserver/publicroom/public_room.go @@ -0,0 +1,158 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 publicroom + +import ( + "encoding/json" + "errors" + "net/http" + + "github.com/matrix-org/dendrite/common" + "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" + "github.com/matrix-org/util" +) + +// RoomserverPublicRoomAPIDatabase has the storage APIs needed to implement the +// public room API. +type RoomserverPublicRoomAPIDatabase interface { + // Lookup the numeric ID for the room. + // Returns 0 if the room doesn't exists. + // Returns an error if there was a problem talking to the database. + RoomNID(roomID string) (types.RoomNID, error) + // Checks the visibility of the room identified by the given numeric ID. + // Returns true if the room is publicly visible, returns false if not. + // If there's no room matching this numeric ID, or if the retrieval failed, + // returns an error. + IsRoomPublic(roomNID types.RoomNID) (bool, error) + // Returns an array of string containing the room IDs of the rooms that are + // publicly visible. + // Returns an error if the retrieval failed. + GetPublicRoomIDs() ([]string, error) + // Updates the visibility for a room to the given value: true means that the + // room is publicly visible, false means that the room isn't publicly visible. + // Returns an error if the update failed. + UpdateRoomVisibility(roomNID types.RoomNID, visibility bool) error + // Returns a map of the aliases bound to a given set of room IDs, ordered + // by room ID (ie map[roomID] = []alias) + // Returns an error if the retrieval failed + GetAliasesFromRoomIDs(roomIDs []string) (map[string][]string, error) +} + +// RoomserverPublicRoomAPI is an implementation of api.RoomserverPublicRoomAPI +type RoomserverPublicRoomAPI struct { + DB RoomserverPublicRoomAPIDatabase +} + +// SetRoomVisibility implements api.RoomserverPublicRoomAPI +func (r *RoomserverPublicRoomAPI) SetRoomVisibility( + req *api.SetRoomVisibilityRequest, + response *api.SetRoomVisibilityResponse, +) error { + roomNID, err := r.DB.RoomNID(req.RoomID) + if err != nil || roomNID == 0 { + return err + } + + var visibility bool + if req.Visibility == "public" { + visibility = true + } else if req.Visibility == "private" { + visibility = false + } else { + return errors.New("Invalid visibility setting") + } + + if err = r.DB.UpdateRoomVisibility(roomNID, visibility); err != nil { + return err + } + + return nil +} + +// GetRoomVisibility implements api.RoomserverPublicRoomAPI +func (r *RoomserverPublicRoomAPI) GetRoomVisibility( + req *api.GetRoomVisibilityRequest, + response *api.GetRoomVisibilityResponse, +) error { + roomNID, err := r.DB.RoomNID(req.RoomID) + if err != nil || roomNID == 0 { + return err + } + + if isPublic, err := r.DB.IsRoomPublic(roomNID); err != nil { + return err + } else if isPublic { + response.Visibility = "public" + } else { + response.Visibility = "private" + } + + return nil +} + +// GetPublicRooms implements api.RoomserverPublicRoomAPI +func (r *RoomserverPublicRoomAPI) GetPublicRooms( + req *api.GetPublicRoomsRequest, + response *api.GetPublicRoomsResponse, +) error { + return nil +} + +// SetupHTTP adds the RoomserverPublicRoomAPI handlers to the http.ServeMux. +func (r *RoomserverPublicRoomAPI) SetupHTTP(servMux *http.ServeMux) { + servMux.Handle( + api.RoomserverSetRoomVisibilityPath, + common.MakeAPI("setRoomVisibility", func(req *http.Request) util.JSONResponse { + var request api.SetRoomVisibilityRequest + var response api.SetRoomVisibilityResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.ErrorResponse(err) + } + if err := r.SetRoomVisibility(&request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: 200, JSON: &response} + }), + ) + servMux.Handle( + api.RoomserverGetRoomVisibilityPath, + common.MakeAPI("getRoomVisibility", func(req *http.Request) util.JSONResponse { + var request api.GetRoomVisibilityRequest + var response api.GetRoomVisibilityResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.ErrorResponse(err) + } + if err := r.GetRoomVisibility(&request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: 200, JSON: &response} + }), + ) + servMux.Handle( + api.RoomserverGetPublicRoomsPath, + common.MakeAPI("getPublicRooms", func(req *http.Request) util.JSONResponse { + var request api.GetPublicRoomsRequest + var response api.GetPublicRoomsResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.ErrorResponse(err) + } + if err := r.GetPublicRooms(&request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: 200, JSON: &response} + }), + ) +}