Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwurstsalat <mailtrash@posteo.de>2023-11-26 19:48:16 +0300
committerwurstsalat <mailtrash@posteo.de>2023-11-26 19:56:12 +0300
commit66c8ce2fd8a753073160d1adcceb9e9eca19760a (patch)
tree77c7e6ee1bc70bfce933aa37616693a255ed3932
parent59f681ba7afeb89e2398aefde495a0f47988d966 (diff)
imprv: Add DBMigration dialog
-rw-r--r--gajim/common/storage/archive/storage.py12
-rw-r--r--gajim/data/gui/db_migration.ui219
-rw-r--r--gajim/gtk/builder.pyi8
-rw-r--r--gajim/gtk/const.py1
-rw-r--r--gajim/gtk/db_migration.py93
5 files changed, 330 insertions, 3 deletions
diff --git a/gajim/common/storage/archive/storage.py b/gajim/common/storage/archive/storage.py
index 51155bc9e..f3f15b486 100644
--- a/gajim/common/storage/archive/storage.py
+++ b/gajim/common/storage/archive/storage.py
@@ -33,7 +33,7 @@ from gajim.common.const import MAX_MESSAGE_CORRECTION_DELAY
from gajim.common.modules.contacts import GroupchatContact
from gajim.common.storage.archive.const import MessageState
from gajim.common.storage.archive.const import MessageType
-# from gajim.common.storage.archive.migration_v8 import MigrationV8
+from gajim.common.storage.archive.migration_v8 import MigrationV8
from gajim.common.storage.archive.statements import ARCHIVE_CREATE_STMT
from gajim.common.storage.archive.statements import FIND_CORRECTED_MSG_STMT
from gajim.common.storage.archive.statements import \
@@ -66,6 +66,8 @@ from gajim.common.storage.base import SqliteStorage
from gajim.common.storage.base import timeit
from gajim.common.storage.base import VALUE_MISSING
+from gajim.gtk.util import open_window
+
CURRENT_USER_VERSION = 7
log = logging.getLogger('gajim.c.storage.archive')
@@ -190,8 +192,12 @@ class MessageArchiveStorage(SqliteStorage):
]
self._execute_multiple(statements)
- # if user_version < 8:
- # MigrationV8(self._con).run()
+ if user_version < 8:
+ open_window(
+ 'DBMigration',
+ migration_routine=MigrationV8,
+ db_connection=self._con,
+ db_path=self._path)
@staticmethod
def _like(search_str: str) -> str:
diff --git a/gajim/data/gui/db_migration.ui b/gajim/data/gui/db_migration.ui
new file mode 100644
index 000000000..adcb61593
--- /dev/null
+++ b/gajim/data/gui/db_migration.ui
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <object class="GtkStack" id="stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">crossfade</property>
+ <property name="interpolate-size">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Database Migration</property>
+ <style>
+ <class name="large-header"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Your chat history is being migrated.
+This may take a while…</property>
+ <property name="justify">center</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinner">
+ <property name="width-request">42</property>
+ <property name="height-request">42</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="active">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="status_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="max-width-chars">52</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">migration-page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Database Migration</property>
+ <style>
+ <class name="large-header"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">dialog-error-symbolic</property>
+ <property name="icon_size">6</property>
+ <style>
+ <class name="error-color"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="error_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="max-width-chars">52</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">_Close</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <signal name="clicked" handler="_on_close_button_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">error-page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Database Migration</property>
+ <style>
+ <class name="large-header"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">feather-check-symbolic</property>
+ <property name="icon_size">6</property>
+ <style>
+ <class name="error-color"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Your chat history database has been migrated successfully.</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="max-width-chars">52</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">success-page</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gajim/gtk/builder.pyi b/gajim/gtk/builder.pyi
index 0e46cffe2..d87717fe6 100644
--- a/gajim/gtk/builder.pyi
+++ b/gajim/gtk/builder.pyi
@@ -315,6 +315,12 @@ class ContactTooltipBuilder(Builder):
resources_box: Gtk.Box
+class DbMigrationBuilder(Builder):
+ stack: Gtk.Stack
+ status_label: Gtk.Label
+ error_label: Gtk.Label
+
+
class EmojiChooserBuilder(Builder):
box: Gtk.Box
search: Gtk.SearchEntry
@@ -1019,6 +1025,8 @@ def get_builder(file_name: Literal['contact_info.ui'], widgets: list[str] = ...)
@overload
def get_builder(file_name: Literal['contact_tooltip.ui'], widgets: list[str] = ...) -> ContactTooltipBuilder: ... # noqa
@overload
+def get_builder(file_name: Literal['db_migration.ui'], widgets: list[str] = ...) -> DbMigrationBuilder: ... # noqa
+@overload
def get_builder(file_name: Literal['emoji_chooser.ui'], widgets: list[str] = ...) -> EmojiChooserBuilder: ... # noqa
@overload
def get_builder(file_name: Literal['exception_dialog.ui'], widgets: list[str] = ...) -> ExceptionDialogBuilder: ... # noqa
diff --git a/gajim/gtk/const.py b/gajim/gtk/const.py
index b2bd9d6e7..84516fbc6 100644
--- a/gajim/gtk/const.py
+++ b/gajim/gtk/const.py
@@ -147,6 +147,7 @@ WINDOW_MODULES = {
'AddContact': 'gajim.gtk.add_contact',
'AdHocCommands': 'gajim.gtk.adhoc',
'AdvancedConfig': 'gajim.gtk.advanced_config',
+ 'DBMigration': 'gajim.gtk.db_migration',
'BlockingList': 'gajim.gtk.blocking',
'Bookmarks': 'gajim.gtk.bookmarks',
'CertificateDialog': 'gajim.gtk.certificate_dialog',
diff --git a/gajim/gtk/db_migration.py b/gajim/gtk/db_migration.py
new file mode 100644
index 000000000..307d81cf9
--- /dev/null
+++ b/gajim/gtk/db_migration.py
@@ -0,0 +1,93 @@
+# This file is part of Gajim.
+#
+# Gajim 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; version 3 only.
+#
+# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import annotations
+
+from typing import Any
+
+import logging
+import shutil
+import time
+from collections.abc import Callable
+from pathlib import Path
+from sqlite3 import Connection
+
+from gi.repository import Gdk
+from gi.repository import Gtk
+
+from gajim.common import app
+from gajim.common.helpers import get_random_string
+from gajim.common.i18n import _
+
+from gajim.gtk.builder import get_builder
+
+log = logging.getLogger('gajim.gtk.db_migration')
+
+
+class DBMigration(Gtk.ApplicationWindow):
+ def __init__(
+ self,
+ migration_routine: Callable[..., Any],
+ db_connection: Connection,
+ db_path: Path,
+ ) -> None:
+ Gtk.ApplicationWindow.__init__(self)
+ self.set_application(app.app)
+ self.set_position(Gtk.WindowPosition.CENTER)
+ self.set_show_menubar(False)
+ self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
+ self.set_resizable(True)
+ self.set_name('DBMigration')
+ self.set_title(_('Database Migration'))
+
+ self.set_resizable(False)
+ self.set_modal(True)
+ self.set_deletable(False)
+
+ self._ui = get_builder('db_migration.ui')
+ self.add(self._ui.stack)
+ self._ui.connect_signals(self)
+
+ self._ui.status_label.set_text(_('Creating backup…'))
+
+ self.connect('destroy', self._on_destroy)
+ self.show_all()
+
+ random_string = get_random_string(6)
+ db_backup_path = db_path.parent / f'{db_path.name}.{random_string}.old'
+ try:
+ shutil.copy(db_path, db_backup_path)
+ except PermissionError as e:
+ self._ui.error_label.set_text(
+ _('Could not create backup file: %s') % e
+ )
+ self._ui.stack.set_visible_child_name('error-page')
+ self._show_error_page()
+ return
+
+ self._ui.status_label.set_text(_('Migrating chat history database…'))
+ migration_routine(db_connection).run()
+
+ self._ui.stack.set_visible_child_name('success-page')
+ time.sleep(5)
+ self.destroy()
+
+ def _show_error_page(self) -> None:
+ self._ui.stack.set_visible_child_name('error-page')
+
+ def _on_close_button_clicked(self, _button: Gtk.Button) -> None:
+ self.destroy()
+
+ def _on_destroy(self, _widget: DBMigration) -> None:
+ app.check_finalize(self)