diff --git a/cmake/MatrixStructs.cmake b/cmake/MatrixStructs.cmake index 447deecf22216d03ded301ce8863900ae3b3ca84..f73b8648cf2d06a42540d682c042a10c83b35336 100644 --- a/cmake/MatrixStructs.cmake +++ b/cmake/MatrixStructs.cmake @@ -13,7 +13,7 @@ ExternalProject_Add( MatrixStructs GIT_REPOSITORY https://github.com/mujx/matrix-structs - GIT_TAG 83be1388e632a43f0570857cb79313c09fb3da0b + GIT_TAG da342f3b3ccf4f505459697f3d857274d0704c45 BUILD_IN_SOURCE 1 SOURCE_DIR ${MATRIX_STRUCTS_ROOT} diff --git a/src/client.cpp b/src/client.cpp index 8a930b5af316f2f780018fa3a7c849662610da5c..7700990cc5ead70dad5c8f047768d94c6a007b2f 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -230,6 +230,7 @@ Client::login( [this, callback](const mtx::responses::Login &resp, std::experimental::optional<mtx::client::errors::ClientError> err) { if (!err && resp.access_token.size()) { + user_id_ = resp.user_id; access_token_ = resp.access_token; } callback(resp, err); @@ -258,6 +259,18 @@ Client::logout( }); } +void +Client::set_displayname( + const std::string &displayname, + std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)> callback) +{ + mtx::requests::DisplayName req; + req.displayname = displayname; + + put<mtx::requests::DisplayName>( + "/profile/" + user_id_.toString() + "/displayname", req, callback); +} + void Client::create_room(const mtx::requests::CreateRoom &room_options, std::function<void(const mtx::responses::CreateRoom &, RequestErr)> callback) diff --git a/src/client.hpp b/src/client.hpp index acb076bf0f22cbe11b52d596ad07c7af0a7592ac..d6ecae08017da3229883be3306f2759893ab8bd3 100644 --- a/src/client.hpp +++ b/src/client.hpp @@ -49,6 +49,8 @@ public: std::function<void(const mtx::responses::Login &response, RequestErr err)>); //! Perform logout. void logout(std::function<void(const mtx::responses::Logout &response, RequestErr err)>); + //! Change displayname. + void set_displayname(const std::string &displayname, std::function<void(RequestErr err)>); //! Create a room with the given options. void create_room( const mtx::requests::CreateRoom &room_options, @@ -101,6 +103,20 @@ private: std::experimental::optional<mtx::client::errors::ClientError>)>, bool requires_auth = true); + // put function for the PUT HTTP requests that send responses + template<class Request, class Response> + void put(const std::string &endpoint, + const Request &req, + std::function<void(const Response &, + std::experimental::optional<mtx::client::errors::ClientError>)>, + bool requires_auth = true); + + template<class Request> + void put(const std::string &endpoint, + const Request &req, + std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)>, + bool requires_auth = true); + template<class Response> void get(const std::string &endpoint, std::function<void(const Response &, @@ -140,6 +156,8 @@ private: std::string server_; //! The access token that would be used for authentication. std::string access_token_; + //! The user ID associated with the client. + mtx::identifiers::User user_id_; //! The token that will be used as the 'since' parameter on the next sync request. std::string next_batch_token_; }; @@ -177,6 +195,60 @@ mtx::client::Client::post( do_request(session); } +// put function for the PUT HTTP requests that send responses +template<class Request, class Response> +void +mtx::client::Client::put( + const std::string &endpoint, + const Request &req, + std::function<void(const Response &, + std::experimental::optional<mtx::client::errors::ClientError>)> callback, + bool requires_auth) +{ + // Serialize request. + nlohmann::json j = req; + + using CallbackType = std::function<void( + const Response &, std::experimental::optional<mtx::client::errors::ClientError>)>; + + std::shared_ptr<Session> session = create_session<Response, CallbackType>(callback); + + session->request.method(boost::beast::http::verb::put); + session->request.target("/_matrix/client/r0" + endpoint); + session->request.set(boost::beast::http::field::user_agent, "mtxclient v0.1.0"); + session->request.set(boost::beast::http::field::content_type, "application/json"); + session->request.set(boost::beast::http::field::host, session->host); + if (requires_auth && !access_token_.empty()) + session->request.set(boost::beast::http::field::authorization, + "Bearer " + access_token_); + session->request.body() = j.dump(); + session->request.prepare_payload(); + + do_request(session); +} + +// provides PUT functionality for the endpoints which dont respond with a body +template<class Request> +void +mtx::client::Client::put( + const std::string &endpoint, + const Request &req, + std::function<void(std::experimental::optional<mtx::client::errors::ClientError>)> callback, + bool requires_auth) +{ + // Serialize request. + nlohmann::json j = req; + + mtx::client::Client::put<Request, mtx::responses::Empty>( + endpoint, + req, + [callback](const mtx::responses::Empty, + std::experimental::optional<mtx::client::errors::ClientError> err) { + callback(err); + }, + requires_auth); +} + template<class Response> void mtx::client::Client::get( diff --git a/tests/client_api.cpp b/tests/client_api.cpp index 1b8f913d2a362fa1baff94cec087688c1fcec6c3..b4bd3fa3ba79b7d2ef8e18aa68090efdac4ac7ca 100644 --- a/tests/client_api.cpp +++ b/tests/client_api.cpp @@ -82,6 +82,41 @@ TEST(ClientAPI, LoginWrongUsername) mtx_client->close(); } +TEST(ClientAPI, ChangeDisplayName) +{ + std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost"); + + mtx_client->login( + "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) { + ASSERT_FALSE(err); + validate_login("@alice:localhost", res); + + // Change the display name to Arthur Dent and verify its success through the lack + // of an error + mtx_client->set_displayname("Arthur Dent", + [](ErrType err) { ASSERT_FALSE(err); }); + }); + + mtx_client->close(); +} + +TEST(ClientAPI, EmptyDisplayName) +{ + std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost"); + + mtx_client->login( + "alice", "secret", [mtx_client](const mtx::responses::Login &res, ErrType err) { + ASSERT_FALSE(err); + validate_login("@alice:localhost", res); + + // Change the display name to an empty string and verify its success through the + // lack of an error + mtx_client->set_displayname("", [](ErrType err) { ASSERT_FALSE(err); }); + }); + + mtx_client->close(); +} + TEST(ClientAPI, CreateRoom) { std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");