Implement ListRoom GET/PUT methods

This commit is contained in:
nxshock 2019-07-31 20:01:20 +05:00
parent ef06534124
commit e8165db50f
11 changed files with 152 additions and 15 deletions

View File

@ -11,4 +11,6 @@ Implemented from [Client-Server API](https://matrix.org/docs/spec/client_server/
- [x] [5.7.1 GET /_matrix/client/r0/account/whoami](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-account-whoami) - [x] [5.7.1 GET /_matrix/client/r0/account/whoami](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-account-whoami)
- [x] [6.1 GET /_matrix/client/r0/capabilities](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities) - [x] [6.1 GET /_matrix/client/r0/capabilities](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities)
- [x] [10.4.1 GET /_matrix/client/r0/joined_rooms](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-joined-rooms) - [x] [10.4.1 GET /_matrix/client/r0/joined_rooms](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-joined-rooms)
- [x] [10.5.1 GET /_matrix/client/r0/directory/list/room/{roomId}](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-directory-list-room-roomid)
- [x] [10.5.2 PUT /_matrix/client/r0/directory/list/room/{roomId}](https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-directory-list-room-roomid)
- [x] [13.10.1.1 GET /_matrix/client/r0/devices](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-devices) - [x] [13.10.1.1 GET /_matrix/client/r0/devices](https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-devices)

View File

@ -12,6 +12,7 @@ type Backend interface {
Register(username, password, device string) (user User, token string, err *models.ApiError) Register(username, password, device string) (user User, token string, err *models.ApiError)
Login(username, password, device string) (token string, err *models.ApiError) Login(username, password, device string) (token string, err *models.ApiError)
GetUserByToken(token string) (user User) GetUserByToken(token string) (user User)
GetRoomByID(id string) Room
Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err *models.ApiError) Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err *models.ApiError)
} }
@ -23,6 +24,7 @@ type Room interface {
Name() string Name() string
Topic() string Topic() string
Events() []rooms.Event Events() []rooms.Event
Visibility() createroom.VisibilityType
} }
type User interface { type User interface {
@ -36,6 +38,7 @@ type User interface {
JoinedRooms() []Room JoinedRooms() []Room
ChangePassword(newPassword string) ChangePassword(newPassword string)
Devices() []devices.Device Devices() []devices.Device
SetRoomVisibility(Room, createroom.VisibilityType) *models.ApiError
Logout(token string) Logout(token string)
LogoutAll() LogoutAll()
} }

View File

@ -90,3 +90,16 @@ func (backend *Backend) GetUserByToken(token string) internal.User {
return nil return nil
} }
func (backend *Backend) GetRoomByID(id string) internal.Room {
backend.mutex.Lock()
defer backend.mutex.Unlock()
for roomID, room := range backend.rooms {
if roomID == id {
return room
}
}
return nil
}

View File

