Added invalid bookmarks deleter

This commit is contained in:
r.kuznetsov 2019-07-02 17:26:13 +03:00 committed by Aleksey Belousov
parent 783695f939
commit 0d04f2011a
12 changed files with 269 additions and 16 deletions

View file

@ -50,6 +50,8 @@ jmethodID g_catalogCustomPropertyConstructor;
jmethodID g_onPingFinishedMethod;
jmethodID g_onCheckInvalidCategoriesMethod;
void PrepareClassRefs(JNIEnv * env)
{
if (g_bookmarkManagerClass)
@ -101,6 +103,9 @@ void PrepareClassRefs(JNIEnv * env)
g_onPingFinishedMethod = jni::GetMethodID(env, bookmarkManagerInstance, "onPingFinished", "(Z)V");
g_onCheckInvalidCategoriesMethod = jni::GetMethodID(env, bookmarkManagerInstance,
"onCheckInvalidCategories", "(Z)V");
g_bookmarkCategoryClass =
jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/BookmarkCategory");
//public BookmarkCategory(long id,
@ -368,6 +373,17 @@ void OnPingFinished(JNIEnv * env, bool isSuccessful)
jni::HandleJavaException(env);
}
void OnCheckInvalidCategories(JNIEnv * env, bool hasInvalidCategories)
{
ASSERT(g_bookmarkManagerClass, ());
auto bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onCheckInvalidCategoriesMethod,
static_cast<jboolean>(hasInvalidCategories));
jni::HandleJavaException(env);
}
void OnUploadStarted(JNIEnv * env, kml::MarkGroupId originCategoryId)
{
ASSERT(g_bookmarkManagerClass, ());
@ -936,8 +952,34 @@ Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativePingBookmarkCatalo
});
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeCheckInvalidCategories(JNIEnv * env,
jobject)
{
frm()->GetBookmarkManager().CheckInvalidCategories(Purchase::GetDeviceId(),
[env](bool hasInvalidCategories)
{
OnCheckInvalidCategories(env, hasInvalidCategories);
});
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteInvalidCategories(JNIEnv * env,
jobject)
{
frm()->GetBookmarkManager().DeleteInvalidCategories();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeResetInvalidCategories(JNIEnv * env,
jobject)
{
frm()->GetBookmarkManager().ResetInvalidCategories();
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env, jobject thiz)
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env,
jobject thiz)
{
auto const & bm = frm()->GetBookmarkManager();
kml::GroupIdCollection const & categories = bm.GetBmGroupsIdList();

View file

@ -69,6 +69,9 @@ public enum BookmarkManager
@NonNull
private final List<BookmarksCatalogPingListener> mCatalogPingListeners = new ArrayList<>();
@NonNull
private final List<BookmarksInvalidCategoriesListener> mInvalidCategoriesListeners = new ArrayList<>();
static
{
@ -327,6 +330,15 @@ public enum BookmarkManager
listener.onPingFinished(isServiceAvailable);
}
// Called from JNI.
@SuppressWarnings("unused")
@MainThread
public void onCheckInvalidCategories(boolean hasInvalidCategories)
{
for (BookmarksInvalidCategoriesListener listener : mInvalidCategoriesListeners)
listener.onCheckInvalidCategories(hasInvalidCategories);
}
public boolean isVisible(long catId)
{
return nativeIsVisible(catId);
@ -661,6 +673,21 @@ public enum BookmarkManager
nativePingBookmarkCatalog();
}
public void checkInvalidCategories()
{
nativeCheckInvalidCategories();
}
public void deleteInvalidCategories()
{
nativeDeleteInvalidCategories();
}
public void resetInvalidCategories()
{
nativeResetInvalidCategories();
}
public boolean isCategoryFromCatalog(long catId)
{
return nativeIsCategoryFromCatalog(catId);
@ -805,6 +832,10 @@ public enum BookmarkManager
private static native void nativePingBookmarkCatalog();
private static native void nativeCheckInvalidCategories();
private static native void nativeDeleteInvalidCategories();
private static native void nativeResetInvalidCategories();
public interface BookmarksLoadingListener
{
void onBookmarksLoadingStarted();
@ -865,6 +896,11 @@ public enum BookmarkManager
void onPingFinished(boolean isServiceAvailable);
}
public interface BookmarksInvalidCategoriesListener
{
void onCheckInvalidCategories(boolean hasInvalidCategories);
}
public interface BookmarksCatalogListener
{
/**

View file

@ -10,6 +10,8 @@
#include "Framework.h"
#include "map/purchase.hpp"
#include "partners_api/utm.hpp"
#include "coding/internal/file_data.hpp"
@ -592,7 +594,7 @@ NSString * const CloudErrorToString(Cloud::SynchronizationResult result)
observer.progressBlock = progress;
observer.downloadCompletionBlock = completion;
[self.catalogObservers setObject:observer forKey:itemId];
self.bm.DownloadFromCatalogAndImport(itemId.UTF8String, name.UTF8String);
self.bm.DownloadFromCatalogAndImport(itemId.UTF8String, Purchase::GetDeviceId(), name.UTF8String);
}
- (void)uploadAndGetDirectLinkCategoryWithId:(MWMMarkGroupID)itemId

View file

@ -77,6 +77,13 @@ std::string BuildPingUrl()
return kCatalogFrontendServer + "storage/ping";
}
std::string BuildDeleteRequestUrl()
{
if (kCatalogFrontendServer.empty())
return {};
return kCatalogFrontendServer + "storage/kmls_to_delete";
}
struct SubtagData
{
std::string m_name;
@ -157,6 +164,31 @@ struct HashResponseData
DECLARE_VISITOR(visitor(m_hash, "hash"))
};
struct DeleteRequestData
{
DeleteRequestData(std::string const & deviceId, std::string const & userId,
std::vector<std::string> const & serverIds)
: m_deviceId(deviceId)
, m_userId(userId)
, m_serverIds(serverIds)
{}
std::string m_deviceId;
std::string m_userId;
std::vector<std::string> m_serverIds;
DECLARE_VISITOR(visitor(m_deviceId, "server_id"),
visitor(m_userId, "user_id"),
visitor(m_serverIds, "server_ids"))
};
struct DeleteRequestResponseData
{
std::vector<std::string> m_serverIds;
DECLARE_VISITOR(visitor(m_serverIds))
};
int constexpr kInvalidHash = -1;
int RequestNewServerId(std::string const & accessToken,
@ -223,7 +255,7 @@ bool BookmarkCatalog::HasDownloaded(std::string const & id) const
}
void BookmarkCatalog::Download(std::string const & id, std::string const & accessToken,
DownloadStartCallback && startHandler,
std::string const & deviceId, DownloadStartCallback && startHandler,
DownloadFinishCallback && finishHandler)
{
if (IsDownloading(id) || HasDownloaded(id))
@ -234,7 +266,7 @@ void BookmarkCatalog::Download(std::string const & id, std::string const & acces
static uint32_t counter = 0;
auto const path = base::JoinPath(GetPlatform().TmpDir(), "file" + strings::to_string(++counter));
platform::RemoteFile remoteFile(BuildCatalogDownloadUrl(id), accessToken);
platform::RemoteFile remoteFile(BuildCatalogDownloadUrl(id), accessToken, deviceId);
remoteFile.DownloadAsync(path, [startHandler = std::move(startHandler)](std::string const &)
{
if (startHandler)
@ -630,6 +662,67 @@ void BookmarkCatalog::Ping(PingCallback && callback) const
});
}
void BookmarkCatalog::RequestBookmarksToDelete(std::string const & accessToken, std::string const & userId,
std::string const & deviceId, std::vector<std::string> const & serverIds,
BookmarksToDeleteCallback && callback) const
{
auto const url = BuildDeleteRequestUrl();
if (url.empty())
{
if (callback)
callback({});
return;
}
GetPlatform().RunTask(Platform::Thread::Network,
[url, accessToken, userId, deviceId, serverIds, callback = std::move(callback)]()
{
platform::HttpClient request(url);
request.SetRawHeader("Accept", "application/json");
request.SetRawHeader("User-Agent", GetPlatform().GetAppUserAgent());
if (!accessToken.empty())
request.SetRawHeader("Authorization", "Bearer " + accessToken);
request.SetHttpMethod("POST");
std::string jsonStr;
{
using Sink = MemWriter<std::string>;
Sink sink(jsonStr);
coding::SerializerJson<Sink> serializer(sink);
serializer(DeleteRequestData(deviceId, userId, serverIds));
}
request.SetBodyData(std::move(jsonStr), "application/json");
uint32_t constexpr kTimeoutInSec = 5;
request.SetTimeout(kTimeoutInSec);
if (request.RunHttpRequest())
{
auto const resultCode = request.ErrorCode();
if (callback && resultCode >= 200 && resultCode < 300)
{
DeleteRequestResponseData responseData;
try
{
coding::DeserializerJson des(request.ServerResponse());
des(responseData);
}
catch (coding::DeserializerJson::Exception const & ex)
{
LOG(LWARNING, ("Bookmarks-to-delete request deserialization error:", ex.Msg()));
if (callback)
callback({});
return;
}
callback(responseData.m_serverIds);
return;
}
}
if (callback)
callback({});
});
}
void BookmarkCatalog::SetInvalidTokenHandler(InvalidTokenHandler && onInvalidToken)
{
m_onInvalidToken = std::move(onInvalidToken);

View file

@ -69,7 +69,7 @@ public:
using DownloadFinishCallback = std::function<void(DownloadResult result,
std::string const & description,
std::string const & filePath)>;
void Download(std::string const & id, std::string const & accessToken,
void Download(std::string const & id, std::string const & accessToken, std::string const & deviceId,
DownloadStartCallback && startHandler, DownloadFinishCallback && finishHandler);
bool IsDownloading(std::string const & id) const;
@ -121,6 +121,11 @@ public:
// Handler can be called from non-UI thread.
void SetInvalidTokenHandler(InvalidTokenHandler && onInvalidToken);
using BookmarksToDeleteCallback = platform::SafeCallback<void(std::vector<std::string> const & serverIds)>;
void RequestBookmarksToDelete(std::string const & accessToken, std::string const & userId,
std::string const & deviceId, std::vector<std::string> const & serverIds,
BookmarksToDeleteCallback && callback) const;
private:
std::set<std::string> m_downloadingIds;
std::set<std::string> m_registeredInCatalog;

View file

@ -1995,6 +1995,19 @@ void BookmarkManager::SetAllCategoriesVisibility(CategoryFilterType const filter
}
}
std::vector<std::string> BookmarkManager::GetAllPaidCategoriesIds() const
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
std::vector<std::string> ids;
for (auto const & category : m_categories)
{
if (category.second->GetCategoryData().m_accessRules != kml::AccessRules::Paid)
continue;
ids.emplace_back(category.second->GetServerId());
}
return ids;
}
bool BookmarkManager::CanConvert() const
{
// The conversion available only after successful migration.
@ -2239,9 +2252,10 @@ void BookmarkManager::SetCatalogHandlers(OnCatalogDownloadStartedHandler && onCa
m_onCatalogUploadFinishedHandler = std::move(onCatalogUploadFinishedHandler);
}
void BookmarkManager::DownloadFromCatalogAndImport(std::string const & id, std::string const & name)
void BookmarkManager::DownloadFromCatalogAndImport(std::string const & id, std::string const & deviceId,
std::string const & name)
{
m_bookmarkCatalog.Download(id, m_user.GetAccessToken(), [this, id]()
m_bookmarkCatalog.Download(id, m_user.GetAccessToken(), deviceId, [this, id]()
{
if (m_onCatalogDownloadStarted)
m_onCatalogDownloadStarted(id);
@ -2504,6 +2518,47 @@ void BookmarkManager::EnableTestMode(bool enable)
m_testModeEnabled = enable;
}
void BookmarkManager::CheckInvalidCategories(std::string const & deviceId,
CheckInvalidCategoriesHandler && handler)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
m_bookmarkCatalog.RequestBookmarksToDelete(m_user.GetAccessToken(), m_user.GetUserId(), deviceId,
GetAllPaidCategoriesIds(),
[this, handler = std::move(handler)](
std::vector<std::string> const & serverIds)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
m_invalidCategories.clear();
for (auto const & s : serverIds)
{
for (auto const & category : m_categories)
{
if (category.second->GetServerId() == s)
m_invalidCategories.emplace_back(category.first);
}
}
if (handler)
handler(!m_invalidCategories.empty());
});
}
void BookmarkManager::DeleteInvalidCategories()
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
if (m_invalidCategories.empty())
return;
auto session = GetEditSession();
for (auto const markGroupId : m_invalidCategories)
session.DeleteBmCategory(markGroupId);
}
void BookmarkManager::ResetInvalidCategories()
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
m_invalidCategories.clear();
}
kml::GroupIdSet BookmarkManager::MarksChangesTracker::GetAllGroupIds() const
{
auto const & groupIds = m_bmManager.GetBmGroupsIdList();

View file

@ -319,7 +319,8 @@ public:
OnCatalogImportFinishedHandler && onCatalogImportFinished,
OnCatalogUploadStartedHandler && onCatalogUploadStartedHandler,
OnCatalogUploadFinishedHandler && onCatalogUploadFinishedHandler);
void DownloadFromCatalogAndImport(std::string const & id, std::string const & name);
void DownloadFromCatalogAndImport(std::string const & id, std::string const & deviceId,
std::string const & name);
void ImportDownloadedFromCatalog(std::string const & id, std::string const & filePath);
void UploadToCatalog(kml::MarkGroupId categoryId, kml::AccessRules accessRules);
bool IsCategoryFromCatalog(kml::MarkGroupId categoryId) const;
@ -329,6 +330,11 @@ public:
bool IsMyCategory(kml::MarkGroupId categoryId) const;
using CheckInvalidCategoriesHandler = std::function<void(bool hasInvalidCategories)>;
void CheckInvalidCategories(std::string const & deviceId, CheckInvalidCategoriesHandler && handler);
void DeleteInvalidCategories();
void ResetInvalidCategories();
/// These functions are public for unit tests only. You shouldn't call them from client code.
void EnableTestMode(bool enable);
bool SaveBookmarkCategory(kml::MarkGroupId groupId);
@ -531,6 +537,9 @@ private:
bool HasDuplicatedIds(kml::FileData const & fileData) const;
bool CheckVisibility(CategoryFilterType const filter, bool isVisible) const;
std::vector<std::string> GetAllPaidCategoriesIds() const;
ThreadChecker m_threadChecker;
User & m_user;
@ -597,6 +606,8 @@ private:
};
std::map<std::string, RestoringCache> m_restoringCache;
std::vector<kml::MarkGroupId> m_invalidCategories;
bool m_testModeEnabled = false;
DISALLOW_COPY_AND_MOVE(BookmarkManager);

View file

@ -1397,7 +1397,8 @@ void Cloud::DownloadingTask(std::string const & dirPath, bool useFallbackUrl,
platform::RemoteFile remoteFile(useFallbackUrl ? result.m_response.m_fallbackUrl
: result.m_response.m_url,
{} /* accessToken */, false /* allowRedirection */);
{} /* accessToken */, {} /* deviceId */,
false /* allowRedirection */);
auto const downloadResult = remoteFile.Download(filePath);
if (downloadResult.m_status == platform::RemoteFile::Status::Ok)

View file

@ -46,11 +46,6 @@ std::string GetSubscriptionId(SubscriptionType type)
kSubscriptionSuffix[base::Underlying(type)]);
}
std::string GetDeviceId()
{
return coding::SHA1::CalculateBase64ForString(GetPlatform().UniqueClientId());
}
std::string GetSubscriptionKey(SubscriptionType type)
{
return kSubscriptionId + kSubscriptionSuffix[base::Underlying(type)];
@ -309,3 +304,9 @@ void Purchase::ValidateImpl(std::string const & url, ValidationInfo const & vali
});
}
}
// static
std::string Purchase::GetDeviceId()
{
return coding::SHA1::CalculateBase64ForString(GetPlatform().UniqueClientId());
}

