From d81d5a467296c4661b66cbb65b2208b0d299f118 Mon Sep 17 00:00:00 2001 From: Kavalar Date: Mon, 21 Sep 2026 15:08:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D1=8B=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=BD?= =?UTF-8?q?=D1=8B=2030=20=D0=BC=D0=B8=D0=BD=D1=83=D1=82,=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BC=20=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D1=8F?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=BD=D0=B5=D0=B4=D0=BE=D1=81=D1=82=D1=83?= =?UTF-8?q?=D0=BF=D0=BD=D1=8B=D0=BC=D0=B8=20(=D0=BD=D0=B5=20=D1=83=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=D1=8F=D1=8E=D1=82=D1=81=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 16 ++++++++++++++++ storage.py | 14 +++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index fc67542..d6f402c 100644 --- a/app.py +++ b/app.py @@ -405,6 +405,8 @@ def shared_result(share_id): result = storage.get_result(share_id) if result is None: return render_template("result.html", result=None, error="Результат не найден", video_exists=False, base_url=BASE_URL), 404 + if storage.is_expired(result["created_at"]): + return render_template("result.html", result=None, error="Ссылка устарела. Результат доступен в течение 30 минут после сканирования.", video_exists=False, base_url=BASE_URL), 410 video_exists = bool(glob.glob(os.path.join(VIDEO_DIR, f"{share_id}.*"))) return render_template("result.html", result=result, error=None, video_exists=video_exists, base_url=BASE_URL) @@ -413,6 +415,11 @@ def shared_result(share_id): @app.route("/download//pdf") def download_pdf(share_id): """Скачать результат в PDF.""" + result = storage.get_result(share_id) + if result is None: + return "Результат не найден", 404 + if storage.is_expired(result["created_at"]): + return "Ссылка устарела. Результат доступен в течение 30 минут.", 410 try: data = export.generate_pdf(share_id) except ValueError: @@ -431,6 +438,11 @@ def download_pdf(share_id): @app.route("/download//docx") def download_docx(share_id): """Скачать результат в DOCX.""" + result = storage.get_result(share_id) + if result is None: + return "Результат не найден", 404 + if storage.is_expired(result["created_at"]): + return "Ссылка устарела. Результат доступен в течение 30 минут.", 410 try: data = export.generate_docx(share_id) except ValueError: @@ -449,6 +461,10 @@ def download_docx(share_id): @app.route("/download//video") def download_video(video_id): """Скачать видео, записанное при сканировании (то, что было в кружке).""" + # Если video_id соответствует результату в БД — проверяем срок действия. + result = storage.get_result(video_id) + if result is not None and storage.is_expired(result["created_at"]): + return "Ссылка устарела. Результат доступен в течение 30 минут.", 410 matches = glob.glob(os.path.join(VIDEO_DIR, f"{video_id}.*")) if not matches: return "Видео не найдено", 404 diff --git a/storage.py b/storage.py index ae49acb..beaaf86 100644 --- a/storage.py +++ b/storage.py @@ -17,13 +17,25 @@ import json import os import sqlite3 import uuid -from datetime import datetime +from datetime import datetime, timedelta DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "results.db") # Первый ID результата FIRST_ID = 10005 +# Срок жизни результата: доступен 30 минут, затем становится недоступным (не удаляется). +RESULT_TTL = timedelta(minutes=30) + + +def is_expired(created_at: str) -> bool: + """True, если результат старше RESULT_TTL (30 минут).""" + try: + created = datetime.fromisoformat(created_at) + except (ValueError, TypeError): + return False + return datetime.now() - created > RESULT_TTL + def _connect(): conn = sqlite3.connect(DB_PATH)