@ -4,6 +4,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/nxshock/signaller/internal/models/createroom"
) )
func TestRegisterUser(t *testing.T) { func TestRegisterUser(t *testing.T) {
@ -89,3 +91,21 @@ func TestLogout(t *testing.T) {
assert.Nil(t, backend.GetUserByToken(token)) assert.Nil(t, backend.GetUserByToken(token))
} }
func TestGetRoomByID(t *testing.T) {
backend := NewBackend("localhost")
user, token, err := backend.Register("user", "", "")
assert.Nil(t, err)
assert.NotNil(t, user)
assert.NotEmpty(t, token)
request := createroom.Request{
RoomAliasName: "room1",
Name: "room1"}
room, err := user.CreateRoom(request)
assert.Nil(t, err)
assert.NotNil(t, room)
assert.Equal(t, room.ID(), backend.GetRoomByID(room.ID()).ID())
}

View File

@ -10,7 +10,7 @@ import (
type Room struct { type Room struct {
id string id string
Visibility createroom.VisibilityType visibility createroom.VisibilityType
aliasName string aliasName string
name string name string
topic string topic string
@ -72,6 +72,13 @@ func (room *Room) Events() []rooms.Event {
return result return result
} }
func (room *Room) Visibility() createroom.VisibilityType {
room.mutex.RLock()
defer room.mutex.RUnlock()
return room.visibility
}
func (room *Room) Creator() internal.User { func (room *Room) Creator() internal.User {
room.mutex.RLock() room.mutex.RLock()
defer room.mutex.RUnlock() defer room.mutex.RUnlock()

View File

@ -83,21 +83,22 @@ func (user *User) CreateRoom(request createroom.Request) (internal.Room, *models
} }
room := &Room{ room := &Room{
id: newToken(groupIDSize), id: newToken(groupIDSize),
aliasName: request.RoomAliasName, aliasName: request.RoomAliasName,
name: request.Name, name: request.Name,
topic: request.Topic, topic: request.Topic,
events: events, events: events,
creator: user, creator: user,
joined: []internal.User{user}, joined: []internal.User{user},
server: user.backend} visibility: request.Visibility,
server: user.backend}
for i, _ := range room.events { for i, _ := range room.events {
room.events[i].Room = room room.events[i].Room = room
//v.Room = room //v.Room = room
} }
user.backend.rooms[room.id] = room user.backend.rooms[room.ID()] = room
return room, nil return room, nil
} }
@ -193,6 +194,19 @@ func (user *User) Devices() []devices.Device {
return result return result
} }
func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) *models.ApiError {
if user.ID() != room.Creator().ID() {
return internal.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too
}
room.(*Room).mutex.Lock()
defer room.(*Room).mutex.Unlock()
room.(*Room).visibility = visibilityType
return nil
}
func (user *User) ChangePassword(newPassword string) { func (user *User) ChangePassword(newPassword string) {
user.mutex.Lock() user.mutex.Lock()
defer user.mutex.Unlock() defer user.mutex.Unlock()

View File

@ -143,3 +143,24 @@ func TestDevices(t *testing.T) {
assert.Len(t, devices, 1) assert.Len(t, devices, 1)
assert.Equal(t, expectedDeviceID, devices[0].DeviceID) assert.Equal(t, expectedDeviceID, devices[0].DeviceID)
} }
func TestSetRoomVisibility(t *testing.T) {
backend := NewBackend("localhost")
user, _, err := backend.Register("user1", "", "")
assert.Nil(t, err)
request := createroom.Request{
RoomAliasName: "room1",
Name: "room1",
Visibility: createroom.VisibilityTypePrivate}
room, err := user.CreateRoom(request)
assert.Nil(t, err)
assert.NotNil(t, room)
assert.Equal(t, createroom.VisibilityTypePrivate, room.Visibility())
err = user.SetRoomVisibility(room, createroom.VisibilityTypePublic)
assert.Nil(t, err)
assert.Equal(t, createroom.VisibilityTypePublic, room.Visibility())
}

View File

@ -8,11 +8,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/gorilla/mux"
"github.com/nxshock/signaller/internal/models/common" "github.com/nxshock/signaller/internal/models/common"
"github.com/nxshock/signaller/internal/models" "github.com/nxshock/signaller/internal/models"
"github.com/nxshock/signaller/internal/models/capabilities" "github.com/nxshock/signaller/internal/models/capabilities"
"github.com/nxshock/signaller/internal/models/joinedrooms" "github.com/nxshock/signaller/internal/models/joinedrooms"
"github.com/nxshock/signaller/internal/models/listroom"
login "github.com/nxshock/signaller/internal/models/login" login "github.com/nxshock/signaller/internal/models/login"
"github.com/nxshock/signaller/internal/models/password" "github.com/nxshock/signaller/internal/models/password"
register "github.com/nxshock/signaller/internal/models/register" register "github.com/nxshock/signaller/internal/models/register"
@ -290,6 +293,48 @@ func DevicesHandler(w http.ResponseWriter, r *http.Request) {
} }
// https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-directory-list-room-roomid
// https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-directory-list-room-roomid
func listRoomHandler(w http.ResponseWriter, r *http.Request) {
room := currServer.Backend.GetRoomByID(mux.Vars(r)["roomID"]) // TODO: can ["roomID"] throw panic?
if room == nil {
errorResponse(w, models.M_NOT_FOUND, http.StatusBadRequest, "room not found")
return
}
switch r.Method {
case http.MethodGet:
response := listroom.Response{
Visibility: room.Visibility()}
sendJsonResponse(w, http.StatusOK, response)
case http.MethodPut:
token := getTokenFromResponse(r)
if token == "" {
errorResponse(w, models.M_FORBIDDEN, http.StatusForbidden, "")
return
}
user := currServer.Backend.GetUserByToken(token)
if user == nil {
errorResponse(w, models.M_UNKNOWN_TOKEN, http.StatusBadRequest, "")
return
}
var request listroom.Request
err := getRequest(r, &request)
if err != nil {
errorResponse(w, models.M_BAD_JSON, http.StatusBadRequest, err.Error())
return
}
user.SetRoomVisibility(room, request.Visibility)
sendJsonResponse(w, http.StatusOK, struct{}{})
default:
errorResponse(w, models.M_UNKNOWN, http.StatusBadRequest, "wrong method: "+r.Method)
}
}
func sendJsonResponse(w http.ResponseWriter, httpStatus int, data interface{}) error { func sendJsonResponse(w http.ResponseWriter, httpStatus int, data interface{}) error {
b, err := json.Marshal(data) b, err := json.Marshal(data)
if err != nil { if err != nil {

View File

@ -9,7 +9,7 @@ type VisibilityType string
const ( const (
VisibilityTypePrivate VisibilityType = "private" VisibilityTypePrivate VisibilityType = "private"
VisibilityTypePublic = "public" VisibilityTypePublic VisibilityType = "public"
) )
type Preset string type Preset string

View File

@ -0,0 +1,13 @@
package listroom
import (
"github.com/nxshock/signaller/internal/models/createroom"
)
type Request struct {
Visibility createroom.VisibilityType `json:"visibility"` // The new visibility setting for the room. Defaults to 'public'. One of: ["private", "public"]
}
type Response struct {
Visibility createroom.VisibilityType `json:"visibility"` // The visibility of the room in the directory. One of: ["private", "public"]
}

View File

@ -1,14 +1,12 @@
package internal package internal
import ( import (
"errors"
"net/http" "net/http"
"strconv"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"errors"
"strconv"
"github.com/nxshock/signaller/internal/models/capabilities" "github.com/nxshock/signaller/internal/models/capabilities"
) )
@ -38,6 +36,7 @@ func NewServer(port int) (*Server, error) {
router.HandleFunc("/_matrix/client/r0/sync", SyncHandler) router.HandleFunc("/_matrix/client/r0/sync", SyncHandler)
router.HandleFunc("/_matrix/client/r0/capabilities", CapabilitiesHandler) router.HandleFunc("/_matrix/client/r0/capabilities", CapabilitiesHandler)
router.HandleFunc("/_matrix/client/r0/devices", DevicesHandler) router.HandleFunc("/_matrix/client/r0/devices", DevicesHandler)
router.HandleFunc("/_matrix/client/r0/directory/list/room/{roomID}", listRoomHandler)
router.HandleFunc("/", RootHandler) router.HandleFunc("/", RootHandler)
if port <= 0 || port > 65535 { if port <= 0 || port > 65535 {