bouquin 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bouquin might be problematic. Click here for more details.
- bouquin/db.py +19 -0
- bouquin/main_window.py +15 -2
- bouquin/settings_dialog.py +30 -2
- {bouquin-0.1.0.dist-info → bouquin-0.1.1.dist-info}/METADATA +1 -2
- bouquin-0.1.1.dist-info/RECORD +14 -0
- bouquin-0.1.0.dist-info/RECORD +0 -14
- {bouquin-0.1.0.dist-info → bouquin-0.1.1.dist-info}/LICENSE +0 -0
- {bouquin-0.1.0.dist-info → bouquin-0.1.1.dist-info}/WHEEL +0 -0
- {bouquin-0.1.0.dist-info → bouquin-0.1.1.dist-info}/entry_points.txt +0 -0
bouquin/db.py
CHANGED
|
@@ -64,6 +64,25 @@ class DBManager:
|
|
|
64
64
|
cur.execute("PRAGMA user_version = 1;")
|
|
65
65
|
self.conn.commit()
|
|
66
66
|
|
|
67
|
+
def rekey(self, new_key: str) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Change the SQLCipher passphrase in-place, then reopen the connection
|
|
70
|
+
with the new key to verify.
|
|
71
|
+
"""
|
|
72
|
+
if self.conn is None:
|
|
73
|
+
raise RuntimeError("Database is not connected")
|
|
74
|
+
cur = self.conn.cursor()
|
|
75
|
+
# Change the encryption key of the currently open database
|
|
76
|
+
cur.execute(f"PRAGMA rekey = '{new_key}';")
|
|
77
|
+
self.conn.commit()
|
|
78
|
+
|
|
79
|
+
# Close and reopen with the new key to verify and restore PRAGMAs
|
|
80
|
+
self.conn.close()
|
|
81
|
+
self.conn = None
|
|
82
|
+
self.cfg.key = new_key
|
|
83
|
+
if not self.connect():
|
|
84
|
+
raise sqlite.Error("Re-open failed after rekey")
|
|
85
|
+
|
|
67
86
|
def get_entry(self, date_iso: str) -> str:
|
|
68
87
|
cur = self.conn.cursor()
|
|
69
88
|
cur.execute("SELECT content FROM entries WHERE date = ?;", (date_iso,))
|
bouquin/main_window.py
CHANGED
|
@@ -72,7 +72,8 @@ class MainWindow(QMainWindow):
|
|
|
72
72
|
act_save.setShortcut("Ctrl+S")
|
|
73
73
|
act_save.triggered.connect(lambda: self._save_current(explicit=True))
|
|
74
74
|
file_menu.addAction(act_save)
|
|
75
|
-
act_settings = QAction("&
|
|
75
|
+
act_settings = QAction("S&ettings", self)
|
|
76
|
+
act_save.setShortcut("Ctrl+E")
|
|
76
77
|
act_settings.triggered.connect(self._open_settings)
|
|
77
78
|
file_menu.addAction(act_settings)
|
|
78
79
|
file_menu.addSeparator()
|
|
@@ -97,6 +98,13 @@ class MainWindow(QMainWindow):
|
|
|
97
98
|
nav_menu.addAction(act_next)
|
|
98
99
|
self.addAction(act_next)
|
|
99
100
|
|
|
101
|
+
act_today = QAction("Today", self)
|
|
102
|
+
act_today.setShortcut("Ctrl+T")
|
|
103
|
+
act_today.setShortcutContext(Qt.ApplicationShortcut)
|
|
104
|
+
act_today.triggered.connect(self._adjust_today)
|
|
105
|
+
nav_menu.addAction(act_today)
|
|
106
|
+
self.addAction(act_today)
|
|
107
|
+
|
|
100
108
|
# Autosave
|
|
101
109
|
self._dirty = False
|
|
102
110
|
self._save_timer = QTimer(self)
|
|
@@ -176,6 +184,11 @@ class MainWindow(QMainWindow):
|
|
|
176
184
|
d = self.calendar.selectedDate().addDays(delta)
|
|
177
185
|
self.calendar.setSelectedDate(d)
|
|
178
186
|
|
|
187
|
+
def _adjust_today(self):
|
|
188
|
+
"""Jump to today."""
|
|
189
|
+
today = QDate.currentDate()
|
|
190
|
+
self.calendar.setSelectedDate(today)
|
|
191
|
+
|
|
179
192
|
def _on_date_changed(self):
|
|
180
193
|
"""
|
|
181
194
|
When the calendar selection changes, save the previous day's note if dirty,
|
|
@@ -219,7 +232,7 @@ class MainWindow(QMainWindow):
|
|
|
219
232
|
self._save_date(self._current_date_iso(), explicit)
|
|
220
233
|
|
|
221
234
|
def _open_settings(self):
|
|
222
|
-
dlg = SettingsDialog(self.cfg, self)
|
|
235
|
+
dlg = SettingsDialog(self.cfg, self.db, self)
|
|
223
236
|
if dlg.exec() == QDialog.Accepted:
|
|
224
237
|
new_cfg = dlg.config
|
|
225
238
|
if new_cfg.path != self.cfg.path:
|
bouquin/settings_dialog.py
CHANGED
|
@@ -13,17 +13,20 @@ from PySide6.QtWidgets import (
|
|
|
13
13
|
QFileDialog,
|
|
14
14
|
QDialogButtonBox,
|
|
15
15
|
QSizePolicy,
|
|
16
|
+
QMessageBox,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
from .db import DBConfig
|
|
19
|
+
from .db import DBConfig, DBManager
|
|
19
20
|
from .settings import save_db_config
|
|
21
|
+
from .key_prompt import KeyPrompt
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class SettingsDialog(QDialog):
|
|
23
|
-
def __init__(self, cfg: DBConfig, parent=None):
|
|
25
|
+
def __init__(self, cfg: DBConfig, db: DBManager, parent=None):
|
|
24
26
|
super().__init__(parent)
|
|
25
27
|
self.setWindowTitle("Settings")
|
|
26
28
|
self._cfg = DBConfig(path=cfg.path, key="")
|
|
29
|
+
self._db = db
|
|
27
30
|
|
|
28
31
|
form = QFormLayout()
|
|
29
32
|
form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
|
|
@@ -44,12 +47,17 @@ class SettingsDialog(QDialog):
|
|
|
44
47
|
h.setStretch(1, 0)
|
|
45
48
|
form.addRow("Database path", path_row)
|
|
46
49
|
|
|
50
|
+
# Change key button
|
|
51
|
+
self.rekey_btn = QPushButton("Change key")
|
|
52
|
+
self.rekey_btn.clicked.connect(self._change_key)
|
|
53
|
+
|
|
47
54
|
bb = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
|
|
48
55
|
bb.accepted.connect(self._save)
|
|
49
56
|
bb.rejected.connect(self.reject)
|
|
50
57
|
|
|
51
58
|
v = QVBoxLayout(self)
|
|
52
59
|
v.addLayout(form)
|
|
60
|
+
v.addWidget(self.rekey_btn)
|
|
53
61
|
v.addWidget(bb)
|
|
54
62
|
|
|
55
63
|
def _browse(self):
|
|
@@ -67,6 +75,26 @@ class SettingsDialog(QDialog):
|
|
|
67
75
|
save_db_config(self._cfg)
|
|
68
76
|
self.accept()
|
|
69
77
|
|
|
78
|
+
def _change_key(self):
|
|
79
|
+
p1 = KeyPrompt(self, title="Change key", message="Enter new key")
|
|
80
|
+
if p1.exec() != QDialog.Accepted:
|
|
81
|
+
return
|
|
82
|
+
new_key = p1.key()
|
|
83
|
+
p2 = KeyPrompt(self, title="Change key", message="Re-enter new key")
|
|
84
|
+
if p2.exec() != QDialog.Accepted:
|
|
85
|
+
return
|
|
86
|
+
if new_key != p2.key():
|
|
87
|
+
QMessageBox.warning(self, "Key mismatch", "The two entries did not match.")
|
|
88
|
+
return
|
|
89
|
+
if not new_key:
|
|
90
|
+
QMessageBox.warning(self, "Empty key", "Key cannot be empty.")
|
|
91
|
+
return
|
|
92
|
+
try:
|
|
93
|
+
self._db.rekey(new_key)
|
|
94
|
+
QMessageBox.information(self, "Key changed", "The database key was updated.")
|
|
95
|
+
except Exception as e:
|
|
96
|
+
QMessageBox.critical(self, "Error", f"Could not change key:\n{e}")
|
|
97
|
+
|
|
70
98
|
@property
|
|
71
99
|
def config(self) -> DBConfig:
|
|
72
100
|
return self._cfg
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bouquin
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher.
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
6
|
Author: Miguel Jacq
|
|
@@ -49,7 +49,6 @@ There is deliberately no network connectivity or syncing intended.
|
|
|
49
49
|
|
|
50
50
|
* Search
|
|
51
51
|
* Taxonomy/tagging
|
|
52
|
-
* Ability to change the SQLCipher key
|
|
53
52
|
* Export to other formats (plaintext, json, sql etc)
|
|
54
53
|
|
|
55
54
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
bouquin/__init__.py,sha256=-bBNFYOq80A2Egtpo5V5zWJtYOxQfRZFQ_feve5lkFU,23
|
|
2
|
+
bouquin/__main__.py,sha256=Vdhw8YA1K3wPMlbJQYL5WqvRzAKVeZ16mZQFO9VRmCo,62
|
|
3
|
+
bouquin/db.py,sha256=-RCWeStZD-eZ2TEUaUTj67cBvq30q2aiSmLoP-K67Jk,3396
|
|
4
|
+
bouquin/highlighter.py,sha256=UPP4G4jdN7U8y1c3nk9zTswkHHJw0Tpl3PX6obZrSG0,4077
|
|
5
|
+
bouquin/key_prompt.py,sha256=RNrW0bN4xnwDGeBlgbmFaBSs_2iQyYrBYpKOQhe4E0c,1092
|
|
6
|
+
bouquin/main.py,sha256=tx59cJZnGgHQ1UHQbdlYgaC36_L0ulyKaOoy6oURXVA,348
|
|
7
|
+
bouquin/main_window.py,sha256=OQQ1BhPp3F3ULVrtjeTsKTraZZDzRECjYCORrRpWmis,9291
|
|
8
|
+
bouquin/settings.py,sha256=bJYQXbTqX_r_DfOKuGnah6IVZLiNwZAuBuz2OgdhA_E,670
|
|
9
|
+
bouquin/settings_dialog.py,sha256=NA40-RvXvM8SND-o5K6b-yKMrShY6NQnQuDAxUoCzyI,3120
|
|
10
|
+
bouquin-0.1.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
11
|
+
bouquin-0.1.1.dist-info/METADATA,sha256=j1CnzeNbB-bzfHaXN9rS66RDaG3-q4Ic6erwzKjqxBw,2148
|
|
12
|
+
bouquin-0.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
13
|
+
bouquin-0.1.1.dist-info/entry_points.txt,sha256=d2C5Mc85suj1vWg_mmcfFuEBAYEkdwhZquusme5EWuQ,49
|
|
14
|
+
bouquin-0.1.1.dist-info/RECORD,,
|
bouquin-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
bouquin/__init__.py,sha256=-bBNFYOq80A2Egtpo5V5zWJtYOxQfRZFQ_feve5lkFU,23
|
|
2
|
-
bouquin/__main__.py,sha256=Vdhw8YA1K3wPMlbJQYL5WqvRzAKVeZ16mZQFO9VRmCo,62
|
|
3
|
-
bouquin/db.py,sha256=0fCr--ko-StUMRPG96Nwzotq7a7xz1-9ZlmaEKs_2PA,2697
|
|
4
|
-
bouquin/highlighter.py,sha256=UPP4G4jdN7U8y1c3nk9zTswkHHJw0Tpl3PX6obZrSG0,4077
|
|
5
|
-
bouquin/key_prompt.py,sha256=RNrW0bN4xnwDGeBlgbmFaBSs_2iQyYrBYpKOQhe4E0c,1092
|
|
6
|
-
bouquin/main.py,sha256=tx59cJZnGgHQ1UHQbdlYgaC36_L0ulyKaOoy6oURXVA,348
|
|
7
|
-
bouquin/main_window.py,sha256=qWDM1ZJcPRHsX8oju_TaoLmBLGAwkaLcUIf44wSRLEQ,8830
|
|
8
|
-
bouquin/settings.py,sha256=bJYQXbTqX_r_DfOKuGnah6IVZLiNwZAuBuz2OgdhA_E,670
|
|
9
|
-
bouquin/settings_dialog.py,sha256=XW7SFg3_bD4rGj9D3jA65j7Jvq6049CxvRilfcGCKDU,2014
|
|
10
|
-
bouquin-0.1.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
11
|
-
bouquin-0.1.0.dist-info/METADATA,sha256=SFda5ee4tRfifEa10WNRbMG9uIhK5IrB1Pz4TbobBNI,2187
|
|
12
|
-
bouquin-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
13
|
-
bouquin-0.1.0.dist-info/entry_points.txt,sha256=d2C5Mc85suj1vWg_mmcfFuEBAYEkdwhZquusme5EWuQ,49
|
|
14
|
-
bouquin-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|