diff --git a/api/backup.py b/api/backup.py new file mode 100644 index 0000000..6703951 --- /dev/null +++ b/api/backup.py @@ -0,0 +1,66 @@ +import shutil +import zipfile +from datetime import datetime + +from flask import Blueprint, send_file, jsonify +import os +from api import require_auth +from db import get_db +from db.models.Markdown import Markdown +from db.models.Path import Path + +import logging +logger = logging.getLogger(__name__) + +backup_bp = Blueprint('backup', __name__, url_prefix='/api/backup') +@backup_bp.route('/', methods=['GET']) +@require_auth(roles=['admin']) +def get_backup(): + try: + paths = {} + with get_db() as session: + pths = session.query(Path).all() + paths = {p.id : p for p in pths} + traverse(1, paths) + timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + archive = shutil.make_archive(base_name=timestamp, format='zip', root_dir='Root') + + shutil.rmtree('Root') + return send_file( + archive, + as_attachment=True, + download_name=timestamp + '.zip', + ) + except Exception as e: + logger.error(f"Failed to get backup: {e}") + return jsonify({"error": "failed to get backup"}), 500 + + +def create_and_cd(path_name): + if not os.path.exists(path_name) or not os.path.isdir(path_name): + os.makedirs(path_name) + os.chdir(path_name) + +def cd_back(): + os.chdir('..') + +def traverse(path_id, paths): + current_path = paths[path_id] + if path_id == 1: + create_and_cd("Root") + else: + create_and_cd(current_path.name) + with open(".meta", "w") as meta_file: + meta_file.write(f"order: {current_path.order}\n") + with get_db() as session: + mds = session.query(Markdown).filter(Markdown.path_id == path_id).all() + for md in mds: + with open(f"{md.title}.md", "w") as md_file: + md_file.write(md.content) + with open(f"{md.title}.mdmeta", "w") as meta_file: + meta_file.write(f"created_at: {md.created_at}\n") + meta_file.write(f"order: {md.order}\n") + children = [c for c in paths.values() if c.parent_id == path_id] + for child in children: + traverse(child.id, paths) + cd_back() diff --git a/app.py b/app.py index 3fd7d02..c236826 100644 --- a/app.py +++ b/app.py @@ -32,7 +32,9 @@ CORS(app, resources={r"/api/*": {"origins": [ r"https?://localhost:\d+", r"https?://127\.0\.0\.1:\d+", r"https?://localhost" -]}}) +]}}, + expose_headers=['Content-Disposition'] + ) limiter.init_app(app)