Browse Source

re-add account migration, to get userId

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 6 năm trước cách đây
mục cha
commit
51d7ea8cd6

+ 145 - 1
src/main/java/com/owncloud/android/authentication/AccountUtils.java

@@ -23,12 +23,20 @@ import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.net.Uri;
 import android.preference.PreferenceManager;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.UserInfo;
 import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
 import com.owncloud.android.ui.activity.ManageAccountsActivity;
 
 import androidx.annotation.NonNull;
@@ -38,10 +46,11 @@ import androidx.annotation.Nullable;
  * Helper class for dealing with accounts.
  */
 public final class AccountUtils {
+    private static final String TAG = AccountUtils.class.getSimpleName();
     private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account";
 
     public static final int ACCOUNT_VERSION = 1;
-    //public static final int ACCOUNT_VERSION_WITH_PROPER_ID = 2;
+    public static final int ACCOUNT_VERSION_WITH_PROPER_ID = 2;
     public static final String ACCOUNT_USES_STANDARD_PASSWORD = "ACCOUNT_USES_STANDARD_PASSWORD";
 
     private AccountUtils() {
@@ -200,4 +209,139 @@ public final class AccountUtils {
     public static boolean hasSearchSupport(Account account) {
         return getServerVersion(account).isSearchSupported();
     }
+
+    /**
+     * Update the accounts in AccountManager to meet the current version of accounts expected by the app, if needed.
+     * <p>
+     * Introduced to handle a change in the structure of stored account names needed to allow different OC servers in
+     * the same domain, but not in the same path.
+     *
+     * @param context Used to access the AccountManager.
+     */
+    public static void updateAccountVersion(Context context) {
+        Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(context);
+        AccountManager accountMgr = AccountManager.get(context);
+
+        if (currentAccount != null) {
+            String currentAccountVersion = accountMgr.getUserData(currentAccount, Constants.KEY_OC_ACCOUNT_VERSION);
+
+            if (!String.valueOf(ACCOUNT_VERSION_WITH_PROPER_ID).equalsIgnoreCase(currentAccountVersion)) {
+                Log_OC.i(TAG, "Upgrading accounts to account version #" + ACCOUNT_VERSION_WITH_PROPER_ID);
+
+                Account[] ocAccounts = accountMgr.getAccountsByType(MainApp.getAccountType(context));
+                String serverUrl;
+                String username;
+                String displayName;
+                String newAccountName;
+                Account newAccount;
+
+                for (Account account : ocAccounts) {
+                    // build new account name
+                    serverUrl = accountMgr.getUserData(account, Constants.KEY_OC_BASE_URL);
+
+                    // update user name
+                    try {
+                        OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
+                        OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton()
+                            .getClientFor(ocAccount, context);
+
+                        GetRemoteUserInfoOperation remoteUserNameOperation = new GetRemoteUserInfoOperation();
+                        RemoteOperationResult result = remoteUserNameOperation.execute(client);
+
+                        if (result.isSuccess()) {
+                            UserInfo userInfo = (UserInfo) result.getData().get(0);
+                            username = userInfo.id;
+                            displayName = userInfo.displayName;
+                        } else {
+                            // skip account, try it next time
+                            Log_OC.e(TAG, "Error while getting username for account: " + account.name);
+                            continue;
+                        }
+                    } catch (Exception e) {
+                        Log_OC.e(TAG, "Error while getting username: " + e.getMessage());
+                        continue;
+                    }
+
+                    newAccountName = com.owncloud.android.lib.common.accounts.AccountUtils.
+                        buildAccountName(Uri.parse(serverUrl), username);
+
+                    // migrate to a new account, if needed
+                    if (!newAccountName.equals(account.name)) {
+                        newAccount = migrateAccount(context, currentAccount, accountMgr, serverUrl, newAccountName,
+                                                    account);
+
+                    } else {
+                        // servers which base URL is in the root of their domain need no change
+                        Log_OC.d(TAG, account.name + " needs no upgrade ");
+                        newAccount = account;
+                    }
+
+                    accountMgr.setUserData(newAccount, Constants.KEY_DISPLAY_NAME, displayName);
+                    accountMgr.setUserData(newAccount, Constants.KEY_USER_ID, username);
+
+                    // at least, upgrade account version
+                    Log_OC.d(TAG, "Setting version " + ACCOUNT_VERSION_WITH_PROPER_ID + " to " + newAccountName);
+                    accountMgr.setUserData(newAccount, Constants.KEY_OC_ACCOUNT_VERSION,
+                                           Integer.toString(ACCOUNT_VERSION_WITH_PROPER_ID));
+                }
+            }
+        }
+    }
+
+    @NonNull
+    private static Account migrateAccount(Context context, Account currentAccount, AccountManager accountMgr,
+                                          String serverUrl, String newAccountName, Account account) {
+
+        Log_OC.d(TAG, "Upgrading " + account.name + " to " + newAccountName);
+
+        // create the new account
+        Account newAccount = new Account(newAccountName, MainApp.getAccountType(context));
+        String password = accountMgr.getPassword(account);
+        accountMgr.addAccountExplicitly(newAccount, (password != null) ? password : "", null);
+
+        // copy base URL
+        accountMgr.setUserData(newAccount, Constants.KEY_OC_BASE_URL, serverUrl);
+
+        // copy server version
+        accountMgr.setUserData(
+            newAccount,
+            Constants.KEY_OC_VERSION,
+            accountMgr.getUserData(account, Constants.KEY_OC_VERSION)
+        );
+
+        // copy cookies
+        accountMgr.setUserData(
+            newAccount,
+            Constants.KEY_COOKIES,
+            accountMgr.getUserData(account, Constants.KEY_COOKIES)
+        );
+
+        // copy type of authentication
+        final String isSamlStr = accountMgr.getUserData(account, Constants.KEY_SUPPORTS_SAML_WEB_SSO);
+        if (Boolean.parseBoolean(isSamlStr)) {
+            accountMgr.setUserData(newAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE");
+        }
+
+        final String isOauthStr = accountMgr.getUserData(account, Constants.KEY_SUPPORTS_OAUTH2);
+        if (Boolean.parseBoolean(isOauthStr)) {
+            accountMgr.setUserData(newAccount, Constants.KEY_SUPPORTS_OAUTH2, "TRUE");
+        }
+
+        /* TODO - study if it's possible to run this method in a background thread to copy the authToken
+        if (isOAuth || isSaml) {
+            accountMgr.setAuthToken(newAccount, mAuthTokenType, mAuthToken);
+        }
+        */
+
+        // don't forget the account saved in preferences as the current one
+        if (currentAccount.name.equals(account.name)) {
+            AccountUtils.setCurrentOwnCloudAccount(context, newAccountName);
+        }
+
+        // remove the old account
+        accountMgr.removeAccount(account, null, null);
+
+        // will assume it succeeds, not a big deal otherwise
+        return newAccount;
+    }
 }

+ 9 - 6
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -1963,10 +1963,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 }
             }
 
-            // include account version with the new account
-            mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
-                    Integer.toString(AccountUtils.ACCOUNT_VERSION));
-
             /// add the new account as default in preferences, if there is none already
             Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);
             if (defaultAccount == null) {
@@ -1995,11 +1991,18 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                     UserInfo userInfo = (UserInfo) authResult.getData().get(0);
                     mAccountMgr.setUserData(mAccount, Constants.KEY_DISPLAY_NAME, userInfo.getDisplayName());
                     mAccountMgr.setUserData(mAccount, Constants.KEY_USER_ID, userInfo.getId());
+                    mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
+                                            Integer.toString(AccountUtils.ACCOUNT_VERSION_WITH_PROPER_ID));
+
                 } catch (ClassCastException c) {
-                    Log_OC.w(TAG, "Couldn't get display name for " + username);
+                    mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
+                                            Integer.toString(AccountUtils.ACCOUNT_VERSION));
+                    Log_OC.w(TAG, "Couldn't get display name and user id for " + username);
                 }
             } else {
-                Log_OC.w(TAG, "Couldn't get display name for " + username);
+                mAccountMgr.setUserData(mAccount, Constants.KEY_OC_ACCOUNT_VERSION,
+                                        Integer.toString(AccountUtils.ACCOUNT_VERSION));
+                Log_OC.w(TAG, "Couldn't get display name and user id for " + username);
             }
 
             if (isSaml) {

+ 9 - 1
src/main/java/com/owncloud/android/ui/activity/FileActivity.java

@@ -39,6 +39,7 @@ import android.view.View;
 import com.google.android.material.snackbar.Snackbar;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.OCFile;
@@ -153,7 +154,8 @@ public abstract class FileActivity extends DrawerActivity
         mHandler = new Handler();
         mFileOperationsHelper = new FileOperationsHelper(this);
         Account account = null;
-        if(savedInstanceState != null) {
+
+        if (savedInstanceState != null) {
             mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
             mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
             mFileOperationsHelper.setOpIdWaitingFor(
@@ -167,6 +169,12 @@ public abstract class FileActivity extends DrawerActivity
                     false);
         }
 
+        Thread t = new Thread(() -> {
+            // best place, before any access to AccountManager or database
+            AccountUtils.updateAccountVersion(this);
+        });
+        t.start();
+
         setAccount(account, savedInstanceState != null);
 
         mOperationsServiceConnection = new OperationsServiceConnection();