feat: logging toegevoegd
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,169 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
import uuid
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
VALID_HISTORY_STATUSES = {"queued", "completed", "failed"}
|
||||
VALID_HISTORY_OPERATIONS = {"mkdir", "rename", "delete", "copy", "move"}
|
||||
|
||||
|
||||
class HistoryRepository:
|
||||
def __init__(self, db_path: str):
|
||||
self._db_path = db_path
|
||||
self._ensure_schema()
|
||||
|
||||
def create_entry(
|
||||
self,
|
||||
*,
|
||||
operation: str,
|
||||
status: str,
|
||||
source: str | None = None,
|
||||
destination: str | None = None,
|
||||
path: str | None = None,
|
||||
error_code: str | None = None,
|
||||
error_message: str | None = None,
|
||||
created_at: str | None = None,
|
||||
finished_at: str | None = None,
|
||||
entry_id: str | None = None,
|
||||
) -> dict:
|
||||
if operation not in VALID_HISTORY_OPERATIONS:
|
||||
raise ValueError("invalid operation")
|
||||
if status not in VALID_HISTORY_STATUSES:
|
||||
raise ValueError("invalid status")
|
||||
|
||||
history_id = entry_id or str(uuid.uuid4())
|
||||
created_value = created_at or self._now_iso()
|
||||
|
||||
with self._connection() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO history (
|
||||
id, operation, status, source, destination, path,
|
||||
error_code, error_message, created_at, finished_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
history_id,
|
||||
operation,
|
||||
status,
|
||||
source,
|
||||
destination,
|
||||
path,
|
||||
error_code,
|
||||
error_message,
|
||||
created_value,
|
||||
finished_at,
|
||||
),
|
||||
)
|
||||
row = conn.execute("SELECT * FROM history WHERE id = ?", (history_id,)).fetchone()
|
||||
return self._to_dict(row)
|
||||
|
||||
def update_entry(
|
||||
self,
|
||||
*,
|
||||
entry_id: str,
|
||||
status: str,
|
||||
error_code: str | None = None,
|
||||
error_message: str | None = None,
|
||||
finished_at: str | None = None,
|
||||
) -> None:
|
||||
if status not in VALID_HISTORY_STATUSES:
|
||||
raise ValueError("invalid status")
|
||||
finished_value = finished_at or self._now_iso()
|
||||
with self._connection() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE history
|
||||
SET status = ?, error_code = ?, error_message = ?, finished_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(status, error_code, error_message, finished_value, entry_id),
|
||||
)
|
||||
|
||||
def list_history(self, limit: int = 100) -> list[dict]:
|
||||
max_limit = max(1, min(limit, 200))
|
||||
with self._connection() as conn:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT * FROM history
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?
|
||||
""",
|
||||
(max_limit,),
|
||||
).fetchall()
|
||||
return [self._to_dict(row) for row in rows]
|
||||
|
||||
def insert_entry_for_testing(self, entry: dict) -> None:
|
||||
with self._connection() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO history (
|
||||
id, operation, status, source, destination, path,
|
||||
error_code, error_message, created_at, finished_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
entry["id"],
|
||||
entry["operation"],
|
||||
entry["status"],
|
||||
entry.get("source"),
|
||||
entry.get("destination"),
|
||||
entry.get("path"),
|
||||
entry.get("error_code"),
|
||||
entry.get("error_message"),
|
||||
entry["created_at"],
|
||||
entry.get("finished_at"),
|
||||
),
|
||||
)
|
||||
|
||||
def _ensure_schema(self) -> None:
|
||||
db_path = Path(self._db_path)
|
||||
if db_path.parent and str(db_path.parent) not in {"", "."}:
|
||||
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with self._connection() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS history (
|
||||
id TEXT PRIMARY KEY,
|
||||
operation TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
source TEXT NULL,
|
||||
destination TEXT NULL,
|
||||
path TEXT NULL,
|
||||
error_code TEXT NULL,
|
||||
error_message TEXT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
finished_at TEXT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE INDEX IF NOT EXISTS idx_history_created_at_desc
|
||||
ON history(created_at DESC)
|
||||
"""
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
def _connection(self):
|
||||
conn = sqlite3.connect(self._db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
try:
|
||||
yield conn
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
@staticmethod
|
||||
def _to_dict(row: sqlite3.Row | None) -> dict | None:
|
||||
if row is None:
|
||||
return None
|
||||
return dict(row)
|
||||
|
||||
@staticmethod
|
||||
def _now_iso() -> str:
|
||||
return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
||||
@@ -32,11 +32,11 @@ class TaskRepository:
|
||||
self._db_path = db_path
|
||||
self._ensure_schema()
|
||||
|
||||
def create_task(self, operation: str, source: str, destination: str) -> dict:
|
||||
def create_task(self, operation: str, source: str, destination: str, task_id: str | None = None) -> dict:
|
||||
if operation not in VALID_OPERATIONS:
|
||||
raise ValueError("invalid operation")
|
||||
|
||||
task_id = str(uuid.uuid4())
|
||||
task_id = task_id or str(uuid.uuid4())
|
||||
created_at = self._now_iso()
|
||||
|
||||
with self._connection() as conn:
|
||||
|
||||
Reference in New Issue
Block a user