mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
fix(candidates): сохранять группировку после действий, чинить пустой ?status=rejected
- _fetch_candidates: жёсткое status='new' только при пустом status; явный статус (rejected/published) — единственный фильтр статуса → ?status=rejected больше не даёт пустой список - формы approve/reclassify/rewrite/reject/comment: скрытые поля group_by/direction/own/q — контекст страницы - POST-роуты: редирект через _cand_back() сохраняет группировку и фильтры (reject → ?status=rejected&group_by=...; approve → ?status=published&...)
This commit is contained in:
+44
-20
@@ -120,6 +120,23 @@ def _row(r):
|
||||
return _Row(dict(r)) if r is not None else None
|
||||
|
||||
|
||||
def _cand_back(group_by: str = "", direction: str = "", own: str = "", q: str = "", **extra):
|
||||
"""URL возврата в /candidates с сохранением группировки и фильтров."""
|
||||
parts = []
|
||||
if group_by:
|
||||
parts.append(f"group_by={quote(group_by)}")
|
||||
if direction:
|
||||
parts.append(f"direction={quote(direction)}")
|
||||
if own in ("0", "1"):
|
||||
parts.append(f"own={own}")
|
||||
if q:
|
||||
parts.append(f"q={quote(q)}")
|
||||
for k, v in extra.items():
|
||||
if v:
|
||||
parts.append(f"{k}={quote(str(v))}")
|
||||
return "/candidates?" + "&".join(parts) if parts else "/candidates"
|
||||
|
||||
|
||||
STATUS_LABELS = {
|
||||
"new": "💎 Новые",
|
||||
"rejected": "🗑 Отклонённые",
|
||||
@@ -155,15 +172,16 @@ def _fetch_candidates(conn, direction: str, status: str, own: str, q: str, group
|
||||
# собственного канала, управляется отдельно (fan-out); published/rejected —
|
||||
# уже решённые посты, им не место в очереди кандидатов.
|
||||
where.append("p.is_own=0")
|
||||
where.append("p.status='new'")
|
||||
if not status:
|
||||
# по умолчанию — только кандидаты (new); явный статус ниже
|
||||
where.append("p.status='new'")
|
||||
else:
|
||||
# явный статус (new/rejected/published) — единственный фильтр статуса
|
||||
where.append("p.status=?")
|
||||
params.append(status)
|
||||
if direction:
|
||||
where.append("p.direction=?")
|
||||
params.append(direction)
|
||||
if status and status != "new":
|
||||
# Явный фильтр статуса (rejected/published) — просмотр решённых;
|
||||
# для 'new' условие уже добавлено выше.
|
||||
where.append("p.status=?")
|
||||
params.append(status)
|
||||
if own in ("1", "0"):
|
||||
where.append("p.is_own=?")
|
||||
params.append(int(own))
|
||||
@@ -360,24 +378,26 @@ def candidates_bulk(request: Request, action: str = Form(...), ids: list[int] =
|
||||
|
||||
|
||||
@app.post("/posts/{post_id}/comment")
|
||||
def post_comment(post_id: int, request: Request, comment: str = Form("")):
|
||||
def post_comment(post_id: int, request: Request, comment: str = Form(""),
|
||||
group_by: str = Form(""), direction: str = Form(""), own: str = Form(""), q: str = Form("")):
|
||||
_require_auth(request)
|
||||
conn = _db()
|
||||
conn.execute("UPDATE posts SET comment=? WHERE id=?", (comment.strip(), post_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id), status_code=302)
|
||||
|
||||
|
||||
@app.post("/posts/{post_id}/reclassify")
|
||||
def post_reclassify(post_id: int, request: Request):
|
||||
def post_reclassify(post_id: int, request: Request,
|
||||
group_by: str = Form(""), direction: str = Form(""), own: str = Form(""), q: str = Form("")):
|
||||
"""Переклассификация кандидата локальной моделью (qwen)."""
|
||||
_require_auth(request)
|
||||
try:
|
||||
impl_reclassify(post_id)
|
||||
except Exception as e:
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}&error=reclassify:{e}", status_code=302)
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id, error=f"reclassify:{e}"), status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id), status_code=302)
|
||||
|
||||
|
||||
def impl_reclassify(post_id: int):
|
||||
@@ -398,14 +418,15 @@ def impl_reclassify(post_id: int):
|
||||
|
||||
|
||||
@app.post("/posts/{post_id}/rewrite")
|
||||
def post_rewrite(post_id: int, request: Request):
|
||||
def post_rewrite(post_id: int, request: Request,
|
||||
group_by: str = Form(""), direction: str = Form(""), own: str = Form(""), q: str = Form("")):
|
||||
_require_auth(request)
|
||||
from classifier.classify import call_ollama
|
||||
conn = _db()
|
||||
p = conn.execute("SELECT * FROM posts WHERE id=?", (post_id,)).fetchone()
|
||||
if not p:
|
||||
conn.close()
|
||||
return RedirectResponse(url="/candidates?error=notfound", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, error="notfound"), status_code=302)
|
||||
d = dict(p)
|
||||
text_ = (d.get("text") or "")[:2000]
|
||||
prompt = (
|
||||
@@ -421,11 +442,11 @@ def post_rewrite(post_id: int, request: Request):
|
||||
draft = r.get("summary") or ""
|
||||
except Exception as e:
|
||||
conn.close()
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}&error=rewrite:{e}", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id, error=f"rewrite:{e}"), status_code=302)
|
||||
conn.execute("UPDATE posts SET rewritten_text=? WHERE id=?", (draft, post_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id), status_code=302)
|
||||
|
||||
|
||||
@app.get("/published", response_class=HTMLResponse)
|
||||
@@ -506,7 +527,8 @@ def impl_approve(post_id: int, comment: str = "", dirs_selected: list[str] | Non
|
||||
|
||||
|
||||
@app.post("/posts/{post_id}/approve")
|
||||
async def approve(post_id: int, request: Request):
|
||||
async def approve(post_id: int, request: Request,
|
||||
group_by: str = Form(""), direction: str = Form(""), own: str = Form(""), q: str = Form("")):
|
||||
"""Подтверждение черновика → публикация в TG (fan-out по направлениям) + создание бандла + статус published."""
|
||||
_require_auth(request)
|
||||
# направления fan-out: из формы (чекбоксы) — по умолчанию направления классификации или направление поста
|
||||
@@ -520,18 +542,20 @@ async def approve(post_id: int, request: Request):
|
||||
pass
|
||||
err = impl_approve(post_id, comment, dirs_selected)
|
||||
if err:
|
||||
return RedirectResponse(url=f"/candidates?selected={post_id}&error={err}", status_code=302)
|
||||
return RedirectResponse(url="/published", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, selected=post_id, error=err), status_code=302)
|
||||
# после публикации остаёмся в своей группировке, смотрим опубликованные
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, status="published"), status_code=302)
|
||||
|
||||
|
||||
@app.post("/posts/{post_id}/reject")
|
||||
def reject(post_id: int, request: Request):
|
||||
def reject(post_id: int, request: Request, group_by: str = Form(""), direction: str = Form(""),
|
||||
own: str = Form(""), q: str = Form("")):
|
||||
_require_auth(request)
|
||||
conn = _db()
|
||||
conn.execute("UPDATE posts SET status='rejected' WHERE id=?", (post_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return RedirectResponse(url="/candidates?status=rejected", status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, status="rejected"), status_code=302)
|
||||
|
||||
|
||||
@app.get("/metrics", response_class=HTMLResponse)
|
||||
|
||||
@@ -138,23 +138,28 @@
|
||||
</div>
|
||||
|
||||
<div class="mb-3 d-flex flex-wrap gap-2">
|
||||
{% set hid %}<input type="hidden" name="group_by" value="{{ group_by }}"><input type="hidden" name="direction" value="{{ direction }}"><input type="hidden" name="own" value="{{ own }}"><input type="hidden" name="q" value="{{ q }}">{% endset %}
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/approve">
|
||||
{{ hid }}
|
||||
<button class="btn btn-success" type="submit">✅ Опубликовать</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reclassify">
|
||||
{{ hid }}
|
||||
<button class="btn btn-info" type="submit">🤖 Обработать моделью</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/rewrite">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-primary" type="submit">✍️ Переписать</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'rejected' and selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reject">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-danger" type="submit">🚫 Отклонить</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
@@ -162,6 +167,7 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<form method="post" action="/posts/{{ selected.id }}/comment">
|
||||
{{ hid }}
|
||||
<label class="form-label small text-muted">💬 Мой комментарий (будет первым в канале):</label>
|
||||
<textarea class="form-control form-control-sm" name="comment" rows="2"
|
||||
placeholder="Комментарий/анонс…">{{ selected.comment or '' }}</textarea>
|
||||
|
||||
Reference in New Issue
Block a user