diff --git a/android/jni/com/mapswithme/maps/Sponsored.cpp b/android/jni/com/mapswithme/maps/Sponsored.cpp index 647ed3eaf8..fd7e8a6bd4 100644 --- a/android/jni/com/mapswithme/maps/Sponsored.cpp +++ b/android/jni/com/mapswithme/maps/Sponsored.cpp @@ -68,11 +68,13 @@ void PrepareClassRefs(JNIEnv * env, jclass sponsoredClass) "placepage/Sponsored$FacilityType;[Lcom/mapswithme/maps/review/Review;[Lcom/mapswithme/" "maps/widget/placepage/Sponsored$NearbyObject;J)V"); - // Sponsored(String rating, String price, String urlBook, String urlDescription) + // Sponsored(String rating, int impress, String price, String url, String deepLink, + // String descriptionUrl, String moreUrl, String reviewUrl, int type, + // int partnerIndex, String partnerName) g_sponsoredClassConstructor = jni::GetConstructorID( env, g_sponsoredClass, "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;IILjava/lang/String;)V"); + "Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); // static void onPriceReceived(final String id, final String price, final String currency) g_priceCallback = jni::GetStaticMethodID(env, g_sponsoredClass, "onPriceReceived", @@ -136,6 +138,7 @@ JNIEXPORT jobject JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_na jni::ToJavaString(env, ppInfo.GetSponsoredUrl()), jni::ToJavaString(env, ppInfo.GetSponsoredDeepLink()), jni::ToJavaString(env, ppInfo.GetSponsoredDescriptionUrl()), + jni::ToJavaString(env, ppInfo.GetSponsoredMoreUrl()), jni::ToJavaString(env, ppInfo.GetSponsoredReviewUrl()), static_cast(ppInfo.GetSponsoredType()), static_cast(ppInfo.GetPartnerIndex()), diff --git a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java index 1b88edde01..1530bc07d9 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java +++ b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java @@ -990,7 +990,7 @@ public class PlacePageView extends NestedScrollView // TODO go to selected object on map } - private void onSponsoredClick(final boolean book, final boolean isMoreDetails) + private void onSponsoredClick(final boolean book, final boolean isDetails) { Utils.checkConnection( getActivity(), R.string.common_check_internet_connection_dialog, new Utils.Proc() @@ -1020,7 +1020,7 @@ public class PlacePageView extends NestedScrollView } else { - String event = isMoreDetails ? PP_SPONSORED_DETAILS : PP_HOTEL_DESCRIPTION_LAND; + String event = isDetails ? PP_SPONSORED_DETAILS : PP_HOTEL_DESCRIPTION_LAND; Statistics.INSTANCE.trackHotelEvent(event, info, mMapObject); } break; @@ -1047,7 +1047,11 @@ public class PlacePageView extends NestedScrollView } else { - Utils.openUrl(getContext(), book ? info.getUrl() : info.getDescriptionUrl()); + if (book) + Utils.openUrl(getContext(), info.getUrl()); + else + Utils.openUrl(getContext(), isDetails ? info.getDescriptionUrl() + : info.getMoreUrl()); } } catch (ActivityNotFoundException e) diff --git a/android/src/com/mapswithme/maps/widget/placepage/Sponsored.java b/android/src/com/mapswithme/maps/widget/placepage/Sponsored.java index 4a7403540d..13d23f2fe9 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/Sponsored.java +++ b/android/src/com/mapswithme/maps/widget/placepage/Sponsored.java @@ -189,6 +189,8 @@ public final class Sponsored @NonNull private final String mDescriptionUrl; @NonNull + private final String mMoreUrl; + @NonNull private final String mReviewUrl; @SponsoredType private final int mType; @@ -198,8 +200,8 @@ public final class Sponsored private Sponsored(@NonNull String rating, @UGC.Impress int impress, @NonNull String price, @NonNull String url, @NonNull String deepLink, @NonNull String descriptionUrl, - @NonNull String reviewUrl, @SponsoredType int type, int partnerIndex, - @NonNull String partnerName) + @NonNull String moreUrl, @NonNull String reviewUrl, @SponsoredType int type, + int partnerIndex, @NonNull String partnerName) { mRating = rating; mImpress = impress; @@ -207,6 +209,7 @@ public final class Sponsored mUrl = url; mDeepLink = deepLink; mDescriptionUrl = descriptionUrl; + mMoreUrl = moreUrl; mReviewUrl = reviewUrl; mType = type; mPartnerIndex = partnerIndex; @@ -260,6 +263,12 @@ public final class Sponsored return mDescriptionUrl; } + @NonNull + String getMoreUrl() + { + return mMoreUrl; + } + @NonNull String getReviewUrl() { diff --git a/coding/sha1.cpp b/coding/sha1.cpp index a6182d497d..b1c412eed0 100644 --- a/coding/sha1.cpp +++ b/coding/sha1.cpp @@ -69,6 +69,18 @@ SHA1::Hash SHA1::CalculateForString(std::string const & str) return result; } +// static +std::string SHA1::CalculateForStringFormatted(std::string const & str) +{ + auto const hashRaw = CalculateForString(str); + + std::ostringstream os; + for (auto const value : hashRaw) + os << std::hex << static_cast(value); + + return os.str(); +} + // static std::string SHA1::CalculateBase64ForString(std::string const & str) { diff --git a/coding/sha1.hpp b/coding/sha1.hpp index e0ad4ad225..842eb95466 100644 --- a/coding/sha1.hpp +++ b/coding/sha1.hpp @@ -15,6 +15,8 @@ public: static std::string CalculateBase64(std::string const & filePath); static Hash CalculateForString(std::string const & str); + // String representation of 40-number hex digit. + static std::string CalculateForStringFormatted(std::string const & str); static std::string CalculateBase64ForString(std::string const & str); }; } // coding diff --git a/iphone/Maps/Common/Statistics/StatisticsStrings.h b/iphone/Maps/Common/Statistics/StatisticsStrings.h index a49d0731f2..1ca5f95735 100644 --- a/iphone/Maps/Common/Statistics/StatisticsStrings.h +++ b/iphone/Maps/Common/Statistics/StatisticsStrings.h @@ -264,6 +264,7 @@ static NSString * const kStatPlacePageHotelBook = @"Placepage_Hotel_book"; static NSString * const kStatPlacePageHotelDetails = @"Placepage_Hotel_details"; static NSString * const kStatPlacePageHotelFacilities = @"PlacePage_Hotel_Facilities_open"; static NSString * const kStatPlacePageHotelGallery = @"PlacePage_Hotel_Gallery_open"; +static NSString * const kStatPlacePageHotelMore = @"PlacePage_Hotel_Description_land"; static NSString * const kStatPlacePageHotelReviews = @"PlacePage_Hotel_Reviews_land"; static NSString * const kStatPlacePageHotelSearch = @"Search.Booking.Com"; static NSString * const kStatPlacePageNonBuilding = @"placepage_nonbuilding"; diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageButtonsProtocol.h b/iphone/Maps/UI/PlacePage/MWMPlacePageButtonsProtocol.h index 306197e9e9..610967743b 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageButtonsProtocol.h +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageButtonsProtocol.h @@ -11,7 +11,10 @@ typedef UIView * _Nullable (^MWMPlacePageButtonsDismissBlock)(NSInteger); - (void)editPlace; - (void)addPlace; - (void)addBusiness; -- (void)book:(BOOL)isDescription; +- (void)book; +- (void)openDescriptionUrl; +- (void)openMoreUrl; +- (void)openReviewUrl; - (void)editBookmark; - (void)orderTaxi:(MWMPlacePageTaxiProvider)provider; - (void)showAllFacilities; diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageData.h b/iphone/Maps/UI/PlacePage/MWMPlacePageData.h index 9cf9107be4..1b34b26bd3 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageData.h +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageData.h @@ -179,6 +179,8 @@ using NewSectionsAreReady = void (^)(NSRange const & range, MWMPlacePageData * d - (NSURL *)sponsoredURL; - (NSURL *)deepLink; - (NSURL *)sponsoredDescriptionURL; +- (NSURL *)sponsoredMoreURL; +- (NSURL *)sponsoredReviewURL; - (NSURL *)bookingSearchURL; - (NSString *)sponsoredId; - (NSString *)hotelDescription; diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm index 11e4c19626..1719d33971 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm @@ -562,6 +562,20 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; : nil; } +- (NSURL *)sponsoredMoreURL +{ + return m_info.IsSponsored() + ? [NSURL URLWithString:@(m_info.GetSponsoredMoreUrl().c_str())] + : nil; +} + +- (NSURL *)sponsoredReviewURL +{ + return m_info.IsSponsored() + ? [NSURL URLWithString:@(m_info.GetSponsoredReviewUrl().c_str())] + : nil; +} + - (NSURL *)bookingSearchURL { auto const & url = m_info.GetBookingSearchUrl(); diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm b/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm index 28562bd149..028d300ed7 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageManager.mm @@ -488,7 +488,7 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page: [self.ownerViewController openFullPlaceDescriptionWithHtml:htmlString]; } -- (void)book:(BOOL)isDescription +- (void)book { auto data = self.data; if (!data) @@ -509,24 +509,52 @@ void RegisterEventIfPossible(eye::MapObject::Event::Type const type, place_page: } logSponsoredEvent(data, eventName); - if (!isDescription && data.isPartnerAppInstalled) - { - [UIApplication.sharedApplication openURL:data.deepLink options:@{} completionHandler:nil]; - return; - } - - NSURL * url = isDescription ? data.sponsoredDescriptionURL : data.sponsoredURL; + NSURL * url = data.isPartnerAppInstalled ? data.deepLink : data.sponsoredURL; NSAssert(url, @"Sponsored url can't be nil!"); [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; } +- (void)openDescriptionUrl +{ + auto data = self.data; + if (!data) + return; + + logSponsoredEvent(data, kStatPlacePageHotelDetails); + [UIApplication.sharedApplication openURL:data.sponsoredDescriptionURL + options:@{} completionHandler:nil]; +} + +- (void)openMoreUrl +{ + auto data = self.data; + if (!data) + return; + + logSponsoredEvent(data, kStatPlacePageHotelMore); + [UIApplication.sharedApplication openURL:data.sponsoredMoreURL + options:@{} completionHandler:nil]; +} + +- (void)openReviewUrl +{ + auto data = self.data; + if (!data) + return; + + logSponsoredEvent(data, kStatPlacePageHotelReviews); + [UIApplication.sharedApplication openURL:data.sponsoredReviewURL + options:@{} completionHandler:nil]; +} + - (void)searchBookingHotels { auto data = self.data; if (!data) return; - logSponsoredEvent(data, kStatPlacePageHotelSearch); + + logSponsoredEvent(data, kStatPlacePageHotelBook); NSURL * url = data.bookingSearchURL; NSAssert(url, @"Search url can't be nil!"); [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageProtocol.h b/iphone/Maps/UI/PlacePage/MWMPlacePageProtocol.h index f790cc32cf..e7cf1434cb 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageProtocol.h +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageProtocol.h @@ -16,7 +16,7 @@ - (void)removeBookmark; - (void)call; -- (void)book:(BOOL)isDecription; +- (void)book; - (void)searchBookingHotels; - (void)openPartner; diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMPlacePageActionBar.mm b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMPlacePageActionBar.mm index cab5bf4247..4ab8b3dc88 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMPlacePageActionBar.mm +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMPlacePageActionBar.mm @@ -227,7 +227,7 @@ { case EButton::Download: [delegate downloadSelectedArea]; break; case EButton::Opentable: - case EButton::Booking: [delegate book:NO]; break; + case EButton::Booking: [delegate book]; break; case EButton::BookingSearch: [delegate searchBookingHotels]; break; case EButton::Call: [delegate call]; break; case EButton::Bookmark: diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/MWMPlacePageLayout.mm b/iphone/Maps/UI/PlacePage/PlacePageLayout/MWMPlacePageLayout.mm index 1559993b8e..01a611c6bc 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/MWMPlacePageLayout.mm +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/MWMPlacePageLayout.mm @@ -413,7 +413,7 @@ map const kMetaInfoCells = { case ButtonsRows::AddPlace: [delegate addPlace]; break; case ButtonsRows::EditPlace: [delegate editPlace]; break; case ButtonsRows::AddBusiness: [delegate addBusiness]; break; - case ButtonsRows::HotelDescription: [delegate book:NO]; break; + case ButtonsRows::HotelDescription: [delegate openDescriptionUrl]; break; case ButtonsRows::Other: NSAssert(false, @"Incorrect row"); } }]; @@ -483,7 +483,7 @@ map const kMetaInfoCells = { [c configWithTitle:L(@"reviews_on_bookingcom") action:^{ - [delegate book:NO]; + [delegate openReviewUrl]; } isInsetButton:NO]; return c; @@ -510,7 +510,7 @@ map const kMetaInfoCells = { [tableView dequeueReusableCellWithCellClass:cls indexPath:indexPath]); [c configWithTitle:L(@"more_on_bookingcom") action:^{ - [delegate book:NO]; + [delegate openMoreUrl]; ; } isInsetButton:NO]; diff --git a/map/framework.cpp b/map/framework.cpp index 56a7f97bfd..2664e48280 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -885,6 +885,7 @@ void Framework::FillInfoFromFeatureType(FeatureType & ft, place_page::Info & inf info.SetSponsoredUrl(m_bookingApi->GetBookHotelUrl(baseUrl)); info.SetSponsoredDeepLink(m_bookingApi->GetDeepLink(hotelId)); info.SetSponsoredDescriptionUrl(m_bookingApi->GetDescriptionUrl(baseUrl)); + info.SetSponsoredMoreUrl(m_bookingApi->GetMoreUrl(baseUrl)); info.SetSponsoredReviewUrl(m_bookingApi->GetHotelReviewsUrl(hotelId, baseUrl)); if (!m_bookingAvailabilityParams.IsEmpty()) { @@ -900,6 +901,8 @@ void Framework::FillInfoFromFeatureType(FeatureType & ft, place_page::Info & inf bind(&Info::SetSponsoredUrl, &info, _1)); urlSetter(bind(&Info::GetSponsoredDescriptionUrl, &info), bind(&Info::SetSponsoredDescriptionUrl, &info, _1)); + urlSetter(bind(&Info::GetSponsoredMoreUrl, &info), + bind(&Info::SetSponsoredMoreUrl, &info, _1)); urlSetter(bind(&Info::GetSponsoredReviewUrl, &info), bind(&Info::SetSponsoredReviewUrl, &info, _1)); urlSetter(bind(&Info::GetSponsoredDeepLink, &info), diff --git a/map/place_page_info.hpp b/map/place_page_info.hpp index 2893bcf856..04268f9763 100644 --- a/map/place_page_info.hpp +++ b/map/place_page_info.hpp @@ -156,6 +156,8 @@ public: 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 SetSponsoredMoreUrl(std::string const & url) { m_sponsoredMoreUrl = url; } + std::string const & GetSponsoredMoreUrl() const { return m_sponsoredMoreUrl; } void SetSponsoredReviewUrl(std::string const & url) { m_sponsoredReviewUrl = url; } std::string const & GetSponsoredReviewUrl() const { return m_sponsoredReviewUrl; } void SetSponsoredType(SponsoredType type) { m_sponsoredType = type; } @@ -314,6 +316,7 @@ private: std::string m_sponsoredUrl; std::string m_sponsoredDeepLink; std::string m_sponsoredDescriptionUrl; + std::string m_sponsoredMoreUrl; std::string m_sponsoredReviewUrl; /// Booking diff --git a/partners_api/booking_api.cpp b/partners_api/booking_api.cpp index 48258aa7c0..0d85594e9b 100644 --- a/partners_api/booking_api.cpp +++ b/partners_api/booking_api.cpp @@ -5,6 +5,7 @@ #include "platform/platform.hpp" #include "coding/url_encode.hpp" +#include "coding/sha1.hpp" #include "base/get_time.hpp" #include "base/logging.hpp" @@ -393,6 +394,30 @@ string ApplyAvailabilityParamsDeep(string const & url, AvailabilityParams const return url::Make(url, p); } + +string AppendAid(string const & baseUrl) +{ + ASSERT(!baseUrl.empty(), ()); + url::Params p = {{"aid", BOOKING_AFFILIATE_ID}}; + return url::Make(baseUrl, p); +} + +string ApplendLabel(string const & baseUrl, string const & labelSource) +{ + ASSERT(!baseUrl.empty(), ()); + ASSERT(!labelSource.empty(), ()); + auto static const kDeviceIdHash = + coding::SHA1::CalculateForStringFormatted(GetPlatform().UniqueClientId()); + + url::Params const p = {{"label", labelSource + "-" + UrlEncode(kDeviceIdHash)}}; + + return url::Make(baseUrl, p); +} + +string AppendAidAndLabel(string const & baseUrl, string const & labelSource) +{ + return ApplendLabel(AppendAid(baseUrl), labelSource); +} } // namespace namespace booking @@ -436,7 +461,7 @@ bool RawApi::BlockAvailability(BlockParams const & params, string & result) string Api::GetBookHotelUrl(string const & baseUrl) const { ASSERT(!baseUrl.empty(), ()); - return GetDescriptionUrl(baseUrl); + return AppendAidAndLabel(baseUrl, "ppActionButton"); } string Api::GetDeepLink(string const & hotelId) const @@ -452,34 +477,39 @@ string Api::GetDeepLink(string const & hotelId) const string Api::GetDescriptionUrl(string const & baseUrl) const { ASSERT(!baseUrl.empty(), ()); - return baseUrl + string("?aid=") + BOOKING_AFFILIATE_ID; + return AppendAidAndLabel(baseUrl, "ppDetails"); +} + +string Api::GetMoreUrl(string const & baseUrl) const +{ + ASSERT(!baseUrl.empty(), ()); + return AppendAidAndLabel(baseUrl, "ppMoreInfo"); } string Api::GetHotelReviewsUrl(string const & hotelId, string const & baseUrl) const { ASSERT(!baseUrl.empty(), ()); ASSERT(!hotelId.empty(), ()); - ostringstream os; - os << GetDescriptionUrl(baseUrl) << "&tab=4&label=hotel-" << hotelId << "_reviews"; - return os.str(); + + url::Params const p = {{"tab", "4"}}; + return url::Make(AppendAidAndLabel(baseUrl, "ppReviews"), p); } string Api::GetSearchUrl(string const & city, string const & name) const { if (city.empty() || name.empty()) - return ""; + return {}; ostringstream paramStream; paramStream << city << " " << name; auto const urlEncodedParams = UrlEncode(paramStream.str()); - ostringstream resultStream; - if (!urlEncodedParams.empty()) - resultStream << kSearchBaseUrl << "?aid=" << BOOKING_AFFILIATE_ID << ";" << "ss=" - << urlEncodedParams << ";"; + if (urlEncodedParams.empty()) + return {}; - return resultStream.str(); + url::Params p = {{"&ss=", urlEncodedParams}}; + return url::Make(AppendAidAndLabel(kSearchBaseUrl, "ppReviews"), p); } string Api::ApplyAvailabilityParams(string const & url, AvailabilityParams const & params) const diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp index f0c88626dd..f70577a664 100644 --- a/partners_api/booking_api.hpp +++ b/partners_api/booking_api.hpp @@ -135,6 +135,7 @@ 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 GetMoreUrl(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; std::string ApplyAvailabilityParams(std::string const & url,