forked from organicmaps/organicmaps
[core] freenow taxi is added
This commit is contained in:
parent
4ae24bb3e3
commit
99c405f19d
14 changed files with 764 additions and 6 deletions
191
data/taxi_places/freenow.json
Normal file
191
data/taxi_places/freenow.json
Normal file
|
@ -0,0 +1,191 @@
|
|||
{
|
||||
"disabled": {
|
||||
"countries": [],
|
||||
"mwms": []
|
||||
},
|
||||
"enabled": {
|
||||
"countries": [
|
||||
{
|
||||
"cities": [
|
||||
"Arezzo",
|
||||
"Bologna",
|
||||
"Cagliari",
|
||||
"Milan",
|
||||
"Naples",
|
||||
"Palermo",
|
||||
"Rome",
|
||||
"Turin"
|
||||
],
|
||||
"id": "Italy"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Faro",
|
||||
"Lisbon",
|
||||
"Porto"
|
||||
],
|
||||
"id": "Portugal"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Gdansk",
|
||||
"Katowice",
|
||||
"Krakow",
|
||||
"\u0141\u00f3d\u017a",
|
||||
"Pozna\u0144",
|
||||
"Warsaw",
|
||||
"Wroc\u0142aw"
|
||||
],
|
||||
"id": "Poland"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Stockholm"
|
||||
],
|
||||
"id": "Sweden"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Graz",
|
||||
"Innsbruck",
|
||||
"Salzburg",
|
||||
"Vienna"
|
||||
],
|
||||
"id": "Austria"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Brighton",
|
||||
"Edinburgh",
|
||||
"Glasgow",
|
||||
"London",
|
||||
"Manchester",
|
||||
"City of Nottingham",
|
||||
"Oxford",
|
||||
"Reading"
|
||||
],
|
||||
"id": "Great Britain"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Aachen",
|
||||
"Aschaffenburg",
|
||||
"Augsburg",
|
||||
"Berlin",
|
||||
"B\u00f6blingen",
|
||||
"Bochum",
|
||||
"Bonn",
|
||||
"Bottrop",
|
||||
"Brunswick",
|
||||
"Bremen",
|
||||
"Dachau",
|
||||
"Darmstadt",
|
||||
"Dortmund",
|
||||
"Dresden",
|
||||
"Dusseldorf",
|
||||
"Duisburg",
|
||||
"Ebersberg",
|
||||
"Emmendingen (Kernstadt)",
|
||||
"Erding",
|
||||
"Erfurt",
|
||||
"Erlangen",
|
||||
"Essen",
|
||||
"Esslingen am Neckar",
|
||||
"Flensburg",
|
||||
"Frankfurt",
|
||||
"Freiburg im Breisgau",
|
||||
"F\u00fcrstenfeldbruck",
|
||||
"F\u00fcrth",
|
||||
"Gelsenkirchen",
|
||||
"Gladbeck",
|
||||
"G\u00f6ppingen",
|
||||
"G\u00fctersloh",
|
||||
"Hagen",
|
||||
"Halle (Saale)",
|
||||
"Hamburg",
|
||||
"Hamm",
|
||||
"Hanau",
|
||||
"Hanover",
|
||||
"Heidelberg",
|
||||
"Heilbronn",
|
||||
"Herne",
|
||||
"Herzogenaurach",
|
||||
"Hildesheim",
|
||||
"Ingolstadt",
|
||||
"Kaiserslautern",
|
||||
"Karlsruhe",
|
||||
"Kassel",
|
||||
"Kiel",
|
||||
"Koblenz",
|
||||
"K\u00f6ln",
|
||||
"Krefeld",
|
||||
"Landsberg am Lech",
|
||||
"Leipzig",
|
||||
"Leverkusen",
|
||||
"L\u00fcbeck",
|
||||
"Ludwigsburg",
|
||||
"Ludwigshafen am Rhein",
|
||||
"Magdeburg",
|
||||
"Mainz",
|
||||
"Mannheim",
|
||||
"Mettmann",
|
||||
"M\u00f6nchengladbach",
|
||||
"Munich",
|
||||
"M\u00fclheim an der Ruhr",
|
||||
"M\u00fcnster",
|
||||
"Neuss",
|
||||
"Nuremberg",
|
||||
"Oberhausen",
|
||||
"Offenbach am Main",
|
||||
"Osnabr\u00fcck",
|
||||
"Paderborn",
|
||||
"Potsdam",
|
||||
"Rastatt",
|
||||
"Baden-Baden",
|
||||
"Regensburg",
|
||||
"Reutlingen",
|
||||
"Rosenheim",
|
||||
"Rostock",
|
||||
"Saarbr\u00fccken",
|
||||
"Solingen",
|
||||
"Starnberg",
|
||||
"Steinfurt",
|
||||
"Stuttgart",
|
||||
"T\u00fcbingen",
|
||||
"Neu-Ulm",
|
||||
"Wetzlar",
|
||||
"Wiesbaden",
|
||||
"Wolfsburg",
|
||||
"Wuppertal"
|
||||
],
|
||||
"id": "Germany"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Cork",
|
||||
"Dublin",
|
||||
"Galway",
|
||||
"Limerick",
|
||||
"Navan"
|
||||
],
|
||||
"id": "Ireland"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Zurich"
|
||||
],
|
||||
"id": "Switzerland"
|
||||
},
|
||||
{
|
||||
"cities": [
|
||||
"Barcelona",
|
||||
"Madrid",
|
||||
"Seville",
|
||||
"Valencia"
|
||||
],
|
||||
"id": "Spain"
|
||||
}
|
||||
],
|
||||
"mwms": []
|
||||
}
|
||||
}
|
|
@ -20,6 +20,8 @@ set(
|
|||
downloader_promo.hpp
|
||||
facebook_ads.cpp
|
||||
facebook_ads.hpp
|
||||
freenow_api.cpp
|
||||
freenow_api.hpp
|
||||
google_ads.cpp
|
||||
google_ads.hpp
|
||||
locals_api.cpp
|
||||
|
|
219
partners_api/freenow_api.cpp
Normal file
219
partners_api/freenow_api.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include "partners_api/freenow_api.hpp"
|
||||
|
||||
#include "platform/http_client.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "platform/preferred_languages.hpp"
|
||||
|
||||
#include "coding/url.hpp"
|
||||
|
||||
#include "geometry/latlon.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include "std/target_os.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "3party/jansson/myjansson.hpp"
|
||||
|
||||
#include "private.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto const kTimeoutSec = 15;
|
||||
|
||||
bool CheckResponse(json_t const * answer)
|
||||
{
|
||||
if (answer == nullptr)
|
||||
return false;
|
||||
|
||||
if (!json_is_array(answer))
|
||||
return false;
|
||||
|
||||
if (json_array_size(answer) <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace taxi
|
||||
{
|
||||
namespace freenow
|
||||
{
|
||||
std::string const kTaxiEndpoint = "https://api.live.free-now.com/publicapigatewayservice/v1";
|
||||
|
||||
bool RawApi::GetAccessToken(std::string & result, std::string const & baseUrl /* = kTaxiEndpoint */)
|
||||
{
|
||||
platform::HttpClient request(url::Join(baseUrl, "oauth/token"));
|
||||
request.SetTimeout(kTimeoutSec);
|
||||
request.SetBodyData("grant_type=client_credentials", "application/x-www-form-urlencoded");
|
||||
request.SetUserAndPassword(FREENOW_CLIENT_ID, FREENOW_CLIENT_SECRET);
|
||||
|
||||
return request.RunHttpRequest(result);
|
||||
}
|
||||
|
||||
bool RawApi::GetServiceTypes(ms::LatLon const & from, ms::LatLon const & to,
|
||||
std::string const & token, std::string & result,
|
||||
const std::string & baseUrl /* = kTaxiEndpoint */)
|
||||
{
|
||||
std::ostringstream url;
|
||||
url << std::fixed << std::setprecision(6) << baseUrl << "/service-types?pickupLatitude="
|
||||
<< from.m_lat << "&pickupLongitude=" << from.m_lon << "&destinationLatitude=" << to.m_lat
|
||||
<< "&destinationLongitude=" << to.m_lon;
|
||||
|
||||
platform::HttpClient request(url.str());
|
||||
request.SetTimeout(kTimeoutSec);
|
||||
request.SetRawHeader("Authorization", "Bearer " + token);
|
||||
request.SetRawHeader("Accept", "application/json");
|
||||
request.SetRawHeader("Accept-Language", languages::GetCurrentOrig());
|
||||
|
||||
return request.RunHttpRequest(result);
|
||||
}
|
||||
|
||||
SafeToken::SafeToken(Token const & token)
|
||||
: m_token(token)
|
||||
{
|
||||
}
|
||||
|
||||
void SafeToken::Set(Token const & token)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_token = token;
|
||||
}
|
||||
|
||||
SafeToken::Token SafeToken::Get() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
return m_token;
|
||||
}
|
||||
|
||||
/// Requests list of available products from Freenow.
|
||||
void Api::GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to,
|
||||
ProductsCallback const & successFn,
|
||||
ErrorProviderCallback const & errorFn)
|
||||
{
|
||||
ASSERT(successFn, ());
|
||||
ASSERT(errorFn, ());
|
||||
|
||||
// TODO(a): Add ErrorCode::FarDistance and provide this error code.
|
||||
if (!IsDistanceSupported(from, to))
|
||||
{
|
||||
errorFn(ErrorCode::NoProducts);
|
||||
return;
|
||||
}
|
||||
|
||||
static_assert(std::is_const<decltype(m_baseUrl)>::value, "");
|
||||
|
||||
GetPlatform().RunTask(Platform::Thread::Network, [this, from, to, successFn, errorFn]()
|
||||
{
|
||||
auto token = m_accessToken.Get();
|
||||
if (token.m_expiredTime <= std::chrono::steady_clock::now() - std::chrono::seconds(kTimeoutSec))
|
||||
{
|
||||
std::string tokenSource;
|
||||
if (!RawApi::GetAccessToken(tokenSource, m_baseUrl))
|
||||
{
|
||||
errorFn(ErrorCode::RemoteError);
|
||||
return;
|
||||
}
|
||||
|
||||
token = MakeTokenFromJson(tokenSource);
|
||||
m_accessToken.Set(token);
|
||||
}
|
||||
|
||||
std::string httpResult;
|
||||
if (!RawApi::GetServiceTypes(from, to, token.m_token, httpResult, m_baseUrl))
|
||||
{
|
||||
errorFn(ErrorCode::RemoteError);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Product> products;
|
||||
try
|
||||
{
|
||||
products = MakeProductsFromJson(httpResult);
|
||||
}
|
||||
catch (base::Json::Exception const & e)
|
||||
{
|
||||
LOG(LERROR, (e.Msg()));
|
||||
products.clear();
|
||||
}
|
||||
|
||||
if (products.empty())
|
||||
errorFn(ErrorCode::NoProducts);
|
||||
else
|
||||
successFn(products);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns link which allows you to launch the Freenow app.
|
||||
RideRequestLinks Api::GetRideRequestLinks(std::string const & productId, ms::LatLon const & from,
|
||||
ms::LatLon const & to) const
|
||||
{
|
||||
std::ostringstream deepLink;
|
||||
deepLink << std::fixed << std::setprecision(6)
|
||||
<< "mytaxi://de.mytaxi.passenger/order?pickup_coordinate=" << from.m_lat << ","
|
||||
<< from.m_lon << "&destination_coordinate=" << to.m_lat << "," << to.m_lon;
|
||||
|
||||
std::string const universalLink = "https://mytaxi.onelink.me/HySP?pid=maps.me&c=in-app-referral-"
|
||||
"link_030320_my_pa_in_0_gl_gl_-_mx_mo_co_mx_af_-_ge_-_-_-_-_-"
|
||||
"&is_retargeting=true&af_dp=mytaxi%3A%2F%2Fde.mytaxi.passenger";
|
||||
return {deepLink.str(), universalLink};
|
||||
|
||||
}
|
||||
|
||||
std::vector<taxi::Product> MakeProductsFromJson(std::string const & src)
|
||||
{
|
||||
std::vector<taxi::Product> products;
|
||||
|
||||
base::Json root(src.c_str());
|
||||
auto const serviceTypesArray = json_object_get(root.get(), "serviceTypes");
|
||||
if (!CheckResponse(serviceTypesArray))
|
||||
return {};
|
||||
|
||||
auto const count = json_array_size(serviceTypesArray);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
taxi::Product product;
|
||||
uint64_t time = 0;
|
||||
uint64_t price = 0;
|
||||
auto const item = json_array_get(serviceTypesArray, i);
|
||||
|
||||
FromJSONObjectOptionalField(item, "id", product.m_productId);
|
||||
FromJSONObjectOptionalField(item, "displayName", product.m_name);
|
||||
|
||||
auto const eta = json_object_get(item, "eta");
|
||||
FromJSONObjectOptionalField(eta, "value", time);
|
||||
product.m_time = strings::to_string(time);
|
||||
|
||||
auto const fare = json_object_get(item, "fare");
|
||||
FromJSONObjectOptionalField(fare, "displayValue", product.m_price);
|
||||
FromJSONObjectOptionalField(fare, "currencyCode", product.m_currency);
|
||||
|
||||
if (product.m_name.empty() || product.m_time.empty() || product.m_price.empty())
|
||||
continue;
|
||||
|
||||
products.push_back(std::move(product));
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
SafeToken::Token MakeTokenFromJson(std::string const & src)
|
||||
{
|
||||
SafeToken::Token result;
|
||||
base::Json root(src.c_str());
|
||||
FromJSONObject(root.get(), "access_token", result.m_token);
|
||||
uint64_t expiresInSeconds = 0;
|
||||
FromJSONObject(root.get(), "expires_in", expiresInSeconds);
|
||||
result.m_expiredTime = std::chrono::steady_clock::now() + std::chrono::seconds(expiresInSeconds);
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace freenow
|
||||
} // namespace taxi
|
70
partners_api/freenow_api.hpp
Normal file
70
partners_api/freenow_api.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include "partners_api/taxi_base.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace ms
|
||||
{
|
||||
class LatLon;
|
||||
}
|
||||
|
||||
namespace taxi
|
||||
{
|
||||
namespace freenow
|
||||
{
|
||||
extern std::string const kTaxiEndpoint;
|
||||
/// "Free now" api wrapper based on synchronous http requests.
|
||||
class RawApi
|
||||
{
|
||||
public:
|
||||
static bool GetAccessToken(std::string & result, std::string const & url = kTaxiEndpoint);
|
||||
static bool GetServiceTypes(ms::LatLon const & from, ms::LatLon const & to,
|
||||
std::string const & token, std::string & result,
|
||||
std::string const & url = kTaxiEndpoint);
|
||||
};
|
||||
|
||||
class SafeToken
|
||||
{
|
||||
public:
|
||||
struct Token
|
||||
{
|
||||
std::string m_token;
|
||||
std::chrono::steady_clock::time_point m_expiredTime;
|
||||
};
|
||||
|
||||
SafeToken() = default;
|
||||
void Set(Token const & token);
|
||||
Token Get() const;
|
||||
|
||||
private:
|
||||
SafeToken(Token const & token);
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
Token m_token;
|
||||
};
|
||||
|
||||
/// Class which used for making products from http requests results.
|
||||
class Api : public ApiBase
|
||||
{
|
||||
public:
|
||||
explicit Api(std::string const & baseUrl = kTaxiEndpoint) : ApiBase(baseUrl) {}
|
||||
// ApiBase overrides:
|
||||
/// Requests list of available products from "Free now".
|
||||
void GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to,
|
||||
ProductsCallback const & successFn,
|
||||
ErrorProviderCallback const & errorFn) override;
|
||||
|
||||
/// Returns link which allows you to launch the "Free now" app.
|
||||
RideRequestLinks GetRideRequestLinks(std::string const & productId, ms::LatLon const & from,
|
||||
ms::LatLon const & to) const override;
|
||||
|
||||
private:
|
||||
SafeToken m_accessToken;
|
||||
};
|
||||
|
||||
SafeToken::Token MakeTokenFromJson(std::string const & src);
|
||||
std::vector<taxi::Product> MakeProductsFromJson(std::string const & src);
|
||||
} // namespace freenow
|
||||
} // namespace taxi
|
|
@ -7,8 +7,10 @@ set(
|
|||
ads_engine_tests.cpp
|
||||
booking_tests.cpp
|
||||
facebook_tests.cpp
|
||||
freenow_tests.cpp
|
||||
google_tests.cpp
|
||||
maxim_tests.cpp
|
||||
# Maxim taxi project is disabled.
|
||||
# maxim_tests.cpp
|
||||
# Megafon project is disabled until the contract is renewed or extended.
|
||||
# megafon_countries_tests.cpp
|
||||
mopub_tests.cpp
|
||||
|
@ -17,7 +19,8 @@ set(
|
|||
rutaxi_tests.cpp
|
||||
taxi_engine_tests.cpp
|
||||
taxi_places_tests.cpp
|
||||
uber_tests.cpp
|
||||
# Uber taxi project is disabled.
|
||||
# uber_tests.cpp
|
||||
yandex_tests.cpp
|
||||
)
|
||||
|
||||
|
|
150
partners_api/partners_api_tests/freenow_tests.cpp
Normal file
150
partners_api/partners_api_tests/freenow_tests.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "partners_api/freenow_api.hpp"
|
||||
|
||||
#include "geometry/latlon.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
using Runner = Platform::ThreadRunner;
|
||||
|
||||
std::string const kTokenResponse = R"(
|
||||
{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV",
|
||||
"token_type": "bearer",
|
||||
"expires_in": 600,
|
||||
"scope": "service-types"
|
||||
})";
|
||||
|
||||
std::string const kServiceTypesResponse = R"(
|
||||
{
|
||||
"serviceTypes": [
|
||||
{
|
||||
"id": "TAXI",
|
||||
"type": "TAXI",
|
||||
"displayName": "Taxi",
|
||||
"eta": {
|
||||
"value": 0,
|
||||
"displayValue": "0 Minutes"
|
||||
},
|
||||
"fare": {
|
||||
"type": "FIXED",
|
||||
"value": 5000,
|
||||
"currencyCode": "GBP",
|
||||
"displayValue": "5000GBP"
|
||||
},
|
||||
"availablePaymentMethodTypes": [
|
||||
"BUSINESS_ACCOUNT",
|
||||
"CREDIT_CARD",
|
||||
"PAYPAL",
|
||||
"CASH"
|
||||
],
|
||||
"seats": {
|
||||
"max": 4,
|
||||
"values": [],
|
||||
"displayValue": "4"
|
||||
},
|
||||
"availableBookingOptions": [
|
||||
{
|
||||
"name": "COMMENT",
|
||||
"displayName": "COMMENT",
|
||||
"type": "TEXT"
|
||||
},
|
||||
{
|
||||
"name": "MERCEDES",
|
||||
"displayName": "MERCEDES",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "FAVORITE_DRIVER",
|
||||
"displayName": "FAVORITE_DRIVER",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "FIVE_STARS",
|
||||
"displayName": "FIVE_STARS",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "SMALL_ANIMAL",
|
||||
"displayName": "SMALL_ANIMAL",
|
||||
"type": "BOOLEAN"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
UNIT_TEST(Freenow_GetAccessToken)
|
||||
{
|
||||
ms::LatLon const from(55.796918, 37.537859);
|
||||
ms::LatLon const to(55.758213, 37.616093);
|
||||
std::string result;
|
||||
|
||||
taxi::freenow::RawApi::GetAccessToken(result);
|
||||
TEST(!result.empty(), ());
|
||||
|
||||
auto const token = taxi::freenow::MakeTokenFromJson(result);
|
||||
TEST(!token.m_token.empty(), ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Freenow_MakeTokenFromJson)
|
||||
{
|
||||
auto const token = taxi::freenow::MakeTokenFromJson(kTokenResponse);
|
||||
TEST(!token.m_token.empty(), ());
|
||||
TEST_NOT_EQUAL(token.m_expiredTime.time_since_epoch().count(), 0, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(Freenow_MakeProductsFromJson)
|
||||
{
|
||||
auto const products = taxi::freenow::MakeProductsFromJson(kServiceTypesResponse);
|
||||
TEST_EQUAL(products.size(), 1, ());
|
||||
TEST_EQUAL(products.back().m_name, "Taxi", ());
|
||||
TEST_EQUAL(products.back().m_time, "0", ());
|
||||
TEST_EQUAL(products.back().m_price, "5000GBP", ());
|
||||
TEST_EQUAL(products.back().m_currency, "GBP", ());
|
||||
}
|
||||
|
||||
UNIT_CLASS_TEST(Runner, Freenow_GetAvailableProducts)
|
||||
{
|
||||
taxi::freenow::Api api("http://localhost:34568/partners");
|
||||
ms::LatLon const from(55.796918, 37.537859);
|
||||
ms::LatLon const to(55.758213, 37.616093);
|
||||
|
||||
std::vector<taxi::Product> resultProducts;
|
||||
|
||||
api.GetAvailableProducts(from, to,
|
||||
[&resultProducts](std::vector<taxi::Product> const & products) {
|
||||
resultProducts = products;
|
||||
testing::Notify();
|
||||
},
|
||||
[](taxi::ErrorCode const code) {
|
||||
TEST(false, (code));
|
||||
});
|
||||
|
||||
testing::Wait();
|
||||
|
||||
TEST(!resultProducts.empty(), ());
|
||||
|
||||
taxi::ErrorCode errorCode = taxi::ErrorCode::RemoteError;
|
||||
ms::LatLon const farPos(56.838197, 35.908507);
|
||||
api.GetAvailableProducts(from, farPos,
|
||||
[](std::vector<taxi::Product> const & products) {
|
||||
TEST(false, ());
|
||||
},
|
||||
[&errorCode](taxi::ErrorCode const code) {
|
||||
errorCode = code;
|
||||
testing::Notify();
|
||||
});
|
||||
|
||||
testing::Wait();
|
||||
|
||||
TEST_EQUAL(errorCode, taxi::ErrorCode::NoProducts, ());
|
||||
}
|
||||
} // namespace
|
|
@ -1,5 +1,6 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "partners_api/freenow_api.hpp"
|
||||
#include "partners_api/maxim_api.hpp"
|
||||
#include "partners_api/rutaxi_api.hpp"
|
||||
#include "partners_api/taxi_engine.hpp"
|
||||
|
@ -97,6 +98,18 @@ public:
|
|||
storage::CountryId GetMwmId(m2::PointD const & point) override { return {}; }
|
||||
};
|
||||
|
||||
class IrelandDublinDelegate : public taxi::Delegate
|
||||
{
|
||||
public:
|
||||
storage::CountriesVec GetCountryIds(m2::PointD const & point) override
|
||||
{
|
||||
return {"Ireland"};
|
||||
}
|
||||
|
||||
std::string GetCityName(m2::PointD const & point) override { return "Dublin"; }
|
||||
storage::CountryId GetMwmId(m2::PointD const & point) override { return {}; }
|
||||
};
|
||||
|
||||
std::vector<taxi::Product> GetUberSynchronous(ms::LatLon const & from, ms::LatLon const & to,
|
||||
std::string const & url)
|
||||
{
|
||||
|
@ -169,6 +182,15 @@ std::vector<taxi::Product> GetRutaxiSynchronous(ms::LatLon const & from, ms::Lat
|
|||
return rutaxiProducts;
|
||||
}
|
||||
|
||||
std::vector<taxi::Product> GetFreenowSynchronous(ms::LatLon const & from, ms::LatLon const & to,
|
||||
std::string const & url)
|
||||
{
|
||||
std::string freenowAnswer;
|
||||
TEST(taxi::freenow::RawApi::GetServiceTypes(from, to, "-" /* token */, freenowAnswer, url), ());
|
||||
|
||||
return taxi::freenow::MakeProductsFromJson(freenowAnswer);
|
||||
}
|
||||
|
||||
taxi::ProvidersContainer GetProvidersSynchronous(taxi::Engine const & engine,
|
||||
ms::LatLon const & from, ms::LatLon const & to,
|
||||
taxi::Delegate & delegate, std::string const & url)
|
||||
|
@ -192,6 +214,9 @@ taxi::ProvidersContainer GetProvidersSynchronous(taxi::Engine const & engine,
|
|||
providers.emplace_back(taxi::Provider::Type::Rutaxi,
|
||||
GetRutaxiSynchronous(from, to, delegate, url));
|
||||
break;
|
||||
case taxi::Provider::Type::Freenow:
|
||||
providers.emplace_back(taxi::Provider::Type::Freenow, GetFreenowSynchronous(from, to, url));
|
||||
break;
|
||||
case taxi::Provider::Type::Count:
|
||||
LOG(LERROR, ());
|
||||
break;
|
||||
|
@ -445,7 +470,8 @@ UNIT_CLASS_TEST(AsyncGuiThread, TaxiEngine_Smoke)
|
|||
taxi::Engine engine({{taxi::Provider::Type::Uber, kTesturl},
|
||||
{taxi::Provider::Type::Yandex, kTesturl},
|
||||
{taxi::Provider::Type::Maxim, kTesturl},
|
||||
{taxi::Provider::Type::Rutaxi, kTesturl}});
|
||||
{taxi::Provider::Type::Rutaxi, kTesturl},
|
||||
{taxi::Provider::Type::Freenow, kTesturl}});
|
||||
|
||||
engine.SetDelegate(std::make_unique<BelarusMinskDelegate>());
|
||||
BelarusMinskDelegate delegate;
|
||||
|
@ -523,5 +549,10 @@ UNIT_TEST(TaxiEngine_GetProvidersAtPos)
|
|||
engine.SetDelegate(std::make_unique<RussiaKonetsDelegate>());
|
||||
providers = engine.GetProvidersAtPos(latlon);
|
||||
TEST(providers.empty(), (providers));
|
||||
|
||||
engine.SetDelegate(std::make_unique<IrelandDublinDelegate>());
|
||||
providers = engine.GetProvidersAtPos(latlon);
|
||||
TEST_EQUAL(providers.size(), 1, ());
|
||||
TEST_EQUAL(providers[0], taxi::Provider::Type::Freenow, ());
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "partners_api/taxi_engine.hpp"
|
||||
|
||||
#include "partners_api/freenow_api.hpp"
|
||||
#include "partners_api/maxim_api.hpp"
|
||||
#include "partners_api/rutaxi_api.hpp"
|
||||
#include "partners_api/taxi_places_loader.hpp"
|
||||
|
@ -118,6 +120,7 @@ Engine::Engine(std::vector<ProviderUrl> urls /* = {} */)
|
|||
{
|
||||
AddApi<yandex::Api>(urls, Provider::Type::Yandex);
|
||||
AddApi<rutaxi::Api>(urls, Provider::Type::Rutaxi);
|
||||
AddApi<freenow::Api>(urls, Provider::Type::Freenow);
|
||||
}
|
||||
|
||||
void Engine::SetDelegate(std::unique_ptr<Delegate> delegate)
|
||||
|
|
|
@ -54,6 +54,7 @@ std::string Loader::GetFileNameByProvider(Provider::Type const type)
|
|||
case Provider::Type::Rutaxi: return "taxi_places/rutaxi.json";
|
||||
case Provider::Type::Uber: return "taxi_places/uber.json";
|
||||
case Provider::Type::Yandex: return "taxi_places/yandex.json";
|
||||
case Provider::Type::Freenow: return "taxi_places/freenow.json";
|
||||
case Provider::Type::Count: LOG(LERROR, ("Incorrect taxi provider")); return "";
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
Yandex,
|
||||
Maxim,
|
||||
Rutaxi,
|
||||
Freenow,
|
||||
Count
|
||||
};
|
||||
|
||||
|
@ -82,6 +83,7 @@ inline std::string DebugPrint(Provider::Type type)
|
|||
case Provider::Type::Yandex: return "Yandex";
|
||||
case Provider::Type::Maxim: return "Maxim";
|
||||
case Provider::Type::Rutaxi: return "Rutaxi";
|
||||
case Provider::Type::Freenow: return "Freenow";
|
||||
case Provider::Type::Count: ASSERT(false, ()); return "";
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -150,6 +150,8 @@ class ResponseProvider:
|
|||
"/gallery/v2/search/": self.promo_gallery_city,
|
||||
"/single/empty/gallery/v2/search/": self.promo_gallery_city_single_empty,
|
||||
"/single/gallery/v2/search/": self.promo_gallery_city_single,
|
||||
"/partners/oauth/token": self.freenow_auth_token,
|
||||
"/partners/service-types": self.freenow_service_types,
|
||||
}[url]()
|
||||
except:
|
||||
return self.test_404()
|
||||
|
@ -251,6 +253,12 @@ class ResponseProvider:
|
|||
def promo_gallery_city_single(self):
|
||||
return Payload(jsons.PROMO_GALLERY_CITY_SINGLE)
|
||||
|
||||
def freenow_auth_token(self):
|
||||
return Payload(jsons.FREENOW_AUTH_TOKEN)
|
||||
|
||||
def freenow_service_types(self):
|
||||
return Payload(jsons.FREENOW_SERVICE_TYPES)
|
||||
|
||||
def kill(self):
|
||||
logging.debug("Kill called in ResponseProvider")
|
||||
self.delegate.kill()
|
||||
|
|
|
@ -607,3 +607,72 @@ PROMO_GALLERY_CITY_SINGLE = """
|
|||
}
|
||||
}
|
||||
"""
|
||||
|
||||
FREENOW_AUTH_TOKEN = """
|
||||
{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXV",
|
||||
"token_type": "bearer",
|
||||
"expires_in": 600,
|
||||
"scope": "service-types"
|
||||
}
|
||||
"""
|
||||
|
||||
FREENOW_SERVICE_TYPES = """
|
||||
{
|
||||
"serviceTypes": [
|
||||
{
|
||||
"id": "TAXI",
|
||||
"type": "TAXI",
|
||||
"displayName": "Taxi",
|
||||
"eta": {
|
||||
"value": 0,
|
||||
"displayValue": "0 Minutes"
|
||||
},
|
||||
"fare": {
|
||||
"type": "FIXED",
|
||||
"value": 5000,
|
||||
"currencyCode": "GBP",
|
||||
"displayValue": "5000GBP"
|
||||
},
|
||||
"availablePaymentMethodTypes": [
|
||||
"BUSINESS_ACCOUNT",
|
||||
"CREDIT_CARD",
|
||||
"PAYPAL",
|
||||
"CASH"
|
||||
],
|
||||
"seats": {
|
||||
"max": 4,
|
||||
"values": [],
|
||||
"displayValue": "4"
|
||||
},
|
||||
"availableBookingOptions": [
|
||||
{
|
||||
"name": "COMMENT",
|
||||
"displayName": "COMMENT",
|
||||
"type": "TEXT"
|
||||
},
|
||||
{
|
||||
"name": "MERCEDES",
|
||||
"displayName": "MERCEDES",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "FAVORITE_DRIVER",
|
||||
"displayName": "FAVORITE_DRIVER",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "FIVE_STARS",
|
||||
"displayName": "FIVE_STARS",
|
||||
"type": "BOOLEAN"
|
||||
},
|
||||
{
|
||||
"name": "SMALL_ANIMAL",
|
||||
"displayName": "SMALL_ANIMAL",
|
||||
"type": "BOOLEAN"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
|
|
@ -181,8 +181,13 @@ class PostHandler(BaseHTTPRequestHandler, ResponseProviderMixin):
|
|||
def do_POST(self):
|
||||
self.init_vars()
|
||||
self.server.reset_selfdestruct_timer()
|
||||
length = int(self.headers.getheader('content-length'))
|
||||
self.dispatch_response(Payload(self.rfile.read(length)))
|
||||
headers = self.prepare_headers()
|
||||
payload = self.response_provider.response_for_url_and_headers(self.path, headers)
|
||||
if payload.response_code() >= 300:
|
||||
length = int(self.headers.getheader('content-length'))
|
||||
self.dispatch_response(Payload(self.rfile.read(length)))
|
||||
else:
|
||||
self.dispatch_response(payload)
|
||||
|
||||
|
||||
def do_GET(self):
|
||||
|
|
|
@ -59,7 +59,11 @@ class MainHandler(tornado.web.RequestHandler, ResponseProviderMixin):
|
|||
|
||||
|
||||
def post(self, param):
|
||||
self.dispatch_response(Payload(self.request.body))
|
||||
payload = self.response_provider.response_for_url_and_headers(self.request.uri, self.headers)
|
||||
if payload.response_code() >= 300:
|
||||
self.dispatch_response(Payload(self.request.body))
|
||||
else:
|
||||
self.dispatch_response(payload)
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
|
Loading…
Add table
Reference in a new issue