Files
vesti/openspec/changes/archive/2026-09-16-keep-candidates-context/design.md
T

89 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Design
### 1. `_fetch_candidates` — статус по умолчанию vs явный
Текущее (строки ~151-166):
```python
where.append("p.is_own=0")
where.append("p.status='new'")
...
if status and status != "new":
where.append("p.status=?")
params.append(status)
```
Правка:
```python
where.append("p.is_own=0")
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 own in ("1", "0"):
where.append("p.is_own=?")
params.append(int(own))
if q:
where.append("(p.text LIKE ? OR p.summary LIKE ?)")
params += [f"%{q}%", f"%{q}%"]
```
### 2. Скрытые поля в формах правой панели
В `candidates.html` в каждую форму правой панели (approve, reclassify, rewrite,
reject, comment) добавить:
```html
<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 }}">
```
(Переменные `group_by`, `direction`, `own`, `q` уже доступны в контексте рендера
роута `/candidates`.)
### 3. Роуты POST-действий — сохранять контекст
Общий хелпер для построения URL возврата:
```python
def _cand_back(group_by="", direction="", own="", q="", **extra):
parts = []
if group_by:
parts.append(f"group_by={group_by}")
if direction:
parts.append(f"direction={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}={v}")
return "/candidates?" + "&".join(parts) if parts else "/candidates"
```
Применение:
- `reject(post_id, request, group_by="", direction="", own="", q="")`:
`return RedirectResponse(url=_cand_back(group_by, direction, own, q, status="rejected"), status_code=302)`
→ пользователь остаётся в своей группировке, видит список отклонённых.
- `comment`/`reclassify`/`rewrite`: `_cand_back(group_by, direction, own, q, selected=post_id)`.
- `approve`: после успеха — `_cand_back(group_by, direction, own, q, status="published")`
(пользователь видит опубликованные в той же группировке) или `/published`.
Решение: approve возвращает в кандидаты с `status=published` в той же группировке,
чтобы контекст не терялся. Ошибки — `_cand_back(..., selected=post_id, error=err)`.
FastAPI: параметры форм объявляются как `group_by: str = Form("")` и т.д.
## Верификация
- `openspec validate keep-candidates-context` — чисто.
- Юнит: `_fetch_candidates(c,'','rejected','','','date')` → возвращает
отклонённые (не пусто); `_fetch_candidates(c,'','','','','date')` → new внешние.
- Живой: POST /posts/{id}/reject с form group_by=date → редирект на
`/candidates?group_by=date&status=rejected`, список не пуст.
- Рестарт vesti-web.