[booking] deep links are injected into place page.

This commit is contained in:
Arsentiy Milchakov 2018-02-02 18:17:42 +03:00 committed by Vlad Mihaylenko
parent b8e539d581
commit a5e68c191c
7 changed files with 97 additions and 33 deletions

View file

@ -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;
};

View file

@ -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))

View file

@ -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;

View file

@ -10,11 +10,12 @@
#include "base/logging.hpp"
#include "base/thread.hpp"
#include "base/url_helpers.hpp"
#include "base/stl_helpers.hpp"
#include <chrono>
#include <iostream>
#include <numeric>
#include <sstream>
#include <unordered_set>
#include <utility>
#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<string> const kAvailabilityParamsForUrl = {"checkin", "checkout", "room"};
unordered_set<string> const kAvailabilityParamsForUniversalLink = {"checkin", "checkout", "room"};
unordered_set<string> const kAvailabilityParamsForDeepLink = {"checkin", "checkout"};
bool RunSimpleHttpRequest(bool const needAuth, string const & url, string & result)
{
@ -251,6 +254,33 @@ void FillHotelIds(string const & src, vector<std::string> & 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,

View file

@ -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;

View file

@ -13,6 +13,11 @@ std::string FormatTime(booking::AvailabilityParams::Time p)
{
return partners_api::FormatTime(p, "%Y-%m-%d");
}
bool Contains(std::unordered_set<std::string> 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<std::string> 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;
}

View file

@ -4,6 +4,7 @@
#include <chrono>
#include <string>
#include <unordered_set>
#include <vector>
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<Room>;
using Stars = std::vector<std::string>;
base::url::Params Get() const;
base::url::Params Get(std::unordered_set<std::string> const & filter = {}) const;
bool IsEmpty() const;
bool operator!=(AvailabilityParams const & rhs) const;
bool operator==(AvailabilityParams const & rhs) const;