about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRicky Kresslein <rk@lakoliu.com>2022-09-22 21:28:50 +0200
committerRicky Kresslein <rk@lakoliu.com>2022-09-22 21:28:50 +0200
commit83e992c2077a4fb5281a461c74fc6f7265a24bde (patch)
tree8f7199a9bf49fb41defd0c61e7d4fb307a74da30
parente72813df2bb343ec4ce683baa7af2befc1ae6f80 (diff)
downloadFurtherance-83e992c2077a4fb5281a461c74fc6f7265a24bde.tar.zst
Backup database
-rw-r--r--Cargo.lock17
-rwxr-xr-xCargo.toml2
-rwxr-xr-xsrc/application.rs44
-rwxr-xr-xsrc/database.rs10
-rwxr-xr-xsrc/gtk/window.ui14
5 files changed, 72 insertions, 15 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7006d82..496cb94 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -647,18 +647,18 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
  "ahash",
 ]
 
 [[package]]
 name = "hashlink"
-version = "0.7.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
+checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
 dependencies = [
  "hashbrown",
 ]
@@ -777,9 +777,9 @@ dependencies = [
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.24.2"
+version = "0.25.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
+checksum = "9f0455f2c1bc9a7caa792907026e469c1d91761fb0ea37cbb16427c77280cf35"
 dependencies = [
  "pkg-config",
  "vcpkg",
@@ -1062,16 +1062,15 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 
 [[package]]
 name = "rusqlite"
-version = "0.27.0"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a"
+checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a"
 dependencies = [
  "bitflags",
  "fallible-iterator",
  "fallible-streaming-iterator",
  "hashlink",
  "libsqlite3-sys",
- "memchr",
  "smallvec",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index d2a7987..bf0b557 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ log = "0.4"
 num-derive = "0.3.3"
 num-traits = "0.2.14"
 once_cell = "1.12.0"
-rusqlite = "0.27.0"
+rusqlite = { version = "0.28.0", features = ["backup"] }
 serde = { version = "1.0", features = ["derive"] }
 
 [dependencies.gtk]
diff --git a/src/application.rs b/src/application.rs
index bfa53e2..b0972ec 100755
--- a/src/application.rs
+++ b/src/application.rs
@@ -131,6 +131,12 @@ impl FurtheranceApplication {
         }));
         self.add_action(&about_action);
 
+        let backup_database_action = gio::SimpleAction::new("backup-database", None);
+        backup_database_action.connect_activate(clone!(@weak self as app => move |_, _| {
+            app.backup_database();
+        }));
+        self.add_action(&backup_database_action);
+
         let discard_idle_action = gio::SimpleAction::new("discard-idle-action", None);
         discard_idle_action.connect_activate(clone!(@weak self as app => move |_, _| {
             let window = FurtheranceWindow::default();
@@ -318,6 +324,44 @@ impl FurtheranceApplication {
         self.withdraw_notification("idle");
         self.send_notification(Some("pomodoro"), &notification);
     }
+
+    pub fn backup_database(&self) {
+        let window = self.active_window().unwrap();
+        let dialog = gtk::FileChooserDialog::new(
+            Some(&gettext("Backup Database")),
+            Some(&window),
+            gtk::FileChooserAction::Save,
+            &[
+                (&gettext("Cancel"), gtk::ResponseType::Reject),
+                (&gettext("Save"), gtk::ResponseType::Accept),
+            ]
+        );
+        dialog.set_modal(true);
+
+        // Set a filter to show only SQLite files
+        let filter = gtk::FileFilter::new();
+        gtk::FileFilter::set_name(&filter, Some("*.db"));
+        filter.add_mime_type("application/x-sqlite3");
+        dialog.add_filter(&filter);
+        dialog.set_current_name("furtherance_bkup.db");
+
+        dialog.connect_response(
+            clone!(@strong dialog, @weak self as this => move |filechooser, resp| {
+                if resp == gtk::ResponseType::Accept {
+                    if let Some(path) = filechooser.file().and_then(|file| file.path()) {
+                        let path = &path.to_string_lossy();
+                        let _bkup = database::backup_db(path.to_string());
+                    }
+                    dialog.close();
+                } else {
+                    dialog.close();
+                }
+            }),
+        );
+
+        dialog.show();
+
+    }
 }
 
 impl Default for FurtheranceApplication {
diff --git a/src/database.rs b/src/database.rs
index 6c2649c..090814e 100755
--- a/src/database.rs
+++ b/src/database.rs
@@ -16,10 +16,11 @@
 
 use chrono::{DateTime, Local};
 use directories::ProjectDirs;
-use rusqlite::{Connection, Result};
+use rusqlite::{Connection, Result, backup};
 use std::convert::TryFrom;
 use std::fs::create_dir_all;
 use std::path::PathBuf;
+use std::time::Duration;
 
 #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 pub struct Task {
@@ -337,3 +338,10 @@ pub fn delete_all() -> Result<()> {
 
     Ok(())
 }
+
+pub fn backup_db(backup_file: String) -> Result<()> {
+    let mut bkup_conn = Connection::open(backup_file)?;
+    let conn = Connection::open(get_directory())?;
+    let backup = backup::Backup::new(&conn, &mut bkup_conn)?;
+    backup.run_to_completion(5, Duration::from_millis(250), None)
+}
diff --git a/src/gtk/window.ui b/src/gtk/window.ui
index ed18063..87317d9 100755
--- a/src/gtk/window.ui
+++ b/src/gtk/window.ui
@@ -94,16 +94,22 @@
         <attribute name="action">app.report</attribute>
       </item>
       <item>
-        <attribute name="label" translatable="yes">_Export as CSV</attribute>
-        <attribute name="action">app.export-csv</attribute>
-      </item>
-      <item>
         <attribute name="label" translatable="yes">_Delete history</attribute>
         <attribute name="action">app.delete-history</attribute>
       </item>
     </section>
     <section>
       <item>
+        <attribute name="label" translatable="yes">Back up</attribute>
+        <attribute name="action">app.backup-database</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Export as CSV</attribute>
+        <attribute name="action">app.export-csv</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
         <attribute name="label" translatable="yes">_Preferences</attribute>
         <attribute name="action">app.preferences</attribute>
       </item>