Files
certain/backend/tests/test_backup.py
T
GuidoandClaude Opus 4.8 f375fc5eaa feat: Backup/Export + Import-UX klarer + Raiffeisen-Preset-Fix
Backup & Export:
- routers/backup: /backup/db (Admin, konsistentes SQLite-Online-Backup),
  /export/transactions.csv|json und /export/all.json (owner-gescoped).
- Einstellungen: Bereich „Backup & Export" mit Download-Buttons. docs/BACKUP.md
  (Wiederherstellung + LXC-Sicherung). pytest für Export + Admin-Schutz.

Import-Verbesserungen (Nutzer-Feedback zum Ablauf):
- Klarer Hinweis, dass die Zuordnungstabelle nur Beispielzeilen zeigt und
  „Vorschau erstellen" die vollständige Prüfliste + Buchen-Button erzeugt.
- Zusammenfassung (erkannt/gebucht) und Warnung, wenn keine gültige Zeile erkannt
  wurde (Hinweis auf Format/Bank-Vorlage).
- Fix: Raiffeisen-Preset hat has_header=true (der Export hat eine Kopfzeile).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-19 20:35:02 +02:00

60 lines
1.9 KiB
Python

import json
import secrets
from datetime import date
def _setup(admin):
acc = admin.post("/api/accounts", json={"name": "Exp", "currency": "EUR"}).json()
admin.post("/api/transactions", json={
"type": "expense", "date": str(date.today()), "account_id": acc["id"],
"amount_cents": 4200, "payee": "Testladen", "description": "Etwas",
})
return acc
def test_export_transactions_csv(admin):
_setup(admin)
r = admin.get("/api/export/transactions.csv")
assert r.status_code == 200
assert "text/csv" in r.headers["content-type"]
body = r.content.decode("utf-8-sig")
assert "Datum;Typ;Konto" in body.splitlines()[0]
assert "Testladen" in body
def test_export_transactions_json(admin):
_setup(admin)
r = admin.get("/api/export/transactions.json")
assert r.status_code == 200
data = json.loads(r.content)
assert any(t["payee"] == "Testladen" for t in data)
def test_export_all_json(admin):
_setup(admin)
r = admin.get("/api/export/all.json")
assert r.status_code == 200
data = json.loads(r.content)
assert data["app"] == "Certain Finance"
assert len(data["accounts"]) >= 1
assert len(data["transactions"]) >= 1
def test_db_backup_admin_only(admin):
from fastapi.testclient import TestClient
from app.main import app
# Admin darf.
r = admin.get("/api/backup/db")
assert r.status_code == 200
assert r.content[:16].startswith(b"SQLite format 3")
# Normaler Nutzer darf nicht.
u, p = "u_" + secrets.token_hex(4), "pw"
admin.post("/api/users", json={"username": u, "password": p, "role": "user"})
other = TestClient(app)
other.post("/api/auth/login", data={"username": u, "password": p})
assert other.get("/api/backup/db").status_code == 403
# ...aber seinen eigenen Export schon (leer).
assert other.get("/api/export/all.json").status_code == 200