06/05 Optimize app

This commit is contained in:
2026-06-05 15:23:23 -04:00
parent db44d6057b
commit 9c9aa694c4
9 changed files with 781 additions and 19 deletions
+12
View File
@@ -253,6 +253,18 @@ def reconcile_api():
})
@dashboard_bp.route('/api/health-score')
@login_required
def health_score_api():
from app.services.health_score_service import compute_health_score
try:
data = compute_health_score()
except Exception as e:
log.warning('[dashboard] health_score_api failed: %s', e)
return jsonify({'error': str(e)}), 500
return jsonify(data)
@dashboard_bp.route('/api/anomalies')
@login_required
def anomalies_api():
+16 -1
View File
@@ -1,7 +1,7 @@
import os
import uuid
from flask import (Blueprint, render_template, redirect, url_for, flash,
request, current_app, send_from_directory)
request, current_app, send_from_directory, jsonify)
from flask_login import login_required, current_user
from app.utils.audit import audit
from flask_wtf import FlaskForm
@@ -208,6 +208,21 @@ def recurring():
return render_template('settings/recurring.html', rules=rules, upcoming=upcoming)
@settings_bp.route('/recurring/projection')
@login_required
def recurring_projection():
days = request.args.get('days', 30, type=int)
if days not in (30, 60, 90):
days = 30
from app.services.recurring_service import projected_cash_flow
data = projected_cash_flow(days)
# Serialize events (date objects → string)
data['events'] = [
{**ev, 'date': ev['date'].strftime('%b %d')} for ev in data['events']
]
return jsonify(data)
@settings_bp.route('/recurring/new', methods=['GET', 'POST'])
@login_required
def recurring_new():
+9
View File
@@ -443,12 +443,21 @@ def ocr_receipt_file():
from app.models.category import Category
from flask import current_app
from app.models.receipt import Receipt
data = request.get_json()
if not data or not data.get('filename'):
return jsonify({'error': 'No filename provided'}), 400
# Security: only allow basenames, no path traversal
filename = os.path.basename(data['filename'])
# Ownership check: filename must exist in receipts table (single-user, but
# prevents OCR extraction from arbitrary files on disk via a crafted request)
receipt_record = Receipt.query.filter_by(filename=filename).first()
if not receipt_record:
return jsonify({'error': 'Receipt not found'}), 404
upload_dir = current_app.config.get('UPLOAD_FOLDER', '/home/pfm/app/uploads')
file_path = os.path.join(upload_dir, filename)