forked from organicmaps/organicmaps
Locals API. First iteration.
This commit is contained in:
parent
a8428f9ffe
commit
753499146c
8 changed files with 295 additions and 0 deletions
|
@ -552,6 +552,15 @@ cian::Api * Framework::GetCianApi(platform::NetworkPolicy const & policy)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
locals::Api * Framework::GetLocalsApi(platform::NetworkPolicy const & policy)
|
||||
{
|
||||
ASSERT(m_localsApi, ());
|
||||
if (policy.CanUse())
|
||||
return m_localsApi.get();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Framework::ShowNode(storage::TCountryId const & countryId)
|
||||
{
|
||||
StopLocationFollow();
|
||||
|
@ -891,6 +900,8 @@ void Framework::FillInfoFromFeatureType(FeatureType const & ft, place_page::Info
|
|||
info.SetPreviewIsExtended();
|
||||
}
|
||||
|
||||
FillLocalExperts(ft, info);
|
||||
|
||||
auto const mwmInfo = ft.GetID().m_mwmId.GetInfo();
|
||||
bool const isMapVersionEditable = mwmInfo && mwmInfo->m_version.IsEditableMap();
|
||||
bool const canEditOrAdd = featureStatus != osm::Editor::FeatureStatus::Obsolete && CanEditMap() &&
|
||||
|
@ -3423,3 +3434,16 @@ void Framework::InjectViator(place_page::Info & info)
|
|||
},
|
||||
rect, scales::GetUpperScale(), mwmId);
|
||||
}
|
||||
|
||||
void Framework::FillLocalExperts(FeatureType const & ft, place_page::Info & info) const
|
||||
{
|
||||
if (GetDrawScale() > scales::GetUpperWorldScale() ||
|
||||
!ftypes::IsCityChecker::Instance()(ft))
|
||||
{
|
||||
info.SetLocalsStatus(place_page::LocalsStatus::NotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
info.SetLocalsStatus(place_page::LocalsStatus::Available);
|
||||
info.SetLocalsPageUrl(locals::Api::GetLocalsPageUrl());
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include "partners_api/booking_api.hpp"
|
||||
#include "partners_api/cian_api.hpp"
|
||||
#include "partners_api/locals_api.hpp"
|
||||
#include "partners_api/taxi_engine.hpp"
|
||||
#include "partners_api/viator_api.hpp"
|
||||
|
||||
|
@ -177,6 +178,7 @@ protected:
|
|||
unique_ptr<booking::Api> m_bookingApi = make_unique<booking::Api>();
|
||||
unique_ptr<viator::Api> m_viatorApi = make_unique<viator::Api>();
|
||||
unique_ptr<cian::Api> m_cianApi = make_unique<cian::Api>();
|
||||
unique_ptr<locals::Api> m_localsApi = make_unique<locals::Api>();
|
||||
|
||||
df::DrapeApi m_drapeApi;
|
||||
|
||||
|
@ -218,6 +220,7 @@ public:
|
|||
viator::Api * GetViatorApi(platform::NetworkPolicy const & policy);
|
||||
taxi::Engine * GetTaxiEngine(platform::NetworkPolicy const & policy);
|
||||
cian::Api * GetCianApi(platform::NetworkPolicy const & policy);
|
||||
locals::Api * GetLocalsApi(platform::NetworkPolicy const & policy);
|
||||
|
||||
df::DrapeApi & GetDrapeApi() { return m_drapeApi; }
|
||||
|
||||
|
@ -831,4 +834,6 @@ private:
|
|||
|
||||
/// Find feature with viator near point, provided in |info|, and inject viator data into |info|.
|
||||
void InjectViator(place_page::Info & info);
|
||||
|
||||
void FillLocalExperts(FeatureType const & ft, place_page::Info & info) const;
|
||||
};
|
||||
|
|
|
@ -46,6 +46,12 @@ enum class LocalAdsStatus
|
|||
Customer
|
||||
};
|
||||
|
||||
enum class LocalsStatus
|
||||
{
|
||||
NotAvailable,
|
||||
Available
|
||||
};
|
||||
|
||||
class Info : public osm::MapObject
|
||||
{
|
||||
public:
|
||||
|
@ -149,6 +155,12 @@ public:
|
|||
return m_reachableByProviders;
|
||||
}
|
||||
|
||||
/// Local experts
|
||||
void SetLocalsStatus(LocalsStatus status) { m_localsStatus = status; }
|
||||
LocalsStatus GetLocalsStatus() const { return m_localsStatus; }
|
||||
void SetLocalsPageUrl(std::string const & url) { m_localsUrl = url; }
|
||||
std::string const & GetLocalsPageUrl() const { return m_localsUrl; }
|
||||
|
||||
/// Local ads
|
||||
void SetLocalAdsStatus(LocalAdsStatus status) { m_localAdsStatus = status; }
|
||||
LocalAdsStatus GetLocalAdsStatus() const { return m_localAdsStatus; }
|
||||
|
@ -251,5 +263,9 @@ private:
|
|||
|
||||
/// Booking
|
||||
std::string m_bookingSearchUrl;
|
||||
|
||||
/// Local experts
|
||||
std::string m_localsUrl;
|
||||
LocalsStatus m_localsStatus = LocalsStatus::NotAvailable;
|
||||
};
|
||||
} // namespace place_page
|
||||
|
|
|
@ -17,6 +17,8 @@ set(
|
|||
facebook_ads.hpp
|
||||
google_ads.cpp
|
||||
google_ads.hpp
|
||||
locals_api.cpp
|
||||
locals_api.hpp
|
||||
mopub_ads.cpp
|
||||
mopub_ads.hpp
|
||||
opentable_api.cpp
|
||||
|
|
174
partners_api/locals_api.cpp
Normal file
174
partners_api/locals_api.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include "partners_api/locals_api.hpp"
|
||||
|
||||
#include "platform/http_client.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/preferred_languages.hpp"
|
||||
|
||||
#include "coding/multilang_utf8_string.hpp"
|
||||
#include "coding/url_encode.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include "3party/jansson/myjansson.hpp"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace locals;
|
||||
|
||||
bool CheckJsonArray(json_t const * data)
|
||||
{
|
||||
if (data == nullptr)
|
||||
return false;
|
||||
return json_is_array(data) && json_array_size(data) > 0;
|
||||
}
|
||||
|
||||
void ParseError(std::string const & src, ErrorCode & errorCode, std::string & message)
|
||||
{
|
||||
message.clear();
|
||||
my::Json root(src.c_str());
|
||||
int code = 0;
|
||||
FromJSONObject(root.get(), "code", code);
|
||||
FromJSONObject(root.get(), "message", message);
|
||||
// TODO(darina): Process real error codes.
|
||||
errorCode = code > 0 ? ErrorCode::NoLocals : ErrorCode::RemoteError;
|
||||
}
|
||||
|
||||
void ParseLocals(std::string const & src, std::vector<LocalExpert> & locals,
|
||||
bool & hasPrevious, bool & hasNext)
|
||||
{
|
||||
locals.clear();
|
||||
my::Json root(src.c_str());
|
||||
auto previousField = my::GetJSONOptionalField(root.get(), "previous");
|
||||
auto nextField = my::GetJSONOptionalField(root.get(), "next");
|
||||
hasPrevious = json_is_number(previousField);
|
||||
hasNext = json_is_number(nextField);
|
||||
auto const results = json_object_get(root.get(), "results");
|
||||
if (!CheckJsonArray(results))
|
||||
return;
|
||||
auto const dataSize = json_array_size(results);
|
||||
for (size_t i = 0; i < dataSize; ++i)
|
||||
{
|
||||
LocalExpert local;
|
||||
auto const item = json_array_get(results, i);
|
||||
FromJSONObject(item, "id", local.m_id);
|
||||
FromJSONObject(item, "motto", local.m_motto);
|
||||
FromJSONObject(item, "link", local.m_pageUrl);
|
||||
FromJSONObject(item, "photo", local.m_photoUrl);
|
||||
FromJSONObject(item, "name", local.m_name);
|
||||
FromJSONObject(item, "country", local.m_country);
|
||||
FromJSONObject(item, "city", local.m_city);
|
||||
FromJSONObject(item, "rating", local.m_rating);
|
||||
FromJSONObject(item, "reviews", local.m_reviewCount);
|
||||
FromJSONObject(item, "price_per_hour", local.m_pricePerHour);
|
||||
FromJSONObject(item, "currency", local.m_currency);
|
||||
FromJSONObject(item, "about_me", local.m_aboutExpert);
|
||||
FromJSONObject(item, "i_will_show_you", local.m_offerDescription);
|
||||
locals.push_back(move(local));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace locals
|
||||
{
|
||||
bool RawApi::Get(double lat, double lon, std::string const & lang, size_t resultsOnPage, size_t pageNumber,
|
||||
std::string & result)
|
||||
{
|
||||
result.clear();
|
||||
std::ostringstream ostream;
|
||||
ostream << LOCALS_API_URL << "/search?api_key=" << LOCALS_API_KEY
|
||||
<< "&lat=" << lat << "&lon=" << lon
|
||||
<< "&limit=" << resultsOnPage << "&page=" << pageNumber;
|
||||
if (!lang.empty())
|
||||
ostream << "&lang=" << lang;
|
||||
|
||||
platform::HttpClient request(ostream.str());
|
||||
request.SetHttpMethod("GET");
|
||||
if (request.RunHttpRequest() && request.ErrorCode() == 200)
|
||||
{
|
||||
result = request.ServerResponse();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Api::GetLocalsPageUrl()
|
||||
{
|
||||
return LOCALS_PAGE_URL;
|
||||
}
|
||||
|
||||
uint64_t Api::GetLocals(double lat, double lon, std::string const & lang,
|
||||
size_t resultsOnPage, size_t pageNumber,
|
||||
LocalsSuccessCallback const & successFn,
|
||||
LocalsErrorCallback const & errorFn)
|
||||
{
|
||||
uint64_t id = ++m_requestId;
|
||||
GetPlatform().RunOnNetworkThread([id, lat, lon, lang,
|
||||
resultsOnPage, pageNumber, successFn, errorFn]()
|
||||
{
|
||||
std::string result;
|
||||
if (!RawApi::Get(lat, lon, lang, resultsOnPage, pageNumber, result))
|
||||
{
|
||||
try
|
||||
{
|
||||
ErrorCode errorCode;
|
||||
std::string errorMessage;
|
||||
ParseError(result, errorCode, errorMessage);
|
||||
LOG(LWARNING, ("Locals request failed:", errorCode, errorMessage));
|
||||
return errorFn(id, errorCode, errorMessage);
|
||||
}
|
||||
catch (my::Json::Exception const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Unknown error:", e.Msg()));
|
||||
return errorFn(id, ErrorCode::UnknownError, "Unknown error: " + e.Msg());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<LocalExpert> locals;
|
||||
bool hasPreviousPage = false;
|
||||
bool hasNextPage = false;
|
||||
try
|
||||
{
|
||||
ParseLocals(result, locals, hasPreviousPage, hasNextPage);
|
||||
}
|
||||
catch (my::Json::Exception const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Locals response parsing failed:", e.Msg()));
|
||||
errorFn(id, ErrorCode::UnknownError, "Response parsing failed: " + e.Msg());
|
||||
}
|
||||
|
||||
successFn(id, locals, pageNumber, resultsOnPage, hasPreviousPage, hasNextPage);
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string DebugPrint(ErrorCode code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case ErrorCode::NoLocals: return "NoLocals";
|
||||
case ErrorCode::RemoteError: return "RemoteError";
|
||||
case ErrorCode::UnknownError: return "UnknownError";
|
||||
}
|
||||
return "Unknown error code";
|
||||
}
|
||||
|
||||
std::string DebugPrint(LocalExpert const & localExpert)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "id: " << localExpert.m_id << std::endl
|
||||
<< "name: " << localExpert.m_name << std::endl
|
||||
<< "about: " << localExpert.m_aboutExpert << std::endl
|
||||
<< "city: " << localExpert.m_city << std::endl
|
||||
<< "country: " << localExpert.m_country << std::endl
|
||||
<< "currency: " << localExpert.m_currency << std::endl
|
||||
<< "pageUrl: " << localExpert.m_pageUrl << std::endl
|
||||
<< "photoUrl: " << localExpert.m_photoUrl << std::endl
|
||||
<< "description: " << localExpert.m_offerDescription << std::endl
|
||||
<< "motto: " << localExpert.m_motto << std::endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace locals
|
64
partners_api/locals_api.hpp
Normal file
64
partners_api/locals_api.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/safe_callback.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define STAGE_LOCALS_SERVER
|
||||
|
||||
namespace locals
|
||||
{
|
||||
class RawApi
|
||||
{
|
||||
public:
|
||||
static bool Get(double lat, double lon, std::string const & lang,
|
||||
size_t resultsOnPage, size_t pageNumber, std::string & result);
|
||||
};
|
||||
|
||||
enum class ErrorCode
|
||||
{
|
||||
NoLocals,
|
||||
RemoteError,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
struct LocalExpert
|
||||
{
|
||||
size_t m_id;
|
||||
std::string m_name;
|
||||
std::string m_country;
|
||||
std::string m_city;
|
||||
double m_rating;
|
||||
size_t m_reviewCount;
|
||||
double m_pricePerHour;
|
||||
std::string m_currency;
|
||||
std::string m_motto;
|
||||
std::string m_aboutExpert;
|
||||
std::string m_offerDescription;
|
||||
std::string m_pageUrl;
|
||||
std::string m_photoUrl;
|
||||
};
|
||||
|
||||
using LocalsSuccessCallback = platform::SafeCallback<void(uint64_t id, std::vector<LocalExpert> const & locals,
|
||||
size_t pageNumber, size_t countPerPage,
|
||||
bool hasPreviousPage, bool hasNextPage)>;
|
||||
using LocalsErrorCallback = platform::SafeCallback<void(uint64_t id, ErrorCode errorCode,
|
||||
std::string const & errorMessage)>;
|
||||
|
||||
class Api
|
||||
{
|
||||
public:
|
||||
static std::string GetLocalsPageUrl();
|
||||
uint64_t GetLocals(double lat, double lon, std::string const & lang,
|
||||
size_t resultsOnPage, size_t pageNumber,
|
||||
LocalsSuccessCallback const & successFn,
|
||||
LocalsErrorCallback const & errorFn);
|
||||
private:
|
||||
// Id for currently processed request.
|
||||
uint64_t m_requestId = 0;
|
||||
};
|
||||
|
||||
std::string DebugPrint(ErrorCode code);
|
||||
std::string DebugPrint(LocalExpert const & localExpert);
|
||||
} // namespace locals
|
|
@ -15,6 +15,7 @@ SOURCES += \
|
|||
cian_api.cpp \
|
||||
facebook_ads.cpp \
|
||||
google_ads.cpp \
|
||||
locals_api.cpp \
|
||||
mopub_ads.cpp \
|
||||
opentable_api.cpp \
|
||||
rb_ads.cpp \
|
||||
|
@ -33,6 +34,7 @@ HEADERS += \
|
|||
cian_api.hpp \
|
||||
facebook_ads.hpp \
|
||||
google_ads.hpp \
|
||||
locals_api.hpp \
|
||||
mopub_ads.hpp \
|
||||
opentable_api.hpp \
|
||||
rb_ads.hpp \
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
3DFEBF9F1EFBFC1500317D5C /* yandex_api.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF991EFBFC1500317D5C /* yandex_api.hpp */; };
|
||||
3DFEBFA31EFBFC2300317D5C /* taxi_engine_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEBFA01EFBFC2300317D5C /* taxi_engine_tests.cpp */; };
|
||||
3DFEBFA41EFBFC2300317D5C /* yandex_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEBFA11EFBFC2300317D5C /* yandex_tests.cpp */; };
|
||||
BB1956E61F543D7C003ECE6C /* locals_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BB1956E41F543D7B003ECE6C /* locals_api.cpp */; };
|
||||
BB1956E71F543D7C003ECE6C /* locals_api.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BB1956E51F543D7C003ECE6C /* locals_api.hpp */; };
|
||||
F67E75251DB8F06F00D6741F /* opentable_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67E75231DB8F06F00D6741F /* opentable_api.cpp */; };
|
||||
F67E75261DB8F06F00D6741F /* opentable_api.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F67E75241DB8F06F00D6741F /* opentable_api.hpp */; };
|
||||
F6B536401DA520E40067EEA5 /* booking_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6B5363C1DA520E40067EEA5 /* booking_api.cpp */; };
|
||||
|
@ -107,6 +109,8 @@
|
|||
3DFEBF991EFBFC1500317D5C /* yandex_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = yandex_api.hpp; sourceTree = "<group>"; };
|
||||
3DFEBFA01EFBFC2300317D5C /* taxi_engine_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = taxi_engine_tests.cpp; sourceTree = "<group>"; };
|
||||
3DFEBFA11EFBFC2300317D5C /* yandex_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = yandex_tests.cpp; sourceTree = "<group>"; };
|
||||
BB1956E41F543D7B003ECE6C /* locals_api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = locals_api.cpp; sourceTree = "<group>"; };
|
||||
BB1956E51F543D7C003ECE6C /* locals_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locals_api.hpp; sourceTree = "<group>"; };
|
||||
F67E75231DB8F06F00D6741F /* opentable_api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opentable_api.cpp; sourceTree = "<group>"; };
|
||||
F67E75241DB8F06F00D6741F /* opentable_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = opentable_api.hpp; sourceTree = "<group>"; };
|
||||
F6B536341DA5209F0067EEA5 /* libpartners_api.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpartners_api.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -178,6 +182,8 @@
|
|||
F6B5363B1DA520B20067EEA5 /* partners_api */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB1956E41F543D7B003ECE6C /* locals_api.cpp */,
|
||||
BB1956E51F543D7C003ECE6C /* locals_api.hpp */,
|
||||
3D47B2B01F14FA14000828D2 /* utils.hpp */,
|
||||
3D47B2AA1F14BE89000828D2 /* cian_api.cpp */,
|
||||
3D47B2AB1F14BE89000828D2 /* cian_api.hpp */,
|
||||
|
@ -288,6 +294,7 @@
|
|||
3DFEBF9C1EFBFC1500317D5C /* taxi_engine.hpp in Headers */,
|
||||
F6B536431DA520E40067EEA5 /* uber_api.hpp in Headers */,
|
||||
3DBC1C551E4B14920016897F /* facebook_ads.hpp in Headers */,
|
||||
BB1956E71F543D7C003ECE6C /* locals_api.hpp in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -398,6 +405,7 @@
|
|||
346E88981E9D087400D4CE9B /* ads_engine.cpp in Sources */,
|
||||
3D47B29B1F054C89000828D2 /* taxi_countries.cpp in Sources */,
|
||||
F67E75251DB8F06F00D6741F /* opentable_api.cpp in Sources */,
|
||||
BB1956E61F543D7C003ECE6C /* locals_api.cpp in Sources */,
|
||||
3DFEBFA31EFBFC2300317D5C /* taxi_engine_tests.cpp in Sources */,
|
||||
F6B536401DA520E40067EEA5 /* booking_api.cpp in Sources */,
|
||||
3D47B29A1F054C89000828D2 /* taxi_base.cpp in Sources */,
|
||||
|
|
Loading…
Add table
Reference in a new issue