Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArsentiy Milchakov <milcars@mapswithme.com>2017-10-18 17:08:05 +0300
committerYuri Gorshenin <mipt.vi002@gmail.com>2017-10-23 16:03:33 +0300
commitd24ac54087b9c364224fd2aab4111c2eb038db1c (patch)
tree9784f7efac252d255e0324ed14b407d48319b712
parent7585a2c1e11e82a904c3024181a3b5ece49f7617 (diff)
[partners_api] booking api hotelAvailability method implementation
-rw-r--r--partners_api/booking_api.cpp146
-rw-r--r--partners_api/booking_api.hpp101
-rw-r--r--partners_api/partners_api_tests/booking_tests.cpp43
-rw-r--r--tools/python/ResponseProvider.py4
-rw-r--r--tools/python/jsons.py22
5 files changed, 259 insertions, 57 deletions
diff --git a/partners_api/booking_api.cpp b/partners_api/booking_api.cpp
index 2b1cb97bb3..bba059d78a 100644
--- a/partners_api/booking_api.cpp
+++ b/partners_api/booking_api.cpp
@@ -6,26 +6,29 @@
#include "coding/url_encode.hpp"
#include "base/get_time.hpp"
-#include "base/gmtime.hpp"
#include "base/logging.hpp"
#include "base/thread.hpp"
-#include "std/initializer_list.hpp"
-#include "std/iomanip.hpp"
-#include "std/iostream.hpp"
-#include "std/sstream.hpp"
-#include "std/utility.hpp"
+#include <ctime>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <utility>
#include "3party/jansson/myjansson.hpp"
#include "private.h"
-namespace
-{
using namespace platform;
using namespace booking;
+using namespace std;
+using namespace std::chrono;
-string const kBookingApiBaseUrl = "https://distribution-xml.booking.com/json/bookings";
+namespace
+{
+string const kBookingApiBaseUrlV1 = "https://distribution-xml.booking.com/json/bookings";
+string const kBookingApiBaseUrlV2 = "https://distribution-xml.booking.com/2.0/json/";
string const kExtendedHotelInfoBaseUrl = "https://hotels.maps.me/getDescription";
string const kPhotoOriginalUrl = "http://aff.bstatic.com/images/hotel/max500/";
string const kPhotoSmallUrl = "http://aff.bstatic.com/images/hotel/max300/";
@@ -44,18 +47,20 @@ bool RunSimpleHttpRequest(bool const needAuth, string const & url, string & resu
result = request.ServerResponse();
return true;
}
+
return false;
}
-string MakeApiUrl(string const & func, initializer_list<pair<string, string>> const & params)
+string MakeApiUrl(string const & baseUrl, string const & func,
+ vector<pair<string, string>> const & params)
{
ASSERT_NOT_EQUAL(params.size(), 0, ());
ostringstream os;
if (!g_BookingUrlForTesting.empty())
- os << g_BookingUrlForTesting << "." << func << "?";
+ os << g_BookingUrlForTesting << func << "?";
else
- os << kBookingApiBaseUrl << "." << func << "?";
+ os << baseUrl << func << "?";
bool firstParam = true;
for (auto const & param : params)
@@ -74,6 +79,33 @@ string MakeApiUrl(string const & func, initializer_list<pair<string, string>> co
return os.str();
}
+string MakeApiUrlV1(string const & func, vector<pair<string, string>> const & params)
+{
+ return MakeApiUrl(kBookingApiBaseUrlV1, "." + func, params);
+}
+
+string MakeApiUrlV2(string const & func, vector<pair<string, string>> const & params)
+{
+ return MakeApiUrl(kBookingApiBaseUrlV2, "/" + func, params);
+}
+
+std::string FormatTime(system_clock::time_point p)
+{
+ time_t t = duration_cast<seconds>(p.time_since_epoch()).count();
+ ostringstream os;
+ os << put_time(std::gmtime(&t), "%Y-%m-%d");
+ return os.str();
+}
+
+string FormatByComma(vector<string> const & src)
+{
+ ostringstream os;
+ ostream_iterator<string> outIt(os, ",");
+ copy(src.cbegin(), src.cend(), outIt);
+
+ return os.str();
+}
+
void ClearHotelInfo(HotelInfo & info)
{
info.m_hotelId.clear();
@@ -238,26 +270,56 @@ void FillPriceAndCurrency(string const & src, string const & currency, string &
}
}
}
+
+void FillHotelIds(string const & src, vector<uint64_t> & result)
+{
+ my::Json root(src.c_str());
+ auto const resultsArray = json_object_get(root.get(), "result");
+
+ auto const size = json_array_size(resultsArray);
+ if (size == 0)
+ return;
+
+ result.resize(size);
+ for (size_t i = 0; i < size; ++i)
+ {
+ auto const obj = json_array_get(resultsArray, i);
+ FromJSONObject(obj, "hotel_id", result[i]);
+ }
+}
} // namespace
namespace booking
{
+vector<pair<string, string>> AvailabilityParams::Get() const
+{
+ vector<pair<string, string>> result;
+
+ result.push_back({"hotel_ids", FormatByComma(m_hotelIds)});
+ result.push_back({"checkin", FormatTime(m_checkin)});
+ result.push_back({"checkout", FormatTime(m_checkout)});
+
+ for (size_t i = 0; i < m_rooms.size(); ++i)
+ result.push_back({"room" + to_string(i+1), m_rooms[i]});
+
+ if (m_minReviewScore != 0.0)
+ result.push_back({"min_review_score", std::to_string(m_minReviewScore)});
+
+ if (!m_stars.empty())
+ result.push_back({"stars", FormatByComma(m_stars)});
+
+ return result;
+}
+
// static
bool RawApi::GetHotelAvailability(string const & hotelId, string const & currency, string & result)
{
- char dateArrival[12]{};
- char dateDeparture[12]{};
-
system_clock::time_point p = system_clock::from_time_t(time(nullptr));
- tm arrival = my::GmTime(system_clock::to_time_t(p));
- tm departure = my::GmTime(system_clock::to_time_t(p + hours(24)));
- strftime(dateArrival, sizeof(dateArrival), "%Y-%m-%d", &arrival);
- strftime(dateDeparture, sizeof(dateDeparture), "%Y-%m-%d", &departure);
-
- string url = MakeApiUrl("getHotelAvailability", {{"hotel_ids", hotelId},
- {"currency_code", currency},
- {"arrival_date", dateArrival},
- {"departure_date", dateDeparture}});
+
+ string url = MakeApiUrlV1("getHotelAvailability", {{"hotel_ids", hotelId},
+ {"currency_code", currency},
+ {"arrival_date", FormatTime(p)},
+ {"departure_date", FormatTime(p + hours(24))}});
return RunSimpleHttpRequest(true, url, result);
}
@@ -269,6 +331,14 @@ bool RawApi::GetExtendedInfo(string const & hotelId, string const & lang, string
return RunSimpleHttpRequest(false, os.str(), result);
}
+// static
+bool RawApi::HotelAvailability(AvailabilityParams const & params, string & result)
+{
+ string url = MakeApiUrlV2("hotelAvailability", params.Get());
+
+ return RunSimpleHttpRequest(true, url, result);
+}
+
string Api::GetBookHotelUrl(string const & baseUrl) const
{
ASSERT(!baseUrl.empty(), ());
@@ -363,6 +433,34 @@ void Api::GetHotelInfo(string const & hotelId, string const & lang, GetHotelInfo
});
}
+void Api::GetHotelAvailability(AvailabilityParams const & params,
+ GetHotelAvailabilityCallback const & fn)
+{
+ GetPlatform().RunOnNetworkThread([params, fn]()
+ {
+ std::vector<uint64_t> result;
+ string httpResult;
+ if (!RawApi::HotelAvailability(params, httpResult))
+ {
+ fn(result);
+ return;
+ }
+
+ try
+ {
+ FillHotelIds(httpResult, result);
+ }
+ catch (my::Json::Exception const & e)
+ {
+ LOG(LINFO, (httpResult));
+ LOG(LERROR, (e.Msg()));
+ result.clear();
+ }
+
+ fn(result);
+ });
+}
+
void SetBookingUrlForTesting(string const & url)
{
g_BookingUrlForTesting = url;
diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp
index c81acd611c..1cd8bd86b7 100644
--- a/partners_api/booking_api.hpp
+++ b/partners_api/booking_api.hpp
@@ -2,76 +2,111 @@
#include "platform/safe_callback.hpp"
-#include "std/chrono.hpp"
-#include "std/function.hpp"
-#include "std/shared_ptr.hpp"
-#include "std/string.hpp"
-#include "std/vector.hpp"
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
namespace booking
{
struct HotelPhotoUrls
{
- string m_small;
- string m_original;
+ std::string m_small;
+ std::string m_original;
};
struct HotelReview
{
/// An issue date.
- time_point<system_clock> m_date;
+ std::chrono::time_point<std::chrono::system_clock> m_date;
/// Author's hotel evaluation.
float m_score = 0.0;
/// Review author name.
- string m_author;
+ std::string m_author;
/// Review text. There can be either one or both positive/negative review.
- string m_pros;
- string m_cons;
+ std::string m_pros;
+ std::string m_cons;
};
struct HotelFacility
{
- string m_type;
- string m_name;
+ std::string m_type;
+ std::string m_name;
};
struct HotelInfo
{
- string m_hotelId;
+ std::string m_hotelId;
- string m_description;
- vector<HotelPhotoUrls> m_photos;
- vector<HotelFacility> m_facilities;
- vector<HotelReview> m_reviews;
+ std::string m_description;
+ std::vector<HotelPhotoUrls> m_photos;
+ std::vector<HotelFacility> m_facilities;
+ std::vector<HotelReview> m_reviews;
float m_score = 0.0;
uint32_t m_scoreCount = 0;
};
+/// Params for checking availability of hotels.
+/// [m_hotelIds], [m_checkin], [m_checkout], [m_rooms] are required.
+struct AvailabilityParams
+{
+ using Time = std::chrono::system_clock::time_point;
+
+ std::vector<std::pair<std::string, std::string>> Get() const;
+
+ /// Limit the result list to the specified hotels where they have availability for the
+ /// specified guests and dates.
+ std::vector<std::string> m_hotelIds;
+ /// The arrival date. Must be within 360 days in the future and in the format yyyy-mm-dd.
+ Time m_checkin;
+ /// The departure date. Must be later than [m_checkin]. Must be between 1 and 30 days after
+ /// [m_checkin]. Must be within 360 days in the future and in the format yyyy-mm-dd.
+ Time m_checkout;
+ /// Each room is s comma separated array of guests to stay in this room where "A" represents an
+ /// adult and an integer represents a child. eg room1=A,A,4 would be a room with 2 adults and 1
+ /// four year-old child. Child age numbers are 0..17.
+ std::vector<std::string> m_rooms;
+ /// Show only hotels with review_score >= that. min_review_score should be in the range 1 to 10.
+ /// Values are rounded down: min_review_score 7.8 will result in properties with review scores
+ /// of 7 and up.
+ double m_minReviewScore = {};
+ /// Limit to hotels with the given number(s) of stars. Supported values 1-5.
+ vector<std::string> m_stars;
+};
+
class RawApi
{
public:
- static bool GetHotelAvailability(string const & hotelId, string const & currency, string & result);
- static bool GetExtendedInfo(string const & hotelId, string const & lang, string & result);
+ // Booking Api v1 methods:
+ static bool GetHotelAvailability(std::string const & hotelId, std::string const & currency, std::string & result);
+ static bool GetExtendedInfo(std::string const & hotelId, std::string const & lang, std::string & result);
+ // Booking Api v2 methods:
+ static bool HotelAvailability(AvailabilityParams const & params, std::string & result);
};
-using GetMinPriceCallback = platform::SafeCallback<void(string const & hotelId, string const & price, string const & currency)>;
+using GetMinPriceCallback = platform::SafeCallback<void(std::string const & hotelId, std::string const & price, std::string const & currency)>;
using GetHotelInfoCallback = platform::SafeCallback<void(HotelInfo const & hotelInfo)>;
+using GetHotelAvailabilityCallback = platform::SafeCallback<void(std::vector<uint64_t> hotelIds)>;
class Api
{
public:
- string GetBookHotelUrl(string const & baseUrl) const;
- string GetDescriptionUrl(string const & baseUrl) const;
- string GetHotelReviewsUrl(string const & hotelId, string const & baseUrl) const;
- string GetSearchUrl(string const & city, string const & name) const;
- // Real-time information methods (used for retriving rapidly changing information).
- // These methods send requests directly to Booking.
- void GetMinPrice(string const & hotelId, string const & currency, GetMinPriceCallback const & fn);
-
- // Static information methods (use for information that can be cached).
- // These methods use caching server to prevent Booking from being ddossed.
- void GetHotelInfo(string const & hotelId, string const & lang, GetHotelInfoCallback const & fn);
+ std::string GetBookHotelUrl(std::string const & baseUrl) const;
+ std::string GetDescriptionUrl(std::string const & baseUrl) const;
+ std::string GetHotelReviewsUrl(std::string const & hotelId, std::string const & baseUrl) const;
+ std::string GetSearchUrl(std::string const & city, std::string const & name) const;
+ /// Real-time information methods (used for retriving rapidly changing information).
+ /// These methods send requests directly to Booking.
+ void GetMinPrice(std::string const & hotelId, std::string const & currency, GetMinPriceCallback const & fn);
+
+ /// Static information methods (use for information that can be cached).
+ /// These methods use caching server to prevent Booking from being ddossed.
+ void GetHotelInfo(std::string const & hotelId, std::string const & lang, GetHotelInfoCallback const & fn);
+
+ void GetHotelAvailability(AvailabilityParams const & params,
+ GetHotelAvailabilityCallback const & fn);
};
-void SetBookingUrlForTesting(string const & url);
+void SetBookingUrlForTesting(std::string const & url);
} // namespace booking
diff --git a/partners_api/partners_api_tests/booking_tests.cpp b/partners_api/partners_api_tests/booking_tests.cpp
index 43755bc77f..bf8e85994d 100644
--- a/partners_api/partners_api_tests/booking_tests.cpp
+++ b/partners_api/partners_api_tests/booking_tests.cpp
@@ -6,6 +6,8 @@
#include "base/scope_guard.hpp"
+#include <chrono>
+
using namespace partners_api;
namespace
@@ -26,6 +28,20 @@ UNIT_TEST(Booking_GetExtendedInfo)
TEST(!result.empty(), ());
}
+UNIT_TEST(Booking_HotelAvailability)
+{
+ booking::AvailabilityParams params;
+ params.m_hotelIds = {"98251"};
+ params.m_rooms = {"A,A"};
+ params.m_checkin = std::chrono::system_clock::now() + std::chrono::hours(24);
+ params.m_checkout = std::chrono::system_clock::now() + std::chrono::hours(24 * 7);
+ params.m_stars = {"4", "5"};
+ string result;
+ TEST(booking::RawApi::HotelAvailability(params, result), ());
+ TEST(!result.empty(), ());
+ LOG(LINFO, (result));
+}
+
UNIT_CLASS_TEST(AsyncGuiThread, Booking_GetMinPrice)
{
booking::SetBookingUrlForTesting("http://localhost:34568/booking/min_price");
@@ -110,4 +126,31 @@ UNIT_CLASS_TEST(AsyncGuiThread, GetHotelInfo)
TEST_EQUAL(info.m_facilities.size(), 7, ());
TEST_EQUAL(info.m_reviews.size(), 4, ());
}
+
+UNIT_CLASS_TEST(AsyncGuiThread, GetHotelAvailability)
+{
+ booking::SetBookingUrlForTesting("http://localhost:34568/booking/min_price");
+ MY_SCOPE_GUARD(cleanup, []() { booking::SetBookingUrlForTesting(""); });
+
+ booking::AvailabilityParams params;
+ params.m_hotelIds = {"77615", "10623"};
+ params.m_rooms = {"A,A"};
+ params.m_checkin = std::chrono::system_clock::now() + std::chrono::hours(24);
+ params.m_checkout = std::chrono::system_clock::now() + std::chrono::hours(24 * 7);
+ params.m_stars = {"4"};
+ booking::Api api;
+ std::vector<uint64_t> result;
+
+ api.GetHotelAvailability(params, [&result](std::vector<uint64_t> const & r)
+ {
+ result = r;
+ testing::Notify();
+ });
+ testing::Wait();
+
+ TEST_EQUAL(result.size(), 3, ());
+ TEST_EQUAL(result[0], 10623, ());
+ TEST_EQUAL(result[1], 10624, ());
+ TEST_EQUAL(result[2], 10625, ());
+}
}
diff --git a/tools/python/ResponseProvider.py b/tools/python/ResponseProvider.py
index 56f2e0e9b9..681af67c0f 100644
--- a/tools/python/ResponseProvider.py
+++ b/tools/python/ResponseProvider.py
@@ -143,6 +143,7 @@ class ResponseProvider:
"/partners/price": self.partners_price,
"/booking/min_price": self.partners_minprice,
"/booking/min_price.getHotelAvailability": self.partners_minprice,
+ "/booking/min_price/hotelAvailability": self.partners_hotel_availability,
"/partners/taxi_info": self.partners_yandex_taxi_info,
"/partners/get-offers-in-bbox/": self.partners_rent_nearby,
}[url]()
@@ -223,6 +224,9 @@ class ResponseProvider:
def partners_minprice(self):
return Payload(jsons.PARTNERS_MINPRICE)
+ def partners_hotel_availability(self):
+ return Payload(jsons.HOTEL_AVAILABILITY)
+
def partners_yandex_taxi_info(self):
return Payload(jsons.PARTNERS_TAXI_INFO)
diff --git a/tools/python/jsons.py b/tools/python/jsons.py
index 8fd47af932..03040fc966 100644
--- a/tools/python/jsons.py
+++ b/tools/python/jsons.py
@@ -186,6 +186,28 @@ PARTNERS_TIME = """
}
"""
+HOTEL_AVAILABILITY = """
+{
+ "result": [
+ {
+ "hotel_currency_code": "EUR",
+ "hotel_id": 10623,
+ "price": 801
+ },
+ {
+ "hotel_currency_code": "USD",
+ "hotel_id": 10624,
+ "price": 802
+ },
+ {
+ "hotel_currency_code": "RUR",
+ "hotel_id": 10625,
+ "price": 803
+ }
+ ]
+}
+"""
+
PARTNERS_MINPRICE = """
[
{