Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorr.kuznetsov <r.kuznetsov@corp.mail.ru>2017-10-10 17:21:27 +0300
committerYuri Gorshenin <mipt.vi002@gmail.com>2017-10-11 15:20:07 +0300
commitaae8eafcf7d07846e06c84d1163f0676539b2e6e (patch)
tree1fef1733a5341073ec110b2cb47039c2312540a9
parent6d6af51536343eaf38ee61d6f55fd7e81cb11a72 (diff)
Added UGC uploading
-rw-r--r--android/jni/com/mapswithme/maps/Framework.cpp5
-rw-r--r--android/jni/com/mapswithme/maps/Framework.hpp1
-rw-r--r--android/jni/com/mapswithme/maps/ugc/UGC.cpp6
-rw-r--r--android/src/com/mapswithme/maps/MwmApplication.java2
-rw-r--r--android/src/com/mapswithme/maps/background/WorkerService.java21
-rw-r--r--android/src/com/mapswithme/maps/ugc/UGC.java21
-rw-r--r--iphone/Maps/Classes/MapsAppDelegate.h1
-rw-r--r--iphone/Maps/Classes/MapsAppDelegate.mm35
-rw-r--r--map/framework.cpp10
-rw-r--r--map/framework.hpp4
-rw-r--r--map/user.cpp95
-rw-r--r--map/user.hpp18
-rw-r--r--qt/mainwindow.cpp3
13 files changed, 207 insertions, 15 deletions
diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp
index 6fa086389e..fb1d22ce4b 100644
--- a/android/jni/com/mapswithme/maps/Framework.cpp
+++ b/android/jni/com/mapswithme/maps/Framework.cpp
@@ -593,6 +593,11 @@ void Framework::SetUGCUpdate(FeatureID const & fid, ugc::UGCUpdate const & ugc)
m_work.GetUGCApi()->SetUGCUpdate(fid, ugc);
}
+void Framework::UploadUGC()
+{
+ m_work.UploadUGC(nullptr /* onCompleteUploading */);
+}
+
uint64_t Framework::GetRentNearby(JNIEnv * env, jobject policy, ms::LatLon const & latlon,
cian::Api::RentNearbyCallback const & onSuccess,
cian::Api::ErrorCallback const & onError)
diff --git a/android/jni/com/mapswithme/maps/Framework.hpp b/android/jni/com/mapswithme/maps/Framework.hpp
index 952eed8d9e..96b1edd510 100644
--- a/android/jni/com/mapswithme/maps/Framework.hpp
+++ b/android/jni/com/mapswithme/maps/Framework.hpp
@@ -202,6 +202,7 @@ namespace android
void RequestUGC(FeatureID const & fid, ugc::Api::UGCCallback const & ugcCallback);
void SetUGCUpdate(FeatureID const & fid, ugc::UGCUpdate const & ugc);
+ void UploadUGC();
uint64_t GetRentNearby(JNIEnv * env, jobject policy, ms::LatLon const & latlon,
cian::Api::RentNearbyCallback const & onSuccess,
diff --git a/android/jni/com/mapswithme/maps/ugc/UGC.cpp b/android/jni/com/mapswithme/maps/ugc/UGC.cpp
index aaabbbb60e..646c312dbb 100644
--- a/android/jni/com/mapswithme/maps/ugc/UGC.cpp
+++ b/android/jni/com/mapswithme/maps/ugc/UGC.cpp
@@ -237,4 +237,10 @@ void JNICALL Java_com_mapswithme_maps_ugc_UGC_setUGCUpdate(JNIEnv * env, jclass
ugc::UGCUpdate update = g_bridge.ToNativeUGCUpdate(env, ugcUpdate);
g_framework->SetUGCUpdate(fid, update);
}
+
+JNIEXPORT
+void JNICALL Java_com_mapswithme_maps_ugc_UGC_nativeUploadUGC(JNIEnv * env, jclass /* clazz */)
+{
+ g_framework->UploadUGC();
+}
}
diff --git a/android/src/com/mapswithme/maps/MwmApplication.java b/android/src/com/mapswithme/maps/MwmApplication.java
index d0bd07b110..8ebf56526d 100644
--- a/android/src/com/mapswithme/maps/MwmApplication.java
+++ b/android/src/com/mapswithme/maps/MwmApplication.java
@@ -27,6 +27,7 @@ import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.settings.StoragePathManager;
import com.mapswithme.maps.sound.TtsPlayer;
import com.mapswithme.maps.traffic.TrafficManager;
+import com.mapswithme.maps.ugc.UGC;
import com.mapswithme.util.Config;
import com.mapswithme.util.Constants;
import com.mapswithme.util.Counters;
@@ -206,6 +207,7 @@ public class MwmApplication extends Application
mBackgroundTracker.addListener(mBackgroundListener);
TrackRecorder.init();
Editor.init();
+ UGC.init();
mPlatformInitialized = true;
}
diff --git a/android/src/com/mapswithme/maps/background/WorkerService.java b/android/src/com/mapswithme/maps/background/WorkerService.java
index 02cd6128e0..756a0734cd 100644
--- a/android/src/com/mapswithme/maps/background/WorkerService.java
+++ b/android/src/com/mapswithme/maps/background/WorkerService.java
@@ -15,6 +15,7 @@ import com.mapswithme.maps.downloader.CountryItem;
import com.mapswithme.maps.downloader.MapManager;
import com.mapswithme.maps.editor.Editor;
import com.mapswithme.maps.location.LocationHelper;
+import com.mapswithme.maps.ugc.UGC;
import com.mapswithme.util.CrashlyticsUtils;
import com.mapswithme.util.PermissionsUtils;
import com.mapswithme.util.concurrency.UiThread;
@@ -29,6 +30,7 @@ public class WorkerService extends IntentService
private static final String TAG = WorkerService.class.getSimpleName();
private static final String ACTION_CHECK_LOCATIION = "com.mapswithme.maps.action.check_location";
private static final String ACTION_UPLOAD_OSM_CHANGES = "com.mapswithme.maps.action.upload_osm_changes";
+ private static final String ACTION_UPLOAD_UGC = "com.mapswithme.maps.action.upload_ugc";
private static final SharedPreferences PREFS = MwmApplication.prefs();
@@ -53,6 +55,16 @@ public class WorkerService extends IntentService
MwmApplication.get().startService(intent);
}
+ /**
+ * Starts this service to upload UGC to our servers.
+ */
+ public static void startActionUploadUGC()
+ {
+ final Intent intent = new Intent(MwmApplication.get(), WorkerService.class);
+ intent.setAction(WorkerService.ACTION_UPLOAD_UGC);
+ MwmApplication.get().startService(intent);
+ }
+
public WorkerService()
{
super("WorkerService");
@@ -77,6 +89,10 @@ public class WorkerService extends IntentService
case ACTION_UPLOAD_OSM_CHANGES:
handleActionUploadOsmChanges();
break;
+
+ case ACTION_UPLOAD_UGC:
+ handleUploadUGC();
+ break;
}
}
}
@@ -124,6 +140,11 @@ public class WorkerService extends IntentService
Editor.uploadChanges();
}
+ private static void handleUploadUGC()
+ {
+ UGC.nativeUploadUGC();
+ }
+
@android.support.annotation.UiThread
private static boolean processLocation()
{
diff --git a/android/src/com/mapswithme/maps/ugc/UGC.java b/android/src/com/mapswithme/maps/ugc/UGC.java
index 3c30edbe9c..6b0c4d2879 100644
--- a/android/src/com/mapswithme/maps/ugc/UGC.java
+++ b/android/src/com/mapswithme/maps/ugc/UGC.java
@@ -6,6 +6,9 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import com.mapswithme.maps.MwmApplication;
+import com.mapswithme.maps.background.AppBackgroundTracker;
+import com.mapswithme.maps.background.WorkerService;
import com.mapswithme.maps.bookmarks.data.FeatureId;
import java.io.Serializable;
@@ -34,6 +37,17 @@ public class UGC
static final int RATING_EXCELLENT = 5;
static final int RATING_COMING_SOON = 6;
+ private static final AppBackgroundTracker.OnTransitionListener UPLOADER =
+ new AppBackgroundTracker.OnTransitionListener()
+ {
+ @Override
+ public void onTransit(boolean foreground)
+ {
+ if (!foreground)
+ WorkerService.startActionUploadUGC();
+ }
+ };
+
@NonNull
private final Rating[] mRatings;
@Nullable
@@ -43,6 +57,11 @@ public class UGC
@Nullable
private static UGCListener mListener;
+ public static void init()
+ {
+ MwmApplication.backgroundTracker().addListener(UPLOADER);
+ }
+
private UGC(@NonNull Rating[] ratings, float averageRating, @Nullable Review[] reviews,
int basedOnCount)
{
@@ -95,6 +114,8 @@ public class UGC
public static native void setUGCUpdate(@NonNull FeatureId fid, UGCUpdate update);
+ public static native void nativeUploadUGC();
+
public static void onUGCReceived(@Nullable UGC ugc, @Nullable UGCUpdate ugcUpdate,
@Impress int impress, @NonNull String rating)
{
diff --git a/iphone/Maps/Classes/MapsAppDelegate.h b/iphone/Maps/Classes/MapsAppDelegate.h
index 6ef66afd12..dfccdab6cb 100644
--- a/iphone/Maps/Classes/MapsAppDelegate.h
+++ b/iphone/Maps/Classes/MapsAppDelegate.h
@@ -10,6 +10,7 @@
NSInteger m_activeDownloadsCounter;
UIBackgroundTaskIdentifier m_backgroundTask;
UIBackgroundTaskIdentifier m_editorUploadBackgroundTask;
+ UIBackgroundTaskIdentifier m_ugcUploadBackgroundTask;
UIAlertView * m_loadingAlertView;
}
diff --git a/iphone/Maps/Classes/MapsAppDelegate.mm b/iphone/Maps/Classes/MapsAppDelegate.mm
index d047189fe0..da2b5290bc 100644
--- a/iphone/Maps/Classes/MapsAppDelegate.mm
+++ b/iphone/Maps/Classes/MapsAppDelegate.mm
@@ -406,6 +406,14 @@ using namespace osm_auth_ios;
lambda);
}
+// Starts async UGC uploading process.
++ (void)uploadUGC:(MWMVoidBlock)finishCallback
+{
+ GetFramework().UploadUGC([finishCallback](){
+ finishCallback();
+ });
+}
+
- (void)application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
@@ -478,7 +486,12 @@ using namespace osm_auth_ios;
with:AuthorizationGetCredentials()];
});
}
- // 3. Check if map for current location is already downloaded, and if not - notify user to
+ // 3. Upload UGC.
+ runFetchTask(^{
+ // Ignore completion callback for now.
+ [MapsAppDelegate uploadUGC:^(){}];
+ });
+ // 4. Check if map for current location is already downloaded, and if not - notify user to
// download it.
runFetchTask(^{
[[LocalNotificationManager sharedManager] showDownloadMapNotificationIfNeeded:callback];
@@ -543,6 +556,26 @@ using namespace osm_auth_ios;
}
with:AuthorizationGetCredentials()];
}
+
+ // Upload UGC. All checks are inside the core part.
+ {
+ auto finishUGCUploadTaskBlock = ^{
+ if (self->m_ugcUploadBackgroundTask != UIBackgroundTaskInvalid)
+ {
+ [application endBackgroundTask:self->m_ugcUploadBackgroundTask];
+ self->m_ugcUploadBackgroundTask = UIBackgroundTaskInvalid;
+ }
+ };
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ static_cast<int64_t>(application.backgroundTimeRemaining)),
+ dispatch_get_main_queue(), finishUGCUploadTaskBlock);
+ m_ugcUploadBackgroundTask =
+ [application beginBackgroundTaskWithExpirationHandler:finishUGCUploadTaskBlock];
+ [MapsAppDelegate uploadUGC:^() {
+ finishUGCUploadTaskBlock();
+ }];
+ }
+
[MWMRouter saveRouteIfNeeded];
LOG(LINFO, ("applicationDidEnterBackground - end"));
}
diff --git a/map/framework.cpp b/map/framework.cpp
index 4d36efeac1..db5ade8b7c 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -3468,3 +3468,13 @@ void Framework::FillLocalExperts(FeatureType const & ft, place_page::Info & info
info.SetLocalsStatus(place_page::LocalsStatus::Available);
info.SetLocalsPageUrl(locals::Api::GetLocalsPageUrl());
}
+
+void Framework::UploadUGC(User::CompleteUploadingHandler const & onCompleteUploading)
+{
+ if (GetPlatform().ConnectionStatus() == Platform::EConnectionType::CONNECTION_NONE)
+ return;
+
+ //TODO: extract UGC for uploading.
+ if (m_user.IsAuthenticated()) // && UGC not empty
+ m_user.UploadUserReviews("{}", onCompleteUploading);
+}
diff --git a/map/framework.hpp b/map/framework.hpp
index 64be2fcf14..85d402b995 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -856,4 +856,8 @@ private:
void InjectViator(place_page::Info & info);
void FillLocalExperts(FeatureType const & ft, place_page::Info & info) const;
+
+public:
+ // UGC.
+ void UploadUGC(User::CompleteUploadingHandler const & onCompleteUploading);
};
diff --git a/map/user.cpp b/map/user.cpp
index fb31d3612f..801d756997 100644
--- a/map/user.cpp
+++ b/map/user.cpp
@@ -6,7 +6,9 @@
#include "coding/url_encode.hpp"
#include "base/logging.hpp"
+#include "base/string_utils.hpp"
+#include "3party/Alohalytics/src/alohalytics.h"
#include "3party/jansson/myjansson.hpp"
#include <chrono>
@@ -24,6 +26,13 @@ std::string const kPassportServerUrl = PASSPORT_URL;
std::string const kAppName = PASSPORT_APP_NAME;
std::string const kUGCServerUrl = UGC_URL;
+enum class ReviewReceiverProtocol : uint8_t
+{
+ v1 = 1, // October 2017. Initial version.
+
+ LatestVersion = v1
+};
+
std::string AuthenticationUrl(std::string const & socialToken,
User::SocialTokenType socialTokenType)
{
@@ -52,8 +61,20 @@ std::string AuthenticationUrl(std::string const & socialToken,
std::string UserDetailsUrl()
{
+ if (kUGCServerUrl.empty())
+ return {};
+
+ return kUGCServerUrl + "/user/reviews/";
+}
+
+std::string ReviewReceiverUrl()
+{
+ if (kUGCServerUrl.empty())
+ return {};
+
std::ostringstream ss;
- ss << kUGCServerUrl << "/user/reviews";
+ ss << kUGCServerUrl << "/receive/"
+ << static_cast<int>(ReviewReceiverProtocol::LatestVersion) << "/";
return ss.str();
}
@@ -183,7 +204,7 @@ void User::Authenticate(std::string const & socialToken, SocialTokenType socialT
// a delayed task calls destructed object.
m_workerThread.Push([this, url]()
{
- Request(url, {}, [this](std::string const & response)
+ Request(url, nullptr, [this](std::string const & response)
{
SetAccessToken(ParseAccessToken(response));
});
@@ -206,8 +227,11 @@ void User::RequestUserDetails()
m_workerThread.Push([this, url]()
{
- auto const headers = std::map<std::string, std::string>{{"Authorization", m_accessToken}};
- Request(url, headers, [this](std::string const & response)
+ Request(url, [this](platform::HttpClient & request)
+ {
+ request.SetRawHeader("Authorization", m_accessToken);
+ },
+ [this](std::string const & response)
{
auto const reviewIds = DeserializeReviewIds(response);
if (!reviewIds.empty())
@@ -220,9 +244,50 @@ void User::RequestUserDetails()
});
}
-void User::Request(std::string const & url,
- std::map<std::string, std::string> const & headers,
- std::function<void(std::string const &)> const & onSuccess)
+void User::UploadUserReviews(std::string const & dataStr,
+ CompleteUploadingHandler const & onCompleteUploading)
+{
+ std::string const url = ReviewReceiverUrl();
+ if (url.empty())
+ {
+ LOG(LWARNING, ("Reviews uploading is unavailable."));
+ return;
+ }
+
+ if (m_accessToken.empty())
+ return;
+
+ m_workerThread.Push([this, url, dataStr, onCompleteUploading]()
+ {
+ size_t const bytesCount = dataStr.size();
+ Request(url, [this, dataStr](platform::HttpClient & request)
+ {
+ request.SetRawHeader("Authorization", m_accessToken);
+ request.SetBodyData(dataStr, "application/json");
+ },
+ [this, bytesCount, onCompleteUploading](std::string const &)
+ {
+ alohalytics::Stats::Instance().LogEvent("UGC_DataUpload_finished",
+ strings::to_string(bytesCount));
+ LOG(LWARNING, ("Reviews have been uploaded."));
+
+ if (onCompleteUploading != nullptr)
+ onCompleteUploading();
+ },
+ [this, onCompleteUploading](int errorCode)
+ {
+ alohalytics::Stats::Instance().LogEvent("UGC_DataUpload_error",
+ strings::to_string(errorCode));
+ LOG(LWARNING, ("Reviews have not been uploaded."));
+
+ if (onCompleteUploading != nullptr)
+ onCompleteUploading();
+ });
+ });
+}
+
+void User::Request(std::string const & url, BuildRequestHandler const & onBuildRequest,
+ SuccessHandler const & onSuccess, ErrorHandler const & onError)
{
ASSERT(onSuccess != nullptr, ());
@@ -231,25 +296,30 @@ void User::Request(std::string const & url,
uint32_t constexpr kDegradationScalar = 2;
uint32_t waitingTime = kWaitingInSeconds;
+ int resultCode = -1;
+ bool isSuccessfulCode = false;
for (uint8_t i = 0; i < kAttemptsCount; ++i)
{
platform::HttpClient request(url);
request.SetRawHeader("Accept", "application/json");
- for (auto const & header : headers)
- request.SetRawHeader(header.first, header.second);
+ if (onBuildRequest != nullptr)
+ onBuildRequest(request);
// TODO: Now passport service uses redirection. If it becomes false, uncomment checking.
if (request.RunHttpRequest())// && !request.WasRedirected())
{
- if (request.ErrorCode() == 200) // Ok.
+ resultCode = request.ErrorCode();
+ isSuccessfulCode = (resultCode == 200 || resultCode == 201);
+ if (isSuccessfulCode) // Ok.
{
onSuccess(request.ServerResponse());
break;
}
- if (request.ErrorCode() == 403) // Forbidden.
+ if (resultCode == 403) // Forbidden.
{
ResetAccessToken();
+ LOG(LWARNING, ("Access denied for", url));
break;
}
}
@@ -262,4 +332,7 @@ void User::Request(std::string const & url,
break;
waitingTime *= kDegradationScalar;
}
+
+ if (!isSuccessfulCode && onError != nullptr)
+ onError(resultCode);
}
diff --git a/map/user.hpp b/map/user.hpp
index 2a1808f4c0..68f053233e 100644
--- a/map/user.hpp
+++ b/map/user.hpp
@@ -9,6 +9,11 @@
#include <string>
#include <vector>
+namespace platform
+{
+class HttpClient;
+}
+
// This class is thread-safe.
class User
{
@@ -24,6 +29,11 @@ public:
Google
};
+ using BuildRequestHandler = std::function<void(platform::HttpClient &)>;
+ using SuccessHandler = std::function<void(std::string const &)>;
+ using ErrorHandler = std::function<void(int)>;
+ using CompleteUploadingHandler = std::function<void()>;
+
User();
~User();
void Authenticate(std::string const & socialToken, SocialTokenType socialTokenType);
@@ -34,13 +44,15 @@ public:
std::string GetAccessToken() const;
Details GetDetails() const;
+ void UploadUserReviews(std::string const & dataStr,
+ CompleteUploadingHandler const & onCompleteUploading);
+
private:
void Init();
void SetAccessToken(std::string const & accessToken);
void RequestUserDetails();
- void Request(std::string const & url,
- std::map<std::string, std::string> const & headers,
- std::function<void(std::string const&)> const & onSuccess);
+ void Request(std::string const & url, BuildRequestHandler const & onBuildRequest,
+ SuccessHandler const & onSuccess, ErrorHandler const & onError = nullptr);
std::string m_accessToken;
mutable std::mutex m_mutex;
diff --git a/qt/mainwindow.cpp b/qt/mainwindow.cpp
index 16b69cf607..bad2b9c906 100644
--- a/qt/mainwindow.cpp
+++ b/qt/mainwindow.cpp
@@ -154,6 +154,8 @@ MainWindow::MainWindow(Framework & framework, bool apiOpenGLES3, QString const &
#endif // NO_DOWNLOADER
m_pDrawWidget->UpdateAfterSettingsChanged();
+
+ m_pDrawWidget->GetFramework().UploadUGC(nullptr /* onCompleteUploading */);
}
#if defined(Q_WS_WIN)
@@ -550,6 +552,7 @@ void MainWindow::OnSwitchSelectionMode()
}
void MainWindow::OnClearSelection() { m_pDrawWidget->GetFramework().GetDrapeApi().Clear(); }
+
void MainWindow::OnSearchButtonClicked()
{
if (m_pSearchAction->isChecked())