From cc08fa3b14a1fcefe057c291460b822fc6072b3e Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Fri, 25 Aug 2017 01:11:44 +0200 Subject: [PATCH] add resetting and deleting an account --- Habitica/res/values/strings.xml | 10 +++ Habitica/res/xml/preferences_fragment.xml | 7 +- .../android/habitica/api/ApiService.java | 7 ++ .../android/habitica/data/ApiClient.java | 3 +- .../android/habitica/data/UserRepository.java | 3 + .../data/implementation/ApiClientImpl.java | 13 ++++ .../implementation/UserRepositoryImpl.java | 11 ++++ .../preferences/AccountDetailsFragment.java | 64 +++++++++++++++++++ 8 files changed, 116 insertions(+), 2 deletions(-) diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index 5f77e9915..f6e50d872 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -644,4 +644,14 @@ Per: Int: Con: + Reset Account + WARNING! This resets many parts of your account. This is highly discouraged, but some people find it useful in the beginning after playing with the site for a short time.\n\nYou will lose all your levels, gold, and experience points. All your tasks (except those from challenges) will be deleted permanently and you will lose all of their historical data. You will lose all your equipment but you will be able to buy it all back, including all limited edition equipment or subscriber Mystery items that you already own (you will need to be in the correct class to re-buy class-specific gear). You will keep your current class and your pets and mounts. You might prefer to use an Orb of Rebirth instead, which is a much safer option and which will preserve your tasks and equipment. + Delete Account + Are you sure? This will delete your account forever, and it can never be restored! You will need to register a new account to use Habitica again. Banked or spent Gems will not be refunded. If you\'re absolutely certain, type your password into the text box below. + reset my account + delete my account + Danger Zone + Nevermind + Resetting Account + Deleting Account diff --git a/Habitica/res/xml/preferences_fragment.xml b/Habitica/res/xml/preferences_fragment.xml index 4b1a7ecfb..83071bbf0 100644 --- a/Habitica/res/xml/preferences_fragment.xml +++ b/Habitica/res/xml/preferences_fragment.xml @@ -60,7 +60,12 @@ android:persistent="false" android:shouldDisableView="false"/> - + + + + > runCron(); + + @POST("user/reset") + Observable> resetAccount(); + + @HTTP(method = "DELETE", path = "user", hasBody = true) + Observable> deleteAccount(@Body Map body); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java index d13a53f37..17636af57 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java @@ -234,5 +234,6 @@ public interface ApiClient { Observable runCron(); - + Observable resetAccount(); + Observable deleteAccount(String password); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java index 6fac8e894..707b496d8 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java @@ -57,4 +57,7 @@ public interface UserRepository extends BaseRepository { Observable changeCustomDayStart(int dayStartTime); Observable updateLanguage(User user, String languageCode); + + Observable resetAccount(); + Observable deleteAccount(String password); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java index 0e866375b..0908a9c76 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java @@ -104,6 +104,7 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -857,4 +858,16 @@ public class ApiClientImpl implements Action1, ApiClient { public Observable runCron() { return apiService.runCron().compose(configureApiCallObserver()); } + + @Override + public Observable resetAccount() { + return apiService.resetAccount().compose(configureApiCallObserver()); + } + + @Override + public Observable deleteAccount(String password) { + Map updateObject = new HashMap<>(); + updateObject.put("password", password); + return apiService.deleteAccount(updateObject).compose(configureApiCallObserver()); + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java index d6b8c1b64..d5dca4f3a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java @@ -233,6 +233,17 @@ public class UserRepositoryImpl extends BaseRepositoryImpl .doOnNext(user1 -> apiClient.setLanguageCode(languageCode)); } + @Override + public Observable resetAccount() { + return apiClient.resetAccount() + .flatMap(aVoid -> retrieveUser(true, true)); + } + + @Override + public Observable deleteAccount(String password) { + return apiClient.deleteAccount(password); + } + @Override public void runCron(List tasks) { Observable> observable; diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountDetailsFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountDetailsFragment.java index 88abb5040..13eb980db 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountDetailsFragment.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountDetailsFragment.java @@ -1,13 +1,19 @@ package com.habitrpg.android.habitica.ui.fragments.preferences; +import android.app.ProgressDialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.support.v7.preference.Preference; +import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.Toast; +import com.habitrpg.android.habitica.HabiticaApplication; import com.habitrpg.android.habitica.HabiticaBaseApplication; import com.habitrpg.android.habitica.R; import com.habitrpg.android.habitica.data.UserRepository; @@ -16,6 +22,7 @@ import com.habitrpg.android.habitica.helpers.QrCodeManager; import com.habitrpg.android.habitica.helpers.RxErrorHandler; import com.habitrpg.android.habitica.models.user.User; import com.habitrpg.android.habitica.models.user.SubscriptionPlan; +import com.habitrpg.android.habitica.ui.activities.MainActivity; import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionDetailsView; import org.greenrobot.eventbus.EventBus; @@ -86,6 +93,10 @@ public class AccountDetailsFragment extends BasePreferencesFragment { } } EventBus.getDefault().post(new OpenGemPurchaseFragmentCommand()); + } else if ("reset_account".equals(preference.getKey())) { + showAccountResetConfirmation(); + } else if ("delete_account".equals(preference.getKey())) { + showAccountDeleteConfirmation(); } else { ClipboardManager clipMan = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); clipMan.setPrimaryClip(ClipData.newPlainText(preference.getKey(), preference.getSummary())); @@ -94,6 +105,59 @@ public class AccountDetailsFragment extends BasePreferencesFragment { return super.onPreferenceTreeClick(preference); } + private void showAccountDeleteConfirmation() { + final EditText input = new EditText(getContext()); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + input.setLayoutParams(lp); + AlertDialog dialog = new AlertDialog.Builder(getContext()) + .setTitle(R.string.delete_account) + .setMessage(R.string.delete_account_description) + .setPositiveButton(R.string.delete_account_confirmation, ((thisDialog, which) -> { + thisDialog.dismiss(); + deleteAccount(input.getText().toString()); + })) + .setNegativeButton(R.string.nevermind, ((thisDialog, which) -> thisDialog.dismiss())) + .create(); + dialog.setOnShowListener(arg0 -> dialog.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getContext(), R.color.worse_10))); + dialog.setView(input); + dialog.show(); + } + + private void deleteAccount(String password) { + ProgressDialog dialog = ProgressDialog.show(getContext(), getContext().getString(R.string.deleting_account), null, true); + userRepository.deleteAccount(password).subscribe(user -> { + HabiticaApplication.logout(getContext()); + getActivity().finish(); + }, throwable -> { + dialog.dismiss(); + RxErrorHandler.reportError(throwable); + }); + } + + private void showAccountResetConfirmation() { + AlertDialog dialog = new AlertDialog.Builder(getContext()) + .setTitle(R.string.reset_account) + .setMessage(R.string.reset_account_description) + .setPositiveButton(R.string.reset_account_confirmation, ((thisDialog, which) -> { + thisDialog.dismiss(); + resetAccount(); + })) + .setNegativeButton(R.string.nevermind, ((thisDialog, which) -> thisDialog.dismiss())) + .create(); + dialog.setOnShowListener(arg0 -> dialog.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(ContextCompat.getColor(getContext(), R.color.worse_10))); + dialog.show(); + } + + private void resetAccount() { + ProgressDialog dialog = ProgressDialog.show(getContext(), getContext().getString(R.string.resetting_account), null, true); + userRepository.resetAccount().subscribe(user -> dialog.dismiss(), throwable -> { + dialog.dismiss(); + RxErrorHandler.reportError(throwable); + }); + } + private void showSubscriptionStatusDialog() { SubscriptionDetailsView view = new SubscriptionDetailsView(getContext()); view.setPlan(user.getPurchased().getPlan());