Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c914c8de authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

fix: allow cloud and local accounts to be reused instead of creating new ones

There are three behavioural changes implemented in this MR:

1. For local accounts

Because of the outage, clicking on the USE LOCAL NOTES button was creating multiple local accounts inside the Notes database.

LocalAccountViewModel now checks if there's any existing local account, and if there's any, it reuses the account instead of creating a new one.

If there's no local account found in the database, only then a new local account is created and used for saving the notes.

2. For cloud accounts

Similar to the local account check, ImportAccountActivity checks for any existing online accounts with the same user ID. If it finds any, it reuses the account. Otherwise, a new online account is created in the database.

3. Clean-up of accounts in database migration

During the outage, users may have clicked on the two buttons — CHOOSE ACCOUNT or USE LOCAL NOTES — numerous times to get it past. Hence, there will be multiple accounts created which will have no notes associated with them. Only the accounts created before the outage will have notes associated with.

This database migration will delete the accounts (possibly created during the outage) without any notes.
parent f6691ac9
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright e Foundation 2025
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package foundation.e.notes.migration

import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

/**
 * Deletes accounts without any associated notes.
 * */
class Migration_24_25 : Migration(24, 25) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL(
            """
                DELETE FROM Account WHERE id NOT IN (SELECT DISTINCT accountId FROM Note);
            """.trimIndent()
        )
    }
}
+12 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedExcepti
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import com.nextcloud.android.sso.exceptions.UnknownErrorException;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
import com.nextcloud.android.sso.ui.UiExceptionManager;

import java.net.HttpURLConnection;
@@ -120,8 +121,13 @@ public class ImportAccountActivity extends AppCompatActivity {
            AccountImporter.onActivityResult(requestCode, resultCode, data, ImportAccountActivity.this, ssoAccount -> {
                runOnUiThread(() -> binding.progressCircular.setVisibility(View.VISIBLE));

                SingleAccountHelper.setCurrentAccount(getApplicationContext(), ssoAccount.name);
                executor.submit(() -> {
                    if (isExistingAccount(ssoAccount)) {
                        finishActivity(false);
                        return;
                    }

                    SingleAccountHelper.setCurrentAccount(getApplicationContext(), ssoAccount.name);
                    Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId);
                    try {
                        Log.i(TAG, "Loading capabilities for " + ssoAccount.name);
@@ -192,6 +198,10 @@ public class ImportAccountActivity extends AppCompatActivity {
        }
    }

    private boolean isExistingAccount(SingleSignOnAccount ssoAccount) {
        return importAccountViewModel.isExistingAccount(ssoAccount);
    }

    private void finishActivity(boolean isLocal) {
        setResult(RESULT_OK);
        Intent intent = new Intent(ImportAccountActivity.this, MainActivity.class);
@@ -243,7 +253,7 @@ public class ImportAccountActivity extends AppCompatActivity {

    private void handleLocalAccount() {
        binding.addLocalButton.setOnClickListener(view -> {
            localAccountViewModel.logInToLocalAccount(getAddLocalAccountCallback());
            localAccountViewModel.logInToLocalAccount(getApplicationContext(), getAddLocalAccountCallback());
        });
    }

+12 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@ import androidx.annotation.Nullable;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;

import com.nextcloud.android.sso.model.SingleSignOnAccount;

import it.niedermann.owncloud.notes.persistence.NotesRepository;
import it.niedermann.owncloud.notes.persistence.entity.Account;
import it.niedermann.owncloud.notes.shared.model.Capabilities;
@@ -26,4 +28,14 @@ public class ImportAccountViewModel extends AndroidViewModel {
    public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities, @Nullable String displayName, @NonNull IResponseCallback<Account> callback) {
        return repo.addAccount(url, username, accountName, capabilities, displayName, callback);
    }

    protected boolean isExistingAccount(@NonNull SingleSignOnAccount ssoAccount) {
        Account account = repo.getAccountByName(ssoAccount.name);

        if (account == null) {
            return false;
        }

        return account.getUrl().equals(ssoAccount.url);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -823,7 +823,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A

    @Override
    public void onAddLocalAccountButtonClick() {
        localAccountViewModel.logInToLocalAccount(new IResponseCallback<>() {
        localAccountViewModel.logInToLocalAccount(getApplicationContext(), new IResponseCallback<>() {
            @Override
            public void onSuccess(@NonNull LocalAccountBundle result) {
                runOnUiThread(() -> {
+4 −2
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.List;

import foundation.e.notes.migration.Migration_23_24;
import foundation.e.notes.migration.Migration_24_25;
import it.niedermann.owncloud.notes.persistence.dao.AccountDao;
import it.niedermann.owncloud.notes.persistence.dao.CategoryOptionsDao;
import it.niedermann.owncloud.notes.persistence.dao.NoteDao;
@@ -46,7 +47,7 @@ import trikita.log.Log;
                CategoryOptions.class,
                SingleNoteWidgetData.class,
                NotesListWidgetData.class
        }, version = 24
        }, version = 25
)
@TypeConverters({Converters.class})
public abstract class NotesDatabase extends RoomDatabase {
@@ -82,7 +83,8 @@ public abstract class NotesDatabase extends RoomDatabase {
                        new Migration_20_21(),
                        new Migration_21_22(context),
                        new Migration_22_23(),
                        new Migration_23_24()
                        new Migration_23_24(),
                        new Migration_24_25()
                )
                .fallbackToDestructiveMigrationOnDowngrade()
                .fallbackToDestructiveMigration()
Loading