View file

@ -65,6 +65,8 @@ public:
void StartTransaction(std::string const & serverId, std::string const & vendorId,
std::string const & accessToken);
static std::string GetDeviceId();
private:
void ValidateImpl(std::string const & url, ValidationInfo const & validationInfo,
std::string const & accessToken, bool startTransaction,

View file

@ -15,9 +15,10 @@ double constexpr kRequestTimeoutInSec = 5.0;
} // namespace
RemoteFile::RemoteFile(std::string url, std::string accessToken /* = {} */,
bool allowRedirection /* = true */)
std::string deviceId /* = {} */, bool allowRedirection /* = true */)
: m_url(std::move(url))
, m_accessToken(std::move(accessToken))
, m_deviceId(std::move(deviceId))
, m_allowRedirection(allowRedirection)
{}
@ -30,6 +31,8 @@ RemoteFile::Result RemoteFile::Download(std::string const & filePath) const
request.SetTimeout(kRequestTimeoutInSec);
if (!m_accessToken.empty())
request.SetRawHeader("Authorization", "Bearer " + m_accessToken);
if (!m_deviceId.empty())
request.SetRawHeader("X-Mapsme-Device-Id", m_deviceId);
request.SetRawHeader("User-Agent", GetPlatform().GetAppUserAgent());
if (request.RunHttpRequest())
{

View file

@ -36,7 +36,8 @@ public:
{}
};
explicit RemoteFile(std::string url, std::string accessToken = {}, bool allowRedirection = true);
explicit RemoteFile(std::string url, std::string accessToken = {}, std::string deviceId = {},
bool allowRedirection = true);
Result Download(std::string const & filePath) const;
@ -49,6 +50,7 @@ public:
private:
std::string const m_url;
std::string const m_accessToken;
std::string const m_deviceId;
bool const m_allowRedirection;
};
} // namespace platform