From aa984fcabcc7396301a2e50bd38b8b69194936e9 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 6 Jan 2017 14:39:25 +0000 Subject: [PATCH 1/5] Add AS membership list APIs Added function to get a user's avatar image URL --- client.go | 38 ++++++++++++++++++++++++++++++++++++++ client_test.go | 26 ++++++++++++++++++++++++++ responses.go | 13 +++++++++++++ 3 files changed, 77 insertions(+) diff --git a/client.go b/client.go index dee17b2..c8b8968 100644 --- a/client.go +++ b/client.go @@ -397,6 +397,24 @@ func (cli *Client) SetDisplayName(displayName string) (err error) { return } +// GetAvatarURL gets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-avatar-url +func (cli *Client) GetAvatarURL() (url string, err error) { + urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url") + s := struct { + AvatarURL string `json:"avatar_url"` + }{} + res, err := cli.MakeRequest("GET", urlPath, &s, nil) + if err != nil { + return "", err + } + + if err = json.Unmarshal(res, &s); err != nil { + return "", err + } + + return s.AvatarURL, nil +} + // SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid // contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal. func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) { @@ -539,6 +557,26 @@ func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, co return &m, nil } +// JoinedMembers returns a map of joined room members. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680 +// +// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes. +// This API is primarily designed for application services which may want to efficiently look up joined members in a room. +func (cli *Client) JoinedMembers(roomID string) (resp *RespJoinedMembers, err error) { + u := cli.BuildURL("rooms", roomID, "joined_members") + _, err = cli.MakeRequest("GET", u, nil, &resp) + return +} + +// JoinedRooms returns a list of rooms which the client is joined to. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680 +// +// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes. +// This API is primarily designed for application services which may want to efficiently look up joined rooms. +func (cli *Client) JoinedRooms() (resp *RespJoinedRooms, err error) { + u := cli.BuildURL("joined_rooms") + _, err = cli.MakeRequest("GET", u, nil, &resp) + return +} + func txnID() string { return "go" + strconv.FormatInt(time.Now().UnixNano(), 10) } diff --git a/client_test.go b/client_test.go index bd99260..32bcd19 100644 --- a/client_test.go +++ b/client_test.go @@ -24,6 +24,32 @@ func TestClient_LeaveRoom(t *testing.T) { } } +func TestClient_GetAvatarUrl(t *testing.T) { + // cli, _ := NewClient("https://matrix.org", "@_neb_google:matrix.org", "MDAxOGxvY2F0aW9uIG1hdHJpeC5vcmcKMDAxM2lkZW50aWZpZXIga2V5CjAwMTBjaWQgZ2VuID0gMQowMDJhY2lkIHVzZXJfaWQgPSBAX25lYl9nb29nbGU6bWF0cml4Lm9yZwowMDE2Y2lkIHR5cGUgPSBhY2Nlc3MKMDAyMWNpZCBub25jZSA9IDpUWHlDZ01KLnU3NFNWeFMKMDAyZnNpZ25hdHVyZSDSP25lx3Mm4JQ-eC5a5pTHxXpHYGFg55bYQNyEpofc2wo") + // url, err := cli.GetAvatarURL() + // if err != nil { + // t.Fatalf("Failed to get avatar URL: %s", err.Error()) + // } + // fmt.Printf("URL: %s\n", url) + + cli := mockClient(func(req *http.Request) (*http.Response, error) { + if req.Method == "GET" && req.URL.Path == "/_matrix/client/r0/profile/@user:test.gomatrix.org/avatar_url" { + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`{"avatar_url":"mxc://matrix.org/iJaUjkshgdfsdkjfn"}`)), + }, nil + } + return nil, fmt.Errorf("unhandled URL: %s", req.URL.Path) + }) + + if response, err := cli.GetAvatarURL(); err != nil { + t.Fatalf("GetAvatarURL: Got error: %s", err.Error()) + } else if response == "" { + t.Fatal("GetAvatarURL: Got empty response") + } + +} + func TestClient_StateEvent(t *testing.T) { cli := mockClient(func(req *http.Request) (*http.Response, error) { if req.Method == "GET" && req.URL.Path == "/_matrix/client/r0/rooms/!foo:bar/state/m.room.name" { diff --git a/responses.go b/responses.go index cf10168..de7a8ae 100644 --- a/responses.go +++ b/responses.go @@ -45,6 +45,19 @@ type RespBanUser struct{} // RespUnbanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban type RespUnbanUser struct{} +// RespJoinedRooms is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680 +type RespJoinedRooms struct { + JoinedRooms []string `json:"joined_rooms"` +} + +// RespJoinedMembers is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680 +type RespJoinedMembers struct { + Joined map[string]struct { + DisplayName *string `json:"display_name"` + AvatarURL *string `json:"avatar_url"` + } `json:"joined"` +} + // RespSendEvent is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid type RespSendEvent struct { EventID string `json:"event_id"` From 4d75d81067ca9417b35d942fa8d4f5ba426c768f Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 15 Feb 2017 22:10:04 +0000 Subject: [PATCH 2/5] Add function to set a users' avatar --- client.go | 27 +++++++++++++++++++++++---- client_test.go | 23 ++++++++++++++++------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/client.go b/client.go index c8b8968..623a94b 100644 --- a/client.go +++ b/client.go @@ -403,18 +403,37 @@ func (cli *Client) GetAvatarURL() (url string, err error) { s := struct { AvatarURL string `json:"avatar_url"` }{} - res, err := cli.MakeRequest("GET", urlPath, &s, nil) + // res, err := cli.MakeRequest("GET", urlPath, nil, &s) + _, err = cli.MakeRequest("GET", urlPath, nil, &s) if err != nil { return "", err } - if err = json.Unmarshal(res, &s); err != nil { - return "", err - } + // if err = json.Unmarshal(res, &s); err != nil { + // return "", err + // } return s.AvatarURL, nil } +// SetAvatarURL sets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-avatar-url +func (cli *Client) SetAvatarURL(url string) (err error) { + urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url") + s := struct { + AvatarURL string `json:"avatar_url"` + }{url} + res, err := cli.MakeRequest("PUT", urlPath, &s, nil) + if err != nil { + return err + } + + if err = json.Unmarshal(res, &s); err != nil { + return err + } + + return nil +} + // SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid // contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal. func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) { diff --git a/client_test.go b/client_test.go index 32bcd19..f238e48 100644 --- a/client_test.go +++ b/client_test.go @@ -25,13 +25,6 @@ func TestClient_LeaveRoom(t *testing.T) { } func TestClient_GetAvatarUrl(t *testing.T) { - // cli, _ := NewClient("https://matrix.org", "@_neb_google:matrix.org", "MDAxOGxvY2F0aW9uIG1hdHJpeC5vcmcKMDAxM2lkZW50aWZpZXIga2V5CjAwMTBjaWQgZ2VuID0gMQowMDJhY2lkIHVzZXJfaWQgPSBAX25lYl9nb29nbGU6bWF0cml4Lm9yZwowMDE2Y2lkIHR5cGUgPSBhY2Nlc3MKMDAyMWNpZCBub25jZSA9IDpUWHlDZ01KLnU3NFNWeFMKMDAyZnNpZ25hdHVyZSDSP25lx3Mm4JQ-eC5a5pTHxXpHYGFg55bYQNyEpofc2wo") - // url, err := cli.GetAvatarURL() - // if err != nil { - // t.Fatalf("Failed to get avatar URL: %s", err.Error()) - // } - // fmt.Printf("URL: %s\n", url) - cli := mockClient(func(req *http.Request) (*http.Response, error) { if req.Method == "GET" && req.URL.Path == "/_matrix/client/r0/profile/@user:test.gomatrix.org/avatar_url" { return &http.Response{ @@ -50,6 +43,22 @@ func TestClient_GetAvatarUrl(t *testing.T) { } +func TestClient_SetAvatarUrl(t *testing.T) { + cli := mockClient(func(req *http.Request) (*http.Response, error) { + if req.Method == "PUT" && req.URL.Path == "/_matrix/client/r0/profile/@user:test.gomatrix.org/avatar_url" { + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`{}`)), + }, nil + } + return nil, fmt.Errorf("unhandled URL: %s", req.URL.Path) + }) + + if err := cli.SetAvatarURL("https://foo.com/bar.png"); err != nil { + t.Fatalf("GetAvatarURL: Got error: %s", err.Error()) + } +} + func TestClient_StateEvent(t *testing.T) { cli := mockClient(func(req *http.Request) (*http.Response, error) { if req.Method == "GET" && req.URL.Path == "/_matrix/client/r0/rooms/!foo:bar/state/m.room.name" { From 971abecece2d48cb12f17746804d1e163fc4347a Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 15 Feb 2017 23:05:35 +0000 Subject: [PATCH 3/5] Test response URL --- client_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client_test.go b/client_test.go index f238e48..9b7d2da 100644 --- a/client_test.go +++ b/client_test.go @@ -39,6 +39,8 @@ func TestClient_GetAvatarUrl(t *testing.T) { t.Fatalf("GetAvatarURL: Got error: %s", err.Error()) } else if response == "" { t.Fatal("GetAvatarURL: Got empty response") + } else if response != "mxc://matrix.org/iJaUjkshgdfsdkjfn" { + t.Fatalf("Unexpected response URL: %s", response) } } From 5e63dffd1b13567f89833864e42bb5ae2fe18f33 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 15 Feb 2017 23:11:12 +0000 Subject: [PATCH 4/5] Cleanup commented code --- client.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client.go b/client.go index 623a94b..896c3ba 100644 --- a/client.go +++ b/client.go @@ -403,16 +403,12 @@ func (cli *Client) GetAvatarURL() (url string, err error) { s := struct { AvatarURL string `json:"avatar_url"` }{} - // res, err := cli.MakeRequest("GET", urlPath, nil, &s) + _, err = cli.MakeRequest("GET", urlPath, nil, &s) if err != nil { return "", err } - // if err = json.Unmarshal(res, &s); err != nil { - // return "", err - // } - return s.AvatarURL, nil } From b8c578e6fb7dc627ebf92b05c90ce9d69261fe5f Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Thu, 16 Feb 2017 13:52:55 +0000 Subject: [PATCH 5/5] Cleanup cruft --- client.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client.go b/client.go index 896c3ba..29784eb 100644 --- a/client.go +++ b/client.go @@ -418,15 +418,11 @@ func (cli *Client) SetAvatarURL(url string) (err error) { s := struct { AvatarURL string `json:"avatar_url"` }{url} - res, err := cli.MakeRequest("PUT", urlPath, &s, nil) + _, err = cli.MakeRequest("PUT", urlPath, &s, nil) if err != nil { return err } - if err = json.Unmarshal(res, &s); err != nil { - return err - } - return nil }