import urllib.parse from flask import Blueprint, Response, redirect, url_for, flash from flask_login import login_required from app.models.schedule import Schedule from app.access import can_view as _can_view bp = Blueprint('export', __name__) @bp.route('/schedules//export/json') @login_required def export_json(schedule_id: int): schedule = Schedule.query.get_or_404(schedule_id) if not _can_view(schedule): flash('Нет доступа', 'danger') return redirect(url_for('schedules.profile')) from app.services.export import export_json as svc_json data = svc_json(schedule) filename = _safe_name(schedule.name) + '.json' return Response( data, mimetype='application/json', headers={'Content-Disposition': _cd(filename)}, ) @bp.route('/schedules//export/csv') @login_required def export_csv(schedule_id: int): schedule = Schedule.query.get_or_404(schedule_id) if not _can_view(schedule): flash('Нет доступа', 'danger') return redirect(url_for('schedules.profile')) from app.services.export import export_csv as svc_csv data = svc_csv(schedule) filename = _safe_name(schedule.name) + '.csv' return Response( data, mimetype='text/csv; charset=utf-8-sig', headers={'Content-Disposition': _cd(filename)}, ) @bp.route('/schedules//export/pdf') @login_required def export_pdf(schedule_id: int): schedule = Schedule.query.get_or_404(schedule_id) if not _can_view(schedule): flash('Нет доступа', 'danger') return redirect(url_for('schedules.profile')) from app.services.export import export_pdf as svc_pdf data = svc_pdf(schedule) filename = _safe_name(schedule.name) + '.pdf' return Response( data, mimetype='application/pdf', headers={'Content-Disposition': _cd(filename)}, ) @bp.route('/schedules//export/png') @login_required def export_png(schedule_id: int): schedule = Schedule.query.get_or_404(schedule_id) if not _can_view(schedule): flash('Нет доступа', 'danger') return redirect(url_for('schedules.profile')) from app.services.export import export_png as svc_png data = svc_png(schedule) filename = _safe_name(schedule.name) + '.png' return Response( data, mimetype='image/png', headers={'Content-Disposition': _cd(filename)}, ) def _safe_name(name: str) -> str: safe = ''.join(c if c.isalnum() or c in ' ._-' else '_' for c in name) return safe.strip() or 'schedule' def _cd(filename: str) -> str: """Content-Disposition с поддержкой Unicode (RFC 5987).""" ascii_name = filename.encode('ascii', 'replace').decode('ascii') utf8_name = urllib.parse.quote(filename, safe='') return f"attachment; filename=\"{ascii_name}\"; filename*=UTF-8''{utf8_name}"