mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
0999424baa
- _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&...)
89 lines
3.7 KiB
Markdown
89 lines
3.7 KiB
Markdown
## 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. |