From a5e68c191c12d17a50a01387f2a8b4062b4ac8bb Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Fri, 2 Feb 2018 18:17:42 +0300 Subject: [PATCH] [booking] deep links are injected into place page. --- base/url_helpers.hpp | 2 + map/framework.cpp | 6 ++ map/place_page_info.hpp | 3 + partners_api/booking_api.cpp | 69 +++++++++++++------- partners_api/booking_api.hpp | 1 + partners_api/booking_availability_params.cpp | 43 +++++++++--- partners_api/booking_availability_params.hpp | 6 +- 7 files changed, 97 insertions(+), 33 deletions(-) diff --git a/base/url_helpers.hpp b/base/url_helpers.hpp index 185d515ff6..ce27431a09 100644 --- a/base/url_helpers.hpp +++ b/base/url_helpers.hpp @@ -10,6 +10,8 @@ namespace url { struct Param { + Param(std::string const & name, std::string const & value) : m_name(name), m_value(value) {} + std::string m_name; std::string m_value; }; diff --git a/map/framework.cpp b/map/framework.cpp index 71a90dae4b..afd4cdfea4 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -860,6 +860,7 @@ void Framework::FillInfoFromFeatureType(FeatureType const & ft, place_page::Info auto const & baseUrl = info.GetMetadata().Get(feature::Metadata::FMD_WEBSITE); auto const & hotelId = info.GetMetadata().Get(feature::Metadata::FMD_SPONSORED_ID); info.SetSponsoredUrl(m_bookingApi->GetBookHotelUrl(baseUrl)); + info.SetSponsoredDeepLink(m_bookingApi->GetDeepLink(hotelId)); info.SetSponsoredDescriptionUrl(m_bookingApi->GetDescriptionUrl(baseUrl)); info.SetSponsoredReviewUrl(m_bookingApi->GetHotelReviewsUrl(hotelId, baseUrl)); if (!m_bookingAvailabilityParams.IsEmpty()) @@ -868,6 +869,11 @@ void Framework::FillInfoFromFeatureType(FeatureType const & ft, place_page::Info auto const & urlWithParams = m_bookingApi->ApplyAvailabilityParams(url, m_bookingAvailabilityParams); info.SetSponsoredUrl(urlWithParams); + + auto const & deepLink = info.GetSponsoredDeepLink(); + auto const & deepLinkWithParams = + m_bookingApi->ApplyAvailabilityParams(deepLink, m_bookingAvailabilityParams); + info.SetSponsoredDeepLink(deepLinkWithParams); } } else if (ftypes::IsOpentableChecker::Instance()(ft)) diff --git a/map/place_page_info.hpp b/map/place_page_info.hpp index d2c9a8155a..a58b4247fa 100644 --- a/map/place_page_info.hpp +++ b/map/place_page_info.hpp @@ -133,6 +133,8 @@ public: std::string const & GetBookingSearchUrl() const { return m_bookingSearchUrl; } void SetSponsoredUrl(std::string const & url) { m_sponsoredUrl = url; } std::string const & GetSponsoredUrl() const { return m_sponsoredUrl; } + void SetSponsoredDeepLink(std::string const & url) { m_sponsoredDeepLink = url; } + std::string const & GetSponsoredDeepLink() const { return m_sponsoredDeepLink; } void SetSponsoredDescriptionUrl(std::string const & url) { m_sponsoredDescriptionUrl = url; } std::string const & GetSponsoredDescriptionUrl() const { return m_sponsoredDescriptionUrl; } void SetSponsoredReviewUrl(std::string const & url) { m_sponsoredReviewUrl = url; } @@ -269,6 +271,7 @@ private: /// Sponsored feature urls. std::string m_sponsoredUrl; + std::string m_sponsoredDeepLink; std::string m_sponsoredDescriptionUrl; std::string m_sponsoredReviewUrl; diff --git a/partners_api/booking_api.cpp b/partners_api/booking_api.cpp index 80968303ce..9aa57f3cab 100644 --- a/partners_api/booking_api.cpp +++ b/partners_api/booking_api.cpp @@ -10,11 +10,12 @@ #include "base/logging.hpp" #include "base/thread.hpp" #include "base/url_helpers.hpp" -#include "base/stl_helpers.hpp" #include #include +#include #include +#include #include #include "3party/jansson/myjansson.hpp" @@ -35,9 +36,11 @@ 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/"; string const kSearchBaseUrl = "https://www.booking.com/search.html"; +string const kDeepLinkBaseUrl = "booking://hotel/"; string g_BookingUrlForTesting = ""; -vector const kAvailabilityParamsForUrl = {"checkin", "checkout", "room"}; +unordered_set const kAvailabilityParamsForUniversalLink = {"checkin", "checkout", "room"}; +unordered_set const kAvailabilityParamsForDeepLink = {"checkin", "checkout"}; bool RunSimpleHttpRequest(bool const needAuth, string const & url, string & result) { @@ -251,6 +254,33 @@ void FillHotelIds(string const & src, vector & ids) ids[i] = std::to_string(id); } } + +string ApplyAvailabilityParamsUniversal(string const & url, AvailabilityParams const & params) +{ + auto p = params.Get(kAvailabilityParamsForUniversalLink); + + auto const pos = url.find('#'); + + if (pos == string::npos) + return url::Make(url, p); + + string result = url::Make(url.substr(0, pos), p); + result.append(url.substr(pos)); + return result; +} + +string ApplyAvailabilityParamsDeep(string const & url, AvailabilityParams const & params) +{ + auto p = params.Get(kAvailabilityParamsForDeepLink); + + int const sum = std::accumulate( + params.m_rooms.cbegin(), params.m_rooms.cend(), 0, + [](int const s, AvailabilityParams::Room const & room) { return s + room.GetAdultsCount(); }); + + p.emplace_back("numberOfGuests", std::to_string(sum)); + + return url::Make(url, p); +} } // namespace namespace booking @@ -289,6 +319,16 @@ string Api::GetBookHotelUrl(string const & baseUrl) const return GetDescriptionUrl(baseUrl) + "#availability"; } +std::string Api::GetDeepLink(std::string const & hotelId) const +{ + ASSERT(!hotelId.empty(), ()); + + ostringstream os; + os << kDeepLinkBaseUrl << hotelId << "?affiliate_id=" << BOOKING_AFFILIATE_ID; + + return os.str(); +} + string Api::GetDescriptionUrl(string const & baseUrl) const { ASSERT(!baseUrl.empty(), ()); @@ -324,30 +364,15 @@ string Api::GetSearchUrl(string const & city, string const & name) const string Api::ApplyAvailabilityParams(string const & url, AvailabilityParams const & params) { + ASSERT(!url.empty(), ()); + if (params.IsEmpty()) return url; - auto p = params.Get(); + if (strings::StartsWith(url, "booking")) + return ApplyAvailabilityParamsDeep(url, params); - my::EraseIf(p, [](url::Param const & param) - { - for (auto const & paramForUrl : kAvailabilityParamsForUrl) - { - // We need to use all numbered rooms, because of this we use StartsWith instead of ==. - if (strings::StartsWith(param.m_name, paramForUrl)) - return false; - } - return true; - }); - - auto const pos = url.find('#'); - - if (pos == string::npos) - return url::Make(url, p); - - string result = url::Make(url.substr(0, pos), p); - result.append(url.substr(pos)); - return result; + return ApplyAvailabilityParamsUniversal(url, params); } void Api::GetMinPrice(string const & hotelId, string const & currency, diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp index a36bec8f73..5ae6e5819d 100644 --- a/partners_api/booking_api.hpp +++ b/partners_api/booking_api.hpp @@ -68,6 +68,7 @@ class Api { public: std::string GetBookHotelUrl(std::string const & baseUrl) const; + std::string GetDeepLink(std::string const & hotelId) 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; diff --git a/partners_api/booking_availability_params.cpp b/partners_api/booking_availability_params.cpp index dc27ab6cac..db5bbb428a 100644 --- a/partners_api/booking_availability_params.cpp +++ b/partners_api/booking_availability_params.cpp @@ -13,6 +13,11 @@ std::string FormatTime(booking::AvailabilityParams::Time p) { return partners_api::FormatTime(p, "%Y-%m-%d"); } + +bool Contains(std::unordered_set const & filter, std::string const & value) +{ + return filter.find(value) != filter.cend(); +} } // namespace namespace booking @@ -32,6 +37,16 @@ void AvailabilityParams::Room::SetAgeOfChild(int8_t ageOfChild) m_ageOfChild = ageOfChild; } +int8_t AvailabilityParams::Room::GetAdultsCount() const +{ + return m_adultsCount; +} + +int8_t AvailabilityParams::Room::GetAgeOfChild() const +{ + return m_ageOfChild; +} + std::string AvailabilityParams::Room::ToString() const { static std::string const kAdult = "A"; @@ -54,22 +69,30 @@ bool AvailabilityParams::Room::operator==(AvailabilityParams::Room const & rhs) return !this->operator!=(rhs); } -url::Params AvailabilityParams::Get() const +url::Params AvailabilityParams::Get(std::unordered_set const & filter /* = {} */) const { url::Params result; - result.push_back({"hotel_ids", strings::JoinStrings(m_hotelIds, ',')}); - result.push_back({"checkin", FormatTime(m_checkin)}); - result.push_back({"checkout", FormatTime(m_checkout)}); + if (filter.empty() || Contains(filter, "hotel_ids")) + result.emplace_back("hotel_ids", strings::JoinStrings(m_hotelIds, ',')); - for (size_t i = 0; i < m_rooms.size(); ++i) - result.push_back({"room" + to_string(i + 1), m_rooms[i].ToString()}); + if (filter.empty() || Contains(filter, "checkin")) + result.emplace_back("checkin", FormatTime(m_checkin)); - if (m_minReviewScore != 0.0) - result.push_back({"min_review_score", to_string(m_minReviewScore)}); + if (filter.empty() || Contains(filter, "checkout")) + result.emplace_back("checkout", FormatTime(m_checkout)); - if (!m_stars.empty()) - result.push_back({"stars", strings::JoinStrings(m_stars, ',')}); + if (filter.empty() || Contains(filter, "room")) + { + for (size_t i = 0; i < m_rooms.size(); ++i) + result.emplace_back("room" + to_string(i + 1), m_rooms[i].ToString()); + } + + if (m_minReviewScore != 0.0 && (filter.empty() || Contains(filter, "min_review_score"))) + result.emplace_back("min_review_score", to_string(m_minReviewScore)); + + if (!m_stars.empty() && (filter.empty() || Contains(filter, "stars"))) + result.emplace_back("stars", strings::JoinStrings(m_stars, ',')); return result; } diff --git a/partners_api/booking_availability_params.hpp b/partners_api/booking_availability_params.hpp index cb07de5dbd..a81c318ea2 100644 --- a/partners_api/booking_availability_params.hpp +++ b/partners_api/booking_availability_params.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace booking @@ -21,6 +22,9 @@ struct AvailabilityParams void SetAdultsCount(uint8_t adultsCount); void SetAgeOfChild(int8_t ageOfChild); + int8_t GetAdultsCount() const; + int8_t GetAgeOfChild() const; + std::string ToString() const; bool operator!=(Room const & rhs) const; @@ -37,7 +41,7 @@ struct AvailabilityParams using Rooms = std::vector; using Stars = std::vector; - base::url::Params Get() const; + base::url::Params Get(std::unordered_set const & filter = {}) const; bool IsEmpty() const; bool operator!=(AvailabilityParams const & rhs) const; bool operator==(AvailabilityParams const & rhs) const;