Ensure that adding a document whilst on an older date page, uses that date as its upload date
This commit is contained in:
parent
bae91f56e6
commit
779049e467
3 changed files with 116 additions and 21 deletions
|
|
@ -1,3 +1,7 @@
|
||||||
|
# 0.6.2
|
||||||
|
|
||||||
|
* Ensure that adding a document whilst on an older date page, uses that date as its upload date
|
||||||
|
|
||||||
# 0.6.1
|
# 0.6.1
|
||||||
|
|
||||||
* Consolidate some code related to opening documents using the Documents feature.
|
* Consolidate some code related to opening documents using the Documents feature.
|
||||||
|
|
|
||||||
|
|
@ -1333,9 +1333,16 @@ class DBManager:
|
||||||
project_id: int,
|
project_id: int,
|
||||||
file_path: str,
|
file_path: str,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
uploaded_at: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Read a file from disk and store it as a BLOB in project_documents.
|
Read a file from disk and store it as a BLOB in project_documents.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id: The project to attach the document to
|
||||||
|
file_path: Path to the file to upload
|
||||||
|
description: Optional description
|
||||||
|
uploaded_at: Optional date in YYYY-MM-DD format. If None, uses current date.
|
||||||
"""
|
"""
|
||||||
path = Path(file_path)
|
path = Path(file_path)
|
||||||
if not path.is_file():
|
if not path.is_file():
|
||||||
|
|
@ -1349,6 +1356,27 @@ class DBManager:
|
||||||
|
|
||||||
with self.conn:
|
with self.conn:
|
||||||
cur = self.conn.cursor()
|
cur = self.conn.cursor()
|
||||||
|
if uploaded_at is not None:
|
||||||
|
# Use explicit date
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO project_documents
|
||||||
|
(project_id, file_name, mime_type,
|
||||||
|
description, size_bytes, uploaded_at, data)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
project_id,
|
||||||
|
file_name,
|
||||||
|
mime_type,
|
||||||
|
description,
|
||||||
|
size_bytes,
|
||||||
|
uploaded_at,
|
||||||
|
Binary(data),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Let DB default to current date
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO project_documents
|
INSERT INTO project_documents
|
||||||
|
|
@ -1376,6 +1404,20 @@ class DBManager:
|
||||||
(description, doc_id),
|
(description, doc_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_document_uploaded_at(self, doc_id: int, uploaded_at: str) -> None:
|
||||||
|
"""
|
||||||
|
Update the uploaded_at date for a document.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
doc_id: Document ID
|
||||||
|
uploaded_at: Date in YYYY-MM-DD format
|
||||||
|
"""
|
||||||
|
with self.conn:
|
||||||
|
self.conn.execute(
|
||||||
|
"UPDATE project_documents SET uploaded_at = ? WHERE id = ?;",
|
||||||
|
(uploaded_at, doc_id),
|
||||||
|
)
|
||||||
|
|
||||||
def delete_document(self, doc_id: int) -> None:
|
def delete_document(self, doc_id: int) -> None:
|
||||||
with self.conn:
|
with self.conn:
|
||||||
self.conn.execute("DELETE FROM project_documents WHERE id = ?;", (doc_id,))
|
self.conn.execute("DELETE FROM project_documents WHERE id = ?;", (doc_id,))
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ class TodaysDocumentsWidget(QFrame):
|
||||||
|
|
||||||
def _open_documents_dialog(self) -> None:
|
def _open_documents_dialog(self) -> None:
|
||||||
"""Open the full DocumentsDialog."""
|
"""Open the full DocumentsDialog."""
|
||||||
dlg = DocumentsDialog(self._db, self)
|
dlg = DocumentsDialog(self._db, self, current_date=self._current_date)
|
||||||
dlg.exec()
|
dlg.exec()
|
||||||
# Refresh after any changes
|
# Refresh after any changes
|
||||||
self.reload()
|
self.reload()
|
||||||
|
|
@ -179,12 +179,14 @@ class DocumentsDialog(QDialog):
|
||||||
db: DBManager,
|
db: DBManager,
|
||||||
parent: QWidget | None = None,
|
parent: QWidget | None = None,
|
||||||
initial_project_id: Optional[int] = None,
|
initial_project_id: Optional[int] = None,
|
||||||
|
current_date: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._db = db
|
self._db = db
|
||||||
self.cfg = load_db_config()
|
self.cfg = load_db_config()
|
||||||
self._reloading_docs = False
|
self._reloading_docs = False
|
||||||
self._search_text: str = ""
|
self._search_text: str = ""
|
||||||
|
self._current_date = current_date # Store the current date for document uploads
|
||||||
|
|
||||||
self.setWindowTitle(strings._("project_documents_title"))
|
self.setWindowTitle(strings._("project_documents_title"))
|
||||||
self.resize(900, 450)
|
self.resize(900, 450)
|
||||||
|
|
@ -382,10 +384,9 @@ class DocumentsDialog(QDialog):
|
||||||
desc_item = QTableWidgetItem(description or "")
|
desc_item = QTableWidgetItem(description or "")
|
||||||
self.table.setItem(row_idx, self.DESC_COL, desc_item)
|
self.table.setItem(row_idx, self.DESC_COL, desc_item)
|
||||||
|
|
||||||
# Col 3: Added at (not editable)
|
# Col 3: Added at (editable)
|
||||||
added_label = uploaded_at
|
added_label = uploaded_at
|
||||||
added_item = QTableWidgetItem(added_label)
|
added_item = QTableWidgetItem(added_label)
|
||||||
added_item.setFlags(added_item.flags() & ~Qt.ItemIsEditable)
|
|
||||||
self.table.setItem(row_idx, self.ADDED_COL, added_item)
|
self.table.setItem(row_idx, self.ADDED_COL, added_item)
|
||||||
|
|
||||||
# Col 4: Size (not editable)
|
# Col 4: Size (not editable)
|
||||||
|
|
@ -422,7 +423,9 @@ class DocumentsDialog(QDialog):
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
self._db.add_document_from_path(proj_id, path)
|
self._db.add_document_from_path(
|
||||||
|
proj_id, path, uploaded_at=self._current_date
|
||||||
|
)
|
||||||
except Exception as e: # pragma: no cover
|
except Exception as e: # pragma: no cover
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
|
|
@ -469,7 +472,7 @@ class DocumentsDialog(QDialog):
|
||||||
|
|
||||||
def _on_item_changed(self, item: QTableWidgetItem) -> None:
|
def _on_item_changed(self, item: QTableWidgetItem) -> None:
|
||||||
"""
|
"""
|
||||||
Handle inline edits to Description and Tags.
|
Handle inline edits to Description, Tags, and Added date.
|
||||||
"""
|
"""
|
||||||
if self._reloading_docs or item is None:
|
if self._reloading_docs or item is None:
|
||||||
return
|
return
|
||||||
|
|
@ -524,9 +527,55 @@ class DocumentsDialog(QDialog):
|
||||||
item.setForeground(QColor())
|
item.setForeground(QColor())
|
||||||
finally:
|
finally:
|
||||||
self._reloading_docs = False
|
self._reloading_docs = False
|
||||||
|
return
|
||||||
|
|
||||||
|
# Added date column
|
||||||
|
if col == self.ADDED_COL:
|
||||||
|
date_str = item.text().strip()
|
||||||
|
|
||||||
|
# Validate date format (YYYY-MM-DD)
|
||||||
|
if not self._validate_date_format(date_str):
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
strings._("project_documents_title"),
|
||||||
|
(
|
||||||
|
strings._("documents_invalid_date_format")
|
||||||
|
if hasattr(strings, "_")
|
||||||
|
and callable(getattr(strings, "_"))
|
||||||
|
and "documents_invalid_date_format" in dir(strings)
|
||||||
|
else f"Invalid date format. Please use YYYY-MM-DD format.\nExample: {date_str[:4]}-01-15"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Reload to reset the cell to its original value
|
||||||
|
self._reload_documents()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update the database
|
||||||
|
self._db.update_document_uploaded_at(doc_id, date_str)
|
||||||
|
return
|
||||||
|
|
||||||
# --- utils -------------------------------------------------------------
|
# --- utils -------------------------------------------------------------
|
||||||
|
|
||||||
|
def _validate_date_format(self, date_str: str) -> bool:
|
||||||
|
"""
|
||||||
|
Validate that a date string is in YYYY-MM-DD format.
|
||||||
|
|
||||||
|
Returns True if valid, False otherwise.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Check basic format with regex
|
||||||
|
if not re.match(r"^\d{4}-\d{2}-\d{2}$", date_str):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Validate it's a real date
|
||||||
|
try:
|
||||||
|
datetime.strptime(date_str, "%Y-%m-%d")
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
def _open_document(self, doc_id: int, file_name: str) -> None:
|
def _open_document(self, doc_id: int, file_name: str) -> None:
|
||||||
"""
|
"""
|
||||||
Fetch BLOB from DB, write to a temporary file, and open with default app.
|
Fetch BLOB from DB, write to a temporary file, and open with default app.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue