Skip to content

Commit

Permalink
Merge pull request #5447 from nextcloud/ezaquarii/migrate-jobs-to-new…
Browse files Browse the repository at this point in the history
…-user-model

Migrate jobs to new user model
  • Loading branch information
tobiasKaminsky authored Feb 17, 2020
2 parents 20b910a + 7b4e1b8 commit 4616b0d
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ public interface UserAccountManager extends CurrentAccountProvider {
*/
void removeAllAccounts();

/**
* Remove registered user.
*
* @param user user to remove
* @return true if account was removed successfully, false otherwise
*/
boolean removeUser(User user);

/**
* Get configured NextCloud's user accounts.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
Expand All @@ -43,6 +46,7 @@
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -81,6 +85,18 @@ public void removeAllAccounts() {
}
}

@Override
public boolean removeUser(User user) {
try {
AccountManagerFuture<Boolean> result = accountManager.removeAccount(user.toPlatformAccount(),
null,
null);
return result.getResult();
} catch (OperationCanceledException| AuthenticatorException| IOException ex) {
return false;
}
}

@Override
@NonNull
public Account[] getAccounts() {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/nextcloud/client/di/AppModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
import com.owncloud.android.ui.activities.data.files.FilesServiceApiImpl;
import com.owncloud.android.ui.activities.data.files.RemoteFilesRepository;

import org.greenrobot.eventbus.EventBus;

import java.io.File;

import javax.inject.Singleton;
Expand Down Expand Up @@ -164,4 +166,10 @@ NotificationManager notificationManager(Context context) {
AudioManager audioManager(Context context) {
return (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
}

@Provides
@Singleton
EventBus eventBus() {
return EventBus.getDefault();
}
}
7 changes: 6 additions & 1 deletion src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import com.owncloud.android.utils.SecurityUtils;

import org.conscrypt.Conscrypt;
import org.greenrobot.eventbus.EventBus;

import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -166,6 +167,9 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
@Inject
Clock clock;

@Inject
EventBus eventBus;

private PassCodeManager passCodeManager;

@SuppressWarnings("unused")
Expand Down Expand Up @@ -274,7 +278,8 @@ public void onCreate() {
uploadsStorageManager,
connectivityService,
powerManagementService,
clock
clock,
eventBus
)
);

Expand Down
165 changes: 82 additions & 83 deletions src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
Expand All @@ -37,9 +35,11 @@
import com.evernote.android.job.Job;
import com.evernote.android.job.util.support.PersistableBundleCompat;
import com.google.gson.Gson;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.core.Clock;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.nextcloud.java.util.Optional;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
Expand All @@ -49,8 +49,8 @@
import com.owncloud.android.datamodel.SyncedFolder;
import com.owncloud.android.datamodel.SyncedFolderProvider;
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManager;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.users.RemoteWipeSuccessRemoteOperation;
Expand All @@ -67,108 +67,128 @@
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import static android.content.Context.ACCOUNT_SERVICE;
import static com.owncloud.android.ui.activity.ManageAccountsActivity.PENDING_FOR_REMOVAL;

/**
* Removes account and all local files
*/
public class AccountRemovalJob extends Job implements AccountManagerCallback<Boolean> {
public class AccountRemovalJob extends Job {
public static final String TAG = "AccountRemovalJob";
public static final String ACCOUNT = "account";
public static final String REMOTE_WIPE = "remote_wipe";

private final UploadsStorageManager uploadsStorageManager;
private final UserAccountManager userAccountManager;
private final Clock clock;
private final EventBus eventBus;

public AccountRemovalJob(UploadsStorageManager uploadStorageManager, UserAccountManager accountManager, Clock clock) {
public AccountRemovalJob(UploadsStorageManager uploadStorageManager,
UserAccountManager accountManager,
Clock clock,
EventBus eventBus) {
this.uploadsStorageManager = uploadStorageManager;
this.userAccountManager = accountManager;
this.clock = clock;
this.eventBus = eventBus;
}

@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
Context context = MainApp.getAppContext();
PersistableBundleCompat bundle = params.getExtras();
Account account = userAccountManager.getAccountByName(bundle.getString(ACCOUNT, ""));
String accountName = bundle.getString(ACCOUNT, "");
if (TextUtils.isEmpty(accountName)) {
// didn't receive account to delete
return Result.FAILURE;
}
Optional<User> optionalUser = userAccountManager.getUser(accountName);
if (!optionalUser.isPresent()) {
// trying to delete non-existing user
return Result.FAILURE;
}
AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
if (accountManager == null) {
return Result.FAILURE;
}
boolean remoteWipe = bundle.getBoolean(REMOTE_WIPE, false);

if (account != null && accountManager != null) {
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());

// disable contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);
User user = optionalUser.get();
// disable contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, user);

removeAccount(account, accountManager);
final boolean userRemoved = userAccountManager.removeUser(user);
if (userRemoved) {
eventBus.post(new AccountRemovedEvent());
}

FileDataStorageManager storageManager = new FileDataStorageManager(account, context.getContentResolver());
FileDataStorageManager storageManager = new FileDataStorageManager(user.toPlatformAccount(), context.getContentResolver());

// remove all files
removeFiles(account, storageManager);
// remove all files
removeFiles(user, storageManager);

// delete all database entries
storageManager.deleteAllFiles();
// delete all database entries
storageManager.deleteAllFiles();

// remove contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);
// remove contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, user);

// disable daily backup
arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
"false");
// disable daily backup
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
"false");

// unregister push notifications
unregisterPushNotifications(context, account, arbitraryDataProvider);
// unregister push notifications
unregisterPushNotifications(context, user, arbitraryDataProvider);

// remove pending account removal
arbitraryDataProvider.deleteKeyForAccount(account.name, PENDING_FOR_REMOVAL);
// remove pending account removal
arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), PENDING_FOR_REMOVAL);

