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

Commit 91ca9f55 authored by Fahim Salam Chowdhury's avatar Fahim Salam Chowdhury 👽
Browse files

Merge branch '1147-Migrate_old_table_notes' into 'main'

1147-Migrate_old_table_notes

See merge request !39
parents c17d0303 0307a41e
Loading
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -175,6 +175,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
                executor.submit(() -> {
                    try {
                        final var account = mainViewModel.getLocalAccountByAccountName(SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext()).name);
                        mainViewModel.migrateOldNotes(account);

                        runOnUiThread(() -> mainViewModel.postCurrentAccount(account));
                    } catch (NextcloudFilesAppAccountNotFoundException e) {
                        // Verbose log output for https://github.com/stefan-niedermann/nextcloud-notes/issues/1256
+5 −0
Original line number Diff line number Diff line
@@ -663,4 +663,9 @@ public class MainViewModel extends AndroidViewModel {
        final var lower = input.toLowerCase(Locale.ROOT);
        return lower.contains("failed to connect") && lower.contains("network is unreachable");
    }

    public void migrateOldNotes(@NonNull Account account) {
        repo.migrateOldNotesIfPossible(account.getId());
    }

}
 No newline at end of file
+19 −4
Original line number Diff line number Diff line
package it.niedermann.owncloud.notes.persistence;

import android.content.Context;
import trikita.log.Log;

import androidx.annotation.NonNull;
import androidx.room.Database;
@@ -10,6 +9,8 @@ import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.sqlite.db.SupportSQLiteDatabase;

import java.util.List;

import it.niedermann.owncloud.notes.persistence.dao.AccountDao;
import it.niedermann.owncloud.notes.persistence.dao.CategoryOptionsDao;
import it.niedermann.owncloud.notes.persistence.dao.NoteDao;
@@ -35,6 +36,7 @@ import it.niedermann.owncloud.notes.persistence.migration.Migration_20_21;
import it.niedermann.owncloud.notes.persistence.migration.Migration_21_22;
import it.niedermann.owncloud.notes.persistence.migration.Migration_22_23;
import it.niedermann.owncloud.notes.persistence.migration.Migration_9_10;
import trikita.log.Log;

@Database(
        entities = {
@@ -105,4 +107,17 @@ public abstract class NotesDatabase extends RoomDatabase {
    public abstract WidgetSingleNoteDao getWidgetSingleNoteDao();

    public abstract WidgetNotesListDao getWidgetNotesListDao();

    /**
     * retrieve notes from old `NOTES` table for migration.
     * If we try to follow the *ROOM way* (entity, dao) for `NOTES` table, the existing data will be removed.
     * So we have to retrieve old entries via raw sql commands.
     *
     * <a href="https://gitlab.e.foundation/e/os/backlog/-/issues/1147">Check for more details</a>
     * @return list of old notes entries
     */
    @NonNull
    public List<OldNote> getNotesFromOldTable() {
        return OldNoteRetriever.getNotesFromOldTable(this);
    }
}
+67 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.ConnectivityManager;
import android.text.TextUtils;

import trikita.log.Log;

import androidx.annotation.AnyThread;
@@ -79,6 +80,8 @@ import retrofit2.Call;
@SuppressWarnings("UnusedReturnValue")
public class NotesRepository {

    private static final String PREF_KEY_MIGRATION_DONE = "old_note_migration_done";

    private static final String TAG = NotesRepository.class.getSimpleName();

    private static NotesRepository instance;
@@ -959,4 +962,68 @@ public class NotesRepository {
    public void updateDisplayName(long id, @Nullable String displayName) {
        db.getAccountDao().updateDisplayName(id, displayName);
    }

    /**
     * migrate old notes to latest note table.
     * if the migration is already done, skip.
     * link the provided account to the migrated notes, as old notes don't have account entry to them.
     *
     *  * <a href="https://gitlab.e.foundation/e/os/backlog/-/issues/1147">Check for more details</a>.
     * @param accountId which will be used to link migrated notes to account
     */
    @AnyThread
    public void migrateOldNotesIfPossible(long accountId) {
        if (isMigrationDone()) {
            return;
        }

        migrateOldNotes(accountId);
    }

    private void migrateOldNotes(long accountId) {
        try {
            executor.submit(() -> {
                List<OldNote> oldNotes = db.getNotesFromOldTable();
                if (oldNotes.isEmpty()) {
                    updatePrefOnMigrationDone();
                    return;
                }

                for (OldNote oldNote : oldNotes) {
                    if (oldNote == null || isNoteAlreadyExistsInNewTable(oldNote)) {
                        continue;
                    }

                    addNewNote(accountId, oldNote);
                }

                updatePrefOnMigrationDone();
            });
        } catch (Exception e) {
            Log.e(TAG, "An exception has been caught", e);
        }
    }

    private boolean isNoteAlreadyExistsInNewTable(@NonNull OldNote oldNote) {
        return db.getNoteDao().countByTitleAndContent(oldNote.getTitle(), oldNote.getContent()) > 0;
    }

    private void addNewNote(long accountId, @NonNull OldNote oldNote) {
        Note newNote = new Note(oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.getCategory(), oldNote.getFavorite(), oldNote.getETag());
        newNote.setStatus(oldNote.getStatus());
        newNote.setAccountId(accountId);
        db.getNoteDao().addNote(newNote);
    }

    private boolean isMigrationDone() {
        final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
        return sharedPreferences.getBoolean(PREF_KEY_MIGRATION_DONE, false);
    }

    private void updatePrefOnMigrationDone() {
        final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
        sharedPreferences.edit()
                .putBoolean(PREF_KEY_MIGRATION_DONE, true)
                .apply();
    }
}
+149 −0
Original line number Diff line number Diff line
/*
 * Copyright MURENA SAS 2023
 * 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 it.niedermann.owncloud.notes.persistence;


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

import java.io.Serializable;
import java.util.Calendar;

import it.niedermann.owncloud.notes.shared.model.DBStatus;

/**
 * Entity representation for `NOTES` table.
 * This is added to migrate old `NOTES` items to new `Note` table.
 *
 * <a href="https://gitlab.e.foundation/e/os/backlog/-/issues/1147">Check for more details</a>
 */
public class OldNote implements Serializable {

    private long id;

    private long remoteId;

    @NonNull
    private DBStatus status;

    @NonNull
    private String title;

    @Nullable
    private Calendar modified;

    @NonNull
    private String content;

    private boolean favorite = false;

    @NonNull
    private String category = "";

    @Nullable
    private String eTag;

    public OldNote(long id, long remoteId, @Nullable Calendar modified, @NonNull String title, @NonNull String content, boolean favorite, @NonNull String category, @Nullable String eTag, @NonNull DBStatus status) {
        this.id = id;
        this.remoteId = remoteId;
        this.status = status;
        this.title = title;
        this.modified = modified;
        this.content = content;
        this.favorite = favorite;
        this.category = category;
        this.eTag = eTag;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getRemoteId() {
        return remoteId;
    }

    public void setRemoteId(long remoteId) {
        this.remoteId = remoteId;
    }

    @NonNull
    public DBStatus getStatus() {
        return status;
    }

    public void setStatus(@NonNull DBStatus status) {
        this.status = status;
    }

    @NonNull
    public String getTitle() {
        return title;
    }

    public void setTitle(@NonNull String title) {
        this.title = title;
    }

    @Nullable
    public Calendar getModified() {
        return modified;
    }

    public void setModified(@Nullable Calendar modified) {
        this.modified = modified;
    }

    @NonNull
    public String getContent() {
        return content;
    }

    public void setContent(@NonNull String content) {
        this.content = content;
    }

    public boolean getFavorite() {
        return favorite;
    }

    public void setFavorite(boolean favorite) {
        this.favorite = favorite;
    }

    @NonNull
    public String getCategory() {
        return category;
    }

    public void setCategory(@NonNull String category) {
        this.category = category;
    }

    @Nullable
    public String getETag() {
        return eTag;
    }

    public void setETag(@Nullable String eTag) {
        this.eTag = eTag;
    }
}
Loading