From f62ecc18f7f3a111450112dcd94a662f129e2da5 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 18:15:26 -0300 Subject: [PATCH 1/8] add the backup feature --- src/pilgrim/service/backup_service.py | 33 +++++++++++++++++++++ src/pilgrim/ui/screens/diary_list_screen.py | 12 ++++++++ src/pilgrim/ui/ui.py | 5 ++++ 3 files changed, 50 insertions(+) create mode 100644 src/pilgrim/service/backup_service.py diff --git a/src/pilgrim/service/backup_service.py b/src/pilgrim/service/backup_service.py new file mode 100644 index 0000000..8bc0bbb --- /dev/null +++ b/src/pilgrim/service/backup_service.py @@ -0,0 +1,33 @@ +import sqlite3 +import zipfile +from pathlib import Path + + +from pilgrim.utils.directory_manager import DirectoryManager + + +class BackupService: + def __init__(self, session): + self.session = session + + def create_backup(self): + db_path = DirectoryManager.get_database_path() + if not db_path.exists(): + raise FileNotFoundError("No Database Found") + conn = self.session.connection().connection + dump = "\n".join(line for line in conn.iterdump()) + filename = str(DirectoryManager.get_config_directory()) + "/backup.zip" + diaries_root_path = DirectoryManager.get_diaries_root() + + try: + with zipfile.ZipFile(filename, "w",zipfile.ZIP_DEFLATED) as zipf: + zipf.writestr("database.sql", dump) + if diaries_root_path.exists(): + for file_path in diaries_root_path.rglob('*'): + if file_path.is_file(): + arcname = file_path.relative_to(diaries_root_path.parent) + zipf.write(file_path, arcname=arcname) + return True, None + except Exception as e: + return False, str(e) + diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index b4912e9..d87ba93 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -14,6 +14,8 @@ from pilgrim.ui.screens.edit_diary_modal import EditDiaryModal from pilgrim.ui.screens.new_diary_modal import NewDiaryModal from pilgrim.ui.screens.edit_entry_screen import EditEntryScreen +from pilgrim.service.backup_service import BackupService + class DiaryListScreen(Screen): TITLE = "Pilgrim - Main" @@ -298,3 +300,13 @@ class DiaryListScreen(Screen): self.notify("Invalid diary ID") else: self.notify("Select a diary to open the settings") + + + def action_backup(self): + session = self.app.service_manager.get_session() + backup_service = BackupService(session) + if session: + result = backup_service.create_backup() + else: + self.notify("You must be logged in to perform this action") + self.notify(f"Backup result: {result}") diff --git a/src/pilgrim/ui/ui.py b/src/pilgrim/ui/ui.py index 5557993..ee613a9 100644 --- a/src/pilgrim/ui/ui.py +++ b/src/pilgrim/ui/ui.py @@ -37,6 +37,11 @@ class UIApp(App): "Open About Pilgrim", screen.action_about_cmd ) + yield SystemCommand( + "Backup Database", + "Backup the Database", + screen.action_backup + ) elif isinstance(screen, AboutScreen): yield SystemCommand( From 8cf5f7e46541e433503d0d99bf2a240fd62f73d3 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 18:39:08 -0300 Subject: [PATCH 2/8] Fix moved the backup service initialization inside the check for the session --- src/pilgrim/ui/screens/diary_list_screen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index d87ba93..a2b9b8b 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -304,8 +304,8 @@ class DiaryListScreen(Screen): def action_backup(self): session = self.app.service_manager.get_session() - backup_service = BackupService(session) if session: + backup_service = BackupService(session) result = backup_service.create_backup() else: self.notify("You must be logged in to perform this action") From 890fc470bb242881e5cddbf5a260a9cbaf9786ab Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 19:00:04 -0300 Subject: [PATCH 3/8] Change the filename variable to conform to the proper pathlike use --- src/pilgrim/service/backup_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pilgrim/service/backup_service.py b/src/pilgrim/service/backup_service.py index 8bc0bbb..4230ed8 100644 --- a/src/pilgrim/service/backup_service.py +++ b/src/pilgrim/service/backup_service.py @@ -16,7 +16,7 @@ class BackupService: raise FileNotFoundError("No Database Found") conn = self.session.connection().connection dump = "\n".join(line for line in conn.iterdump()) - filename = str(DirectoryManager.get_config_directory()) + "/backup.zip" + filename = DirectoryManager.get_config_directory() / "backup.zip" diaries_root_path = DirectoryManager.get_diaries_root() try: From 209099cc5e67200b09872ccbd818e9ecf7a2bccf Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 19:05:55 -0300 Subject: [PATCH 4/8] Add a error handling on backup operation --- src/pilgrim/service/backup_service.py | 2 +- src/pilgrim/ui/screens/diary_list_screen.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pilgrim/service/backup_service.py b/src/pilgrim/service/backup_service.py index 4230ed8..eb8facc 100644 --- a/src/pilgrim/service/backup_service.py +++ b/src/pilgrim/service/backup_service.py @@ -27,7 +27,7 @@ class BackupService: if file_path.is_file(): arcname = file_path.relative_to(diaries_root_path.parent) zipf.write(file_path, arcname=arcname) - return True, None + return True, filename except Exception as e: return False, str(e) diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index a2b9b8b..059abb7 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -306,7 +306,13 @@ class DiaryListScreen(Screen): session = self.app.service_manager.get_session() if session: backup_service = BackupService(session) - result = backup_service.create_backup() + result_operation,result_data = backup_service.create_backup() else: self.notify("You must be logged in to perform this action") - self.notify(f"Backup result: {result}") + if result_operation: + self.notify(f"Backup result: {result_data}") + else: + self.notify(f"Error performing backup {result_data}") + raise Exception("Error performing backup") + self.app.exit() + From 17371088da67726d0dda02834a15c54affc96f0b Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 19:21:47 -0300 Subject: [PATCH 5/8] Changed the way it uses the database connection to be more robust --- src/pilgrim/service/backup_service.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pilgrim/service/backup_service.py b/src/pilgrim/service/backup_service.py index eb8facc..930bddc 100644 --- a/src/pilgrim/service/backup_service.py +++ b/src/pilgrim/service/backup_service.py @@ -14,8 +14,11 @@ class BackupService: db_path = DirectoryManager.get_database_path() if not db_path.exists(): raise FileNotFoundError("No Database Found") - conn = self.session.connection().connection - dump = "\n".join(line for line in conn.iterdump()) + + with self.session.connection() as conn: + raw_conn = conn.connection + dump = dump = "\n".join(line for line in raw_conn.iterdump()) + filename = DirectoryManager.get_config_directory() / "backup.zip" diaries_root_path = DirectoryManager.get_diaries_root() From 7c950b93ab7184ff588b30c9b1153683339a996f Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Miranda Date: Thu, 24 Jul 2025 19:23:40 -0300 Subject: [PATCH 6/8] Update src/pilgrim/ui/screens/diary_list_screen.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/pilgrim/ui/screens/diary_list_screen.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index 059abb7..dcc386b 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -306,13 +306,10 @@ class DiaryListScreen(Screen): session = self.app.service_manager.get_session() if session: backup_service = BackupService(session) - result_operation,result_data = backup_service.create_backup() + result_operation, result_data = backup_service.create_backup() + if result_operation: + self.notify(f"Backup result: {result_data}") + else: + self.notify(f"Error performing backup: {result_data}") else: self.notify("You must be logged in to perform this action") - if result_operation: - self.notify(f"Backup result: {result_data}") - else: - self.notify(f"Error performing backup {result_data}") - raise Exception("Error performing backup") - self.app.exit() - From bb9457978c99bb6a29062e1c7a2a0d860adaf716 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Miranda Date: Thu, 24 Jul 2025 19:31:13 -0300 Subject: [PATCH 7/8] Update src/pilgrim/service/backup_service.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/pilgrim/service/backup_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pilgrim/service/backup_service.py b/src/pilgrim/service/backup_service.py index 930bddc..e01d432 100644 --- a/src/pilgrim/service/backup_service.py +++ b/src/pilgrim/service/backup_service.py @@ -17,7 +17,7 @@ class BackupService: with self.session.connection() as conn: raw_conn = conn.connection - dump = dump = "\n".join(line for line in raw_conn.iterdump()) + dump = "\n".join(line for line in raw_conn.iterdump()) filename = DirectoryManager.get_config_directory() / "backup.zip" diaries_root_path = DirectoryManager.get_diaries_root() From c3397ab98287f015d53e79b725bcdfa9536c615f Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Thu, 24 Jul 2025 19:36:03 -0300 Subject: [PATCH 8/8] Remove the wrong error message and made the program exit if no session is found --- src/pilgrim/ui/screens/diary_list_screen.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index dcc386b..5407609 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -312,4 +312,6 @@ class DiaryListScreen(Screen): else: self.notify(f"Error performing backup: {result_data}") else: - self.notify("You must be logged in to perform this action") + self.notify("Error: Session not found",severity="error") + self.app.exit() +