From 55cb965d9fa5acbc14b310d03000d7f5fade9f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Mon, 22 Jun 2026 17:58:20 +0300 Subject: [PATCH] =?UTF-8?q?1.=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8=D1=8E?= =?UTF-8?q?=202.=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=20?= =?UTF-8?q?=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=BA=D1=83=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9,=20=D1=87=D1=82?= =?UTF-8?q?=D0=BE=D0=B1=D1=8B=20=D0=BD=D0=B5=20=D1=87=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B7=20=D0=BA=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 269 ++++++++ static/docs/no photo.png | Bin 0 -> 8595 bytes static/docs/scorebug with title.png | Bin 0 -> 36394 bytes templates/admin_db_index.html | 240 +++++++- templates/info.html | 911 ++++++++++++++++------------ 5 files changed, 1016 insertions(+), 404 deletions(-) create mode 100644 static/docs/no photo.png create mode 100644 static/docs/scorebug with title.png diff --git a/app.py b/app.py index c08da9e..fca0d87 100644 --- a/app.py +++ b/app.py @@ -27,6 +27,8 @@ from urllib.parse import quote, urlencode import traceback import contextlib import os +import html +import re from parsers.parser_game import run_parser_game from parsers.parser_players import run_parser_players from parsers.parser_schedule import run_parser_schedule @@ -1924,6 +1926,230 @@ async def list_vmix_clients(): return {"items": clients} + +INFO_TEMPLATE_PATH = BASE_DIR / "templates" / "info.html" + + +def _clean_update_text(value: str | None) -> str: + return (value or "").strip() + + +def _escape_text(value: str | None) -> str: + return html.escape(_clean_update_text(value), quote=True) + + +def _split_lines(value: str | None) -> list[str]: + return [line.strip() for line in (value or "").splitlines() if line.strip()] + + +def _format_update_date(value: str | None) -> str: + value = _clean_update_text(value) + if re.fullmatch(r"\d{4}-\d{2}-\d{2}", value): + try: + return datetime.strptime(value, "%Y-%m-%d").strftime("%d.%m.%Y") + except ValueError: + return value + return value + + +def _paragraphs_html(value: str | None) -> str: + lines = _split_lines(value) + if not lines: + return "

Описание не заполнено.

" + + return "\n".join(f"

{_escape_text(line)}

