homepage v0.2.0 [base]
Блоки домашней страницы веб-панели (/api/homepage).
| version | date | commit | файлов |
|---|---|---|---|
| 0.2.0 | 2026-09-17 | 91610a9fc155 | 8 |
README
# homepage
Блоки домашней страницы веб-панели: что видит гость без входа.
Тип: Модуль. Категория: `base`. Зависимостей нет.
## Описание
Публичная витрина панели. Текстовые блоки домашней страницы — объявления, ссылки, памятки — читаются без входа, а правятся прямо в кабинете.
На сохранение стоят лимиты: число блоков и ссылок ограничено, чтобы витрину нельзя было раздуть до бесконечности.
## Возможности
- `load` `{}` → `{blocks: [...]}` — конфиг блоков домашней страницы
- `save` `{data: {blocks: [...]}}` → сохранить блоки
## Права
- `homepage_edit` — Редактирование блоков домашней (POST /api/homepage)
## Web
- `GET /api/homepage` — блоки (публично)
- `POST /api/homepage` — сохранить (право `homepage_edit`)
## Конфигурация (`config.schema.json`)
- обязательных нет; опциональные (дефолты):
- `HOMEPAGE_FILE` = `` (не задан) — путь файла блоков
Манифест
{
"name": "homepage",
"version": "0.2.0",
"category": "base",
"description": "Блоки домашней страницы веб-панели (/api/homepage).",
"requires": [],
"rights": [],
"api_methods": [],
"web_routes": [],
"commit": "91610a9fc1556c139f02139ef0fd9a4504251dcf",
"updated": "2026-09-17 12:26:56 +0300",
"integrity": "sha256:5e4ac528aeba325e0291e64b2f4756f74b6e7fe92fa63288ef337c950c237686",
"files": "[8 файлов — см. вкладки ниже]",
"note": "",
"wdesc": "",
"wbody": "",
"_extra": {
"api": "",
"events_emitted": "[]",
"events_subscribed": "[]",
"shared_routes": "",
"config_schema": "config.schema.json",
"env_example": ".env.example"
}
} Файлы и исходники
Дерево файлов
- · корень
- 1.3 КБ
- 0.1 КБ
- 0.9 КБ
- 0.8 КБ
- 1.2 КБ
- 1.7 КБ
- web/
- 0.4 КБ
- 18.9 КБ
Предпросмотр
Выберите файл в дереве выше — код откроется здесь.
Все исходники (.py) одним списком
engine.py 0.9 КБ
"""homepage.engine — хранение блоков домашней страницы (JSON-файл)."""
import json
import logging
import os
import threading
logger = logging.getLogger(__name__)
_lock = threading.Lock()
_file = ""
def configure(path: str) -> None:
global _file
_file = path
def load():
try:
with open(_file, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
return {"blocks": []}
def save(data) -> bool:
with _lock:
try:
os.makedirs(os.path.dirname(_file) or ".", exist_ok=True)
tmp = _file + ".tmp"
with open(tmp, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
os.replace(tmp, _file)
return True
except OSError as e:
logger.warning("Не удалось сохранить homepage: %s", e)
return False
module.py 1.2 КБ
"""homepage.Module — блоки домашней страницы веб-панели (/api/homepage)."""
import logging
import os
from core.base_module import BaseModule
from . import engine as hp
logger = logging.getLogger(__name__)
class Module(BaseModule):
def setup(self, ctx) -> None:
mod_dir = os.path.dirname(os.path.abspath(__file__))
self.config = ctx.module_config("homepage", mod_dir)
self.ctx = ctx
def _f(key, default):
return (self.config.get(key, "") or "").strip() or default
def _fp(key, default):
from core.paths import abs_data
return abs_data(ctx.data_dir,
(self.config.get(key, "") or "").strip(),
default)
hp.configure(_fp("HOMEPAGE_FILE",
os.path.join(ctx.data_dir, "homepage.json")))
ctx.api.register("homepage", "load", hp.load)
ctx.api.register("homepage", "save", hp.save)
def health(self) -> dict:
try:
blocks = len((hp.load().get("blocks") or []))
except Exception: # noqa: BLE001
blocks = -1
return {"ok": blocks >= 0, "module": self.name, "blocks": blocks}
ui_web.py 1.7 КБ
"""homepage.ui_web — GET/POST /api/homepage (блоки домашней страницы).
Порт HomepageHandler из старого messengers/web.py. GET публичный,
POST — право homepage_edit. Лимиты как в старом: ≤200 блоков,
≤200 ссылок на блок.
"""
ROUTES = [
("GET", "/api/homepage", "homepage", {"right": None}),
("POST", "/api/homepage", "homepage", {"right": "homepage_edit"}),
]
PANELS = []
NAV = [{"id": "homepage", "title": "Домашняя", "view": "homepage",
"icon": "", "right": None}]
def handle_api(ctx, config, method, req):
from core.errors import UserError
from . import engine as hp
if method == "homepage":
if req.get("http_method") == "GET":
data = hp.load()
if not isinstance(data, dict):
data = {}
blocks = data.get("blocks", [])
if not isinstance(blocks, list):
blocks = []
return {"ok": True, "blocks": blocks}
body = req.get("body") or {}
blocks = body.get("blocks", [])
if not isinstance(blocks, list):
return 400, {"ok": False, "error": "blocks должен быть списком"}
if len(blocks) > 200 or any(
not isinstance(b, dict) or len(b.get("links") or []) > 200 for b in blocks
):
return 400, {"ok": False, "error": "Слишком большой конфиг"}
if not hp.save({"blocks": blocks}):
return 500, {"ok": False, "error": "Ошибка записи"}
return {"ok": True}
raise UserError("неизвестный метод: %s" % method)