// remove synced folders set for account
remoceSyncedFolders(context, account, clock);
// remove synced folders set for account
remoceSyncedFolders(context, user.toPlatformAccount(), clock);

// delete all uploads for account
uploadsStorageManager.removeAccountUploads(account);
// delete all uploads for account
uploadsStorageManager.removeAccountUploads(user.toPlatformAccount());

// delete stored E2E keys
arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PRIVATE_KEY);
arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PUBLIC_KEY);
// delete stored E2E keys
arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PRIVATE_KEY);
arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PUBLIC_KEY);

OwnCloudClient client = createClient(account);
if (remoteWipe && client != null) {
if (remoteWipe) {
Optional<OwnCloudClient> optionalClient = createClient(user);
if (optionalClient.isPresent()) {
OwnCloudClient client = optionalClient.get();
String authToken = client.getCredentials().getAuthToken();
new RemoteWipeSuccessRemoteOperation(authToken).execute(client);
}
}

// notify Document Provider
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String authority = context.getResources().getString(R.string.document_provider_authority);
Uri rootsUri = DocumentsContract.buildRootsUri(authority);
context.getContentResolver().notifyChange(rootsUri, null);
}

return Result.SUCCESS;
} else {
return Result.FAILURE;
// notify Document Provider
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String authority = context.getResources().getString(R.string.document_provider_authority);
Uri rootsUri = DocumentsContract.buildRootsUri(authority);
context.getContentResolver().notifyChange(rootsUri, null);
}
}

private void unregisterPushNotifications(Context context, Account account, ArbitraryDataProvider arbitraryDataProvider) {
String arbitraryDataPushString;
return Result.SUCCESS;
}

if (!TextUtils.isEmpty(arbitraryDataPushString = arbitraryDataProvider.getValue(
account, PushUtils.KEY_PUSH)) &&
!TextUtils.isEmpty(context.getResources().getString(R.string.push_server_url))) {
private void unregisterPushNotifications(Context context,
User user,
ArbitraryDataProvider arbitraryDataProvider) {
final String arbitraryDataPushString = arbitraryDataProvider.getValue(user.toPlatformAccount(),
PushUtils.KEY_PUSH);
final String pushServerUrl = context.getResources().getString(R.string.push_server_url);
if (!TextUtils.isEmpty(arbitraryDataPushString) && !TextUtils.isEmpty(pushServerUrl)) {
Gson gson = new Gson();
PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
PushConfigurationState.class);
pushArbitraryData.setShouldBeDeleted(true);
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), PushUtils.KEY_PUSH,
gson.toJson(pushArbitraryData));

PushUtils.pushRegistrationToServer(userAccountManager, pushArbitraryData.getPushToken());
Expand Down Expand Up @@ -198,44 +218,23 @@ private void remoceSyncedFolders(Context context, Account account, Clock clock)
}
}

private void removeFiles(Account account, FileDataStorageManager storageManager) {
File tempDir = new File(FileStorageUtils.getTemporalPath(account.name));
File saveDir = new File(FileStorageUtils.getSavePath(account.name));
private void removeFiles(User user, FileDataStorageManager storageManager) {
File tempDir = new File(FileStorageUtils.getTemporalPath(user.getAccountName()));
File saveDir = new File(FileStorageUtils.getSavePath(user.getAccountName()));

FileStorageUtils.deleteRecursively(tempDir, storageManager);
FileStorageUtils.deleteRecursively(saveDir, storageManager);
}

private void removeAccount(Account account, AccountManager accountManager) {
try {
AccountManagerFuture<Boolean> accountRemoval = accountManager.removeAccount(account, this, null);
boolean removal = accountRemoval.getResult();

if (!removal) {
Log_OC.e(this, "Account removal of " + account.name + " failed!");
}
} catch (Exception e) {
Log_OC.e(this, "Account removal of " + account.name + " failed!", e);
}
}

@Nullable
private OwnCloudClient createClient(Account account) {
OwnCloudClient client = null;
private Optional<OwnCloudClient> createClient(User user) {
try {
OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount,
MainApp.getAppContext());
Context context = MainApp.getAppContext();
OwnCloudClientManager factory = OwnCloudClientManagerFactory.getDefaultSingleton();
OwnCloudClient client = factory.getClientFor(user.toOwnCloudAccount(), context);
return Optional.of(client);
} catch (Exception e) {
Log_OC.e(this, "Could not create client", e);
}
return client;
}

@Override
public void run(AccountManagerFuture<Boolean> future) {
if (future.isDone()) {
EventBus.getDefault().post(new AccountRemovedEvent());
return Optional.empty();
}
}
}
Loading

0 comments on commit 4616b0d

Please sign in to comment.