" for line in lines) + + +def _normalize_update_image_path(value: str | None) -> str: + path = _clean_update_text(value) + if not path: + return "" + + # Удобный вариант для админки: можно ввести только имя файла, + # например "no photo.png" — оно превратится в /static/docs/no photo.png. + if path.startswith("static/"): + path = "/" + path + elif path.startswith("docs/"): + path = "/static/" + path + elif not path.startswith(("/static/", "http://", "https://")): + path = "/static/docs/" + path.lstrip("/") + + return path + + +def _image_html(value: str | None, alt: str | None = None) -> str: + path = _normalize_update_image_path(value) + if not path: + return "" + + return f'\n {_escape_text(alt or ' + + +def _build_update_block( + version: str, + date: str, + operator_actions: str, + item_badges: list[str], + item_titles: list[str], + item_texts: list[str], + item_images: list[str] | None = None, +) -> str: + badge_meta = { + "new": ("new", "Новое"), + "fix": ("fix", "Исправлено"), + "improve": ("improve", "Улучшено"), + "important": ("important", "Важно"), + } + + version_html = _escape_text(version) + date_html = _escape_text(date) + + actions = _split_lines(operator_actions) + if actions: + actions_html = "\n".join(f"
  • {_escape_text(action)}
  • " for action in actions) + else: + actions_html = "
  • Ознакомиться с обновлением перед работой с матчем.
  • " + + item_images = item_images or [] + + update_items: list[str] = [] + max_len = max(len(item_titles), len(item_texts), len(item_badges), len(item_images), 1) + + for index in range(max_len): + title = _clean_update_text(item_titles[index] if index < len(item_titles) else "") + text = _clean_update_text(item_texts[index] if index < len(item_texts) else "") + badge = _clean_update_text(item_badges[index] if index < len(item_badges) else "new") + image = _clean_update_text(item_images[index] if index < len(item_images) else "") + + if not title and not text: + continue + + badge_class, badge_label = badge_meta.get(badge, badge_meta["new"]) + item_title_html = _escape_text(title or "Без названия") + item_text_html = _paragraphs_html(text) + _image_html(image, title or "Скриншот обновления") + + update_items.append( + f'''
    + {badge_label} + +
    +
    {item_title_html}
    + +
    + {item_text_html} +
    +
    +
    ''' + ) + + if not update_items: + update_items.append( + '''
    + Новое + +
    +
    Обновление системы
    + +
    +

    Описание не заполнено.

    +
    +
    +
    ''' + ) + + items_html = "\n".join(update_items) + + return f''' +
    + +
    +
    +
    +
    Версия {version_html}
    +
    {date_html}
    +
    +
    +
    + +
    +
    Что сделать оператору
    +
      + {actions_html} +
    +
    + +
    +{items_html} +
    +
    +
    +
    +'''.rstrip() + + +def _update_latest_summary(html_text: str, version: str, date: str, item_titles: list[str]) -> str: + titles = [title.strip() for title in item_titles if title and title.strip()] + if not titles: + titles = ["Добавлено новое обновление системы."] + + list_items = "\n".join(f"
  • {_escape_text(title)}
  • " for title in titles[:5]) + summary_html = f'''
    +
    Последние изменения: версия {_escape_text(version)} от {_escape_text(date)}
    + +
    ''' + + pattern = re.compile(r'
    .*?
    ', re.S) + return pattern.sub(summary_html, html_text, count=1) + + +def add_update_to_info_template( + version: str, + date: str, + operator_actions: str, + item_badges: list[str], + item_titles: list[str], + item_texts: list[str], + item_images: list[str] | None = None, +) -> None: + version = _clean_update_text(version) + date = _format_update_date(date) + + if not version: + raise ValueError("Укажите номер версии.") + if not date: + raise ValueError("Укажите дату обновления.") + + html_text = INFO_TEMPLATE_PATH.read_text(encoding="utf-8") + insert_marker = '
    ' + + if insert_marker not in html_text: + raise RuntimeError("Не найден блок updates-timeline в templates/info.html.") + + # У старых карточек убираем отметку latest, чтобы зелёная лента NEW была только у свежего обновления. + html_text = html_text.replace('update-card latest', 'update-card') + + new_update_html = _build_update_block( + version=version, + date=date, + operator_actions=operator_actions, + item_badges=item_badges, + item_titles=item_titles, + item_texts=item_texts, + item_images=item_images, + ) + + html_text = html_text.replace( + insert_marker, + insert_marker + "\n" + new_update_html, + 1, + ) + html_text = _update_latest_summary(html_text, version, date, item_titles) + + INFO_TEMPLATE_PATH.write_text(html_text, encoding="utf-8") + + @app.get("/info", response_class=HTMLResponse) def info_page(request: Request): return templates.TemplateResponse(name="info.html", request=request, context={}) @@ -1934,6 +2160,8 @@ def render_admin_db_index( parser_output: str | None = None, parser_name: str | None = None, parser_success: bool | None = None, + update_output: str | None = None, + update_success: bool | None = None, ): return templates.TemplateResponse( name="admin_db_index.html", @@ -1943,6 +2171,8 @@ def render_admin_db_index( "parser_output": parser_output, "parser_name": parser_name, "parser_success": parser_success, + "update_output": update_output, + "update_success": update_success, }, ) @@ -2002,6 +2232,45 @@ def admin_db_run_parser(request: Request, parser_name: str = Form(...)): ) + +@app.post("/admin/db/add-update", response_class=HTMLResponse) +def admin_db_add_update( + request: Request, + version: str = Form(...), + date: str = Form(...), + operator_actions: str = Form(default=""), + item_badge: list[str] = Form(default=[]), + item_title: list[str] = Form(default=[]), + item_text: list[str] = Form(default=[]), + item_image: list[str] = Form(default=[]), +): + current_user = getattr(request.state, "current_user", None) + if not current_user or current_user.get("role") != "admin": + return RedirectResponse(url="/login", status_code=303) + + try: + add_update_to_info_template( + version=version, + date=date, + operator_actions=operator_actions, + item_badges=item_badge, + item_titles=item_title, + item_texts=item_text, + item_images=item_image, + ) + return render_admin_db_index( + request, + update_output=f"Обновление версии {version.strip()} добавлено в templates/info.html и будет отображаться сверху на странице /info.", + update_success=True, + ) + except Exception: + return render_admin_db_index( + request, + update_output="Ошибка при добавлении обновления:\n" + traceback.format_exc(), + update_success=False, + ) + + @app.post("/admin/db/create-account", response_class=HTMLResponse) def admin_db_create_account( request: Request, diff --git a/static/docs/no photo.png b/static/docs/no photo.png new file mode 100644 index 0000000000000000000000000000000000000000..ac7dcdf9185820fc0fa5c919ff2ae39b91c94983 GIT binary patch literal 8595 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�M?Jktp=KnBdx6?{fg`jj^<1Rgs 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 P003D@MTtW3_dfpx`#I3j literal 0 HcmV?d00001 diff --git a/static/docs/scorebug with title.png b/static/docs/scorebug with title.png new file mode 100644 index 0000000000000000000000000000000000000000..25edbeb37bc3dff92b461993203ca3b9ea6ec20a GIT binary patch literal 36394 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 literal 0 HcmV?d00001 diff --git a/templates/admin_db_index.html b/templates/admin_db_index.html index 837749c..8842916 100644 --- a/templates/admin_db_index.html +++ b/templates/admin_db_index.html @@ -150,7 +150,8 @@ pointer-events: none; } - .account-modal { + .account-modal, + .update-modal { position: fixed; inset: 0; display: none; @@ -161,11 +162,13 @@ padding: 20px; } - .account-modal.active { + .account-modal.active, + .update-modal.active { display: flex; } - .account-modal-card { + .account-modal-card, + .update-modal-card { width: min(100%, 460px); background: rgba(12, 17, 26, 0.98); border: 1px solid rgba(0, 255, 136, 0.28); @@ -174,13 +177,21 @@ padding: 24px; } - .account-modal-title { + .update-modal-card { + width: min(100%, 760px); + max-height: 92vh; + overflow-y: auto; + } + + .account-modal-title, + .update-modal-title { font-size: 22px; font-weight: 700; margin-bottom: 8px; } - .account-modal-subtitle { + .account-modal-subtitle, + .update-modal-subtitle { color: var(--muted); margin-bottom: 18px; line-height: 1.5; @@ -200,7 +211,8 @@ } .field-input, - .field-select { + .field-select, + .field-textarea { width: 100%; min-height: 44px; border-radius: 12px; @@ -212,12 +224,75 @@ outline: none; } + .field-textarea { + min-height: 96px; + padding: 12px 14px; + resize: vertical; + line-height: 1.45; + font-family: Arial, sans-serif; + } + .field-input:focus, - .field-select:focus { + .field-select:focus, + .field-textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0, 255, 136, 0.12); } + .update-form-grid { + display: grid; + grid-template-columns: 1fr 180px; + gap: 14px; + } + + .update-items-editor { + display: grid; + gap: 14px; + } + + .update-item-form { + display: grid; + grid-template-columns: 160px minmax(0, 1fr); + gap: 12px; + padding: 14px; + border: 1px solid var(--border); + border-radius: 14px; + background: rgba(255, 255, 255, 0.025); + } + + .update-item-text, + .update-item-image { + grid-column: 1 / -1; + } + + .helper-text { + color: var(--muted); + font-size: 12px; + line-height: 1.45; + } + + .add-row-btn { + min-height: 38px; + padding: 0 14px; + border-radius: 999px; + border: 1px dashed rgba(0, 255, 136, 0.45); + background: rgba(0, 255, 136, 0.06); + color: var(--accent); + font-weight: 700; + cursor: pointer; + } + + .add-row-btn:hover { + background: rgba(0, 255, 136, 0.12); + } + + @media (max-width: 720px) { + .update-form-grid, + .update-item-form { + grid-template-columns: 1fr; + } + } + .modal-actions { display: flex; gap: 12px; @@ -308,6 +383,7 @@ {% if account_output %} @@ -339,6 +415,21 @@
    {{ parser_output }}
    {% endif %} + + {% if update_output %} +
    +
    Добавление обновления
    +
    + Статус: + {% if update_success %} + успешно + {% else %} + ошибка + {% endif %} +
    +
    {{ update_output }}
    +
    + {% endif %} @@ -376,6 +467,78 @@ + + +