diff --git a/editor/editor_tests/server_api_test.cpp b/editor/editor_tests/server_api_test.cpp index 7afe0e1665..83d6e652f9 100644 --- a/editor/editor_tests/server_api_test.cpp +++ b/editor/editor_tests/server_api_test.cpp @@ -56,7 +56,7 @@ void DeleteOSMNodeIfExists(ServerApi06 const & api, uint64_t changeSetId, ms::La { node.attribute("changeset") = changeSetId; node.remove_child("tag"); - TEST(api.DeleteElement(editor::XMLFeature(node)), ()); + TEST_NO_THROW(api.DeleteElement(editor::XMLFeature(node)), ()); } } @@ -111,5 +111,15 @@ UNIT_TEST(OSM_ServerAPI_ChangesetAndNode) MY_SCOPE_GUARD(guard, changesetCloser); // New changeset has new id. node.SetAttribute("changeset", strings::to_string(changeSetId)); - TEST(api.DeleteElement(node), ()); + TEST_NO_THROW(api.DeleteElement(node), ()); +} + +UNIT_TEST(OSM_ServerAPI_Notes) +{ + ms::LatLon const pos(59.9, 30.5); + ServerApi06 const api = CreateAPI(); + uint64_t id; + TEST_NO_THROW(id = api.CreateNote(pos, "A test note"), ("Creating a note")); + TEST_GREATER(id, 0, ("Note id should be a positive integer")); + TEST_NO_THROW(api.CloseNote(id), ("Closing a note")); } diff --git a/editor/server_api.cpp b/editor/server_api.cpp index 0c3f80040d..7d4f00f552 100644 --- a/editor/server_api.cpp +++ b/editor/server_api.cpp @@ -84,7 +84,7 @@ void ServerApi06::ModifyElementAndSetVersion(editor::XMLFeature & element) const element.SetAttribute("version", strings::to_string(version)); } -bool ServerApi06::DeleteElement(editor::XMLFeature const & element) const +void ServerApi06::DeleteElement(editor::XMLFeature const & element) const { string const id = element.GetAttribute("id"); if (id.empty()) @@ -92,7 +92,8 @@ bool ServerApi06::DeleteElement(editor::XMLFeature const & element) const OsmOAuth::Response const response = m_auth.Request("/" + element.GetTypeString() + "/" + id, "DELETE", element.ToOSMString()); - return (response.first == OsmOAuth::HTTP::OK || response.first == OsmOAuth::HTTP::Gone); + if (response.first != OsmOAuth::HTTP::OK && response.first != OsmOAuth::HTTP::Gone) + MYTHROW(ErrorDeletingElement, ("Could not delete an element:", response)); } void ServerApi06::CloseChangeSet(uint64_t changesetId) const @@ -102,6 +103,29 @@ void ServerApi06::CloseChangeSet(uint64_t changesetId) const MYTHROW(ErrorClosingChangeSet, ("CloseChangeSet request has failed:", response)); } +uint64_t ServerApi06::CreateNote(ms::LatLon const & ll, string const & message) const +{ + CHECK(!message.empty(), ("Note content should not be empty.")); + string const params = "?lat=" + strings::to_string_dac(ll.lat, 7) + "&lon=" + strings::to_string_dac(ll.lon, 7) + "&text=" + UrlEncode(message); + OsmOAuth::Response const response = m_auth.Request("/notes" + params, "POST"); + if (response.first != OsmOAuth::HTTP::OK) + MYTHROW(ErrorAddingNote, ("Could not post a new note:", response)); + pugi::xml_document details; + if (!details.load_string(response.second.c_str())) + MYTHROW(CantParseServerResponse, ("Could not parse a note XML response", response)); + pugi::xml_node const uid = details.child("osm").child("note").child("id"); + if (!uid) + MYTHROW(CantParseServerResponse, ("Caould not find a note id", response)); + return uid.text().as_ullong(); +} + +void ServerApi06::CloseNote(uint64_t const id) const +{ + OsmOAuth::Response const response = m_auth.Request("/notes/" + strings::to_string(id) + "/close", "POST"); + if (response.first != OsmOAuth::HTTP::OK) + MYTHROW(ErrorDeletingElement, ("Could not close a note:", response)); +} + bool ServerApi06::TestOSMUser(string const & userName) { string const method = "/user/" + UrlEncode(userName); diff --git a/editor/server_api.hpp b/editor/server_api.hpp index 0cc88ce2db..e69983b5a5 100644 --- a/editor/server_api.hpp +++ b/editor/server_api.hpp @@ -38,7 +38,9 @@ public: DECLARE_EXCEPTION(ModifiedElementHasNoIdAttribute, ServerApi06Exception); DECLARE_EXCEPTION(ModifyElementHasFailed, ServerApi06Exception); DECLARE_EXCEPTION(ErrorClosingChangeSet, ServerApi06Exception); + DECLARE_EXCEPTION(ErrorAddingNote, ServerApi06Exception); DECLARE_EXCEPTION(DeletedElementHasNoIdAttribute, ServerApi06Exception); + DECLARE_EXCEPTION(ErrorDeletingElement, ServerApi06Exception); DECLARE_EXCEPTION(CantGetUserPreferences, ServerApi06Exception); DECLARE_EXCEPTION(CantParseUserPreferences, ServerApi06Exception); @@ -67,8 +69,11 @@ public: /// Some nodes can't be deleted if they are used in ways or relations. /// @param element should already have all attributes set, including "id", "version", "changeset". /// @returns true if element was successfully deleted (or was already deleted). - bool DeleteElement(editor::XMLFeature const & element) const; + void DeleteElement(editor::XMLFeature const & element) const; void CloseChangeSet(uint64_t changesetId) const; + /// @returns id of a created note. + uint64_t CreateNote(ms::LatLon const & ll, string const & message) const; + void CloseNote(uint64_t const id) const; /// @returns OSM xml string with features in the bounding box or empty string on error. OsmOAuth::Response GetXmlFeaturesInRect(m2::RectD const & latLonRect) const;