Fix editor action updates

This commit is contained in:
Your Name
2026-07-28 12:52:24 +05:00
parent 3ab8a7b4f2
commit 89adc6852d
5 changed files with 105 additions and 70 deletions
+52 -21
View File
@@ -2709,6 +2709,30 @@ async def fetch_single_editor_row(pool, post_id: int):
post_id
)
async def editor_post_update_response(
request: Request,
user: dict,
pool,
post_id: int,
action_message: str = "",
action_tone: str = "info",
):
row = await fetch_single_editor_row(pool, post_id)
if not row:
return HTMLResponse("", status_code=204)
return templates.TemplateResponse(
"editor_post_update.html",
base_context(
request,
user,
p=prepare_editor_post(row),
action_message=action_message,
action_tone=action_tone,
),
)
@app.get("/editor", response_class=HTMLResponse)
async def editor_feed(
request: Request,
@@ -2926,13 +2950,7 @@ async def editor_accept(request: Request, post_id: int, csrf_token: str = Form(.
)
await audit(user["id"], "editor.accept", "raw_post", post_id)
if request.headers.get("hx-request"):
row = await fetch_single_editor_row(pool, post_id)
if row:
categories = await writer_category_options()
return templates.TemplateResponse(
"editor_post.html",
base_context(request, user, p=prepare_editor_post(row), categories=categories)
)
return await editor_post_update_response(request, user, pool, post_id, "Принято к публикации", "success")
return redirect("/editor")
@@ -2959,13 +2977,31 @@ async def editor_reject(request: Request, post_id: int, csrf_token: str = Form(.
)
await audit(user["id"], "editor.reject", "raw_post", post_id)
if request.headers.get("hx-request"):
row = await fetch_single_editor_row(pool, post_id)
if row:
categories = await writer_category_options()
return templates.TemplateResponse(
"editor_post.html",
base_context(request, user, p=prepare_editor_post(row), categories=categories)
)
return await editor_post_update_response(request, user, pool, post_id, "Отклонено", "error")
return redirect("/editor")
@app.post("/editor/{post_id}/return")
async def editor_return_to_review(request: Request, post_id: int, csrf_token: str = Form(...)):
user = await get_current_user(request)
if not user:
return redirect("/login")
require_csrf(user, csrf_token)
pool = await get_pool()
await pool.execute(
"""
UPDATE raw_posts
SET editorial_status=NULL,
reviewed_by=NULL,
reviewed_at=NULL,
updated_at=NOW()
WHERE id=$1 AND rewrite_status='ready'
""",
post_id,
)
await audit(user["id"], "editor.return_to_review", "raw_post", post_id)
if request.headers.get("hx-request"):
return await editor_post_update_response(request, user, pool, post_id, "Возвращено на проверку", "warning")
return redirect("/editor")
@@ -3094,13 +3130,8 @@ async def editor_save(
)
await audit(user["id"], "editor.save" if status_value == "edited" else "editor.save_accept", "raw_post", post_id)
if request.headers.get("hx-request"):
row = await fetch_single_editor_row(pool, post_id)
if row:
categories = await writer_category_options()
return templates.TemplateResponse(
"editor_post.html",
base_context(request, user, p=prepare_editor_post(row), categories=categories)
)
message = "Принято к публикации" if status_value == "accepted" else "Сохранено как черновик"
return await editor_post_update_response(request, user, pool, post_id, message, "success")
return redirect("/editor")
+3 -49
View File
@@ -1,4 +1,4 @@
<form hx-post="/editor/{{ p.id }}/save" hx-target="#post-container-{{ p.id }}" hx-swap="outerHTML" hx-encoding="multipart/form-data" id="post-container-{{ p.id }}" class="card flex flex-col group relative transition-colors border border-app-border {% if p.editorial_status == 'accepted' %}bg-app-successBg/10 border-app-success/20{% elif p.editorial_status == 'rejected' %}bg-app-errorBg/10 opacity-75{% else %}hover:border-app-borderFocus hover:shadow-glow{% endif %}">
<form hx-post="/editor/{{ p.id }}/save" hx-target="#post-actions-{{ p.id }}" hx-swap="outerHTML" hx-encoding="multipart/form-data" id="post-container-{{ p.id }}" class="card flex flex-col group relative transition-colors border border-app-border {% if p.editorial_status == 'accepted' %}bg-app-successBg/10 border-app-success/20{% elif p.editorial_status == 'rejected' %}bg-app-errorBg/10 opacity-75{% else %}hover:border-app-borderFocus hover:shadow-glow{% endif %}">
<input type="hidden" name="csrf_token" value="{{ user.csrf_token }}">
<div class="flex flex-col">
@@ -6,23 +6,7 @@
<div class="w-full bg-app-bg/50 border-b border-app-border p-4 flex flex-col gap-3 md:flex-row md:flex-wrap md:items-center">
<div class="flex items-center justify-between gap-3 md:justify-start">
<span class="text-xs font-mono text-app-textMuted tracking-wider">#{{ p.id }}</span>
{% if p.editorial_status == 'accepted' or p.editorial_status == 'published' %}
<div class="flex items-center gap-1 text-xs font-medium text-app-success bg-app-success/10 px-2 py-1 rounded-md">
<i data-lucide="check-circle-2" class="w-3 h-3"></i> Принят
</div>
{% elif p.editorial_status == 'rejected' or p.editorial_status == 'publish_failed' %}
<div class="flex items-center gap-1 text-xs font-medium text-app-error bg-app-error/10 px-2 py-1 rounded-md">
<i data-lucide="x-circle" class="w-3 h-3"></i> Отклонен
</div>
{% elif p.editorial_status == 'regenerating' %}
<div class="flex items-center gap-1 text-xs font-medium text-app-warning bg-app-warning/10 px-2 py-1 rounded-md">
<i data-lucide="refresh-cw" class="w-3 h-3 animate-spin"></i> В работе
</div>
{% else %}
<div class="flex items-center gap-1 text-xs font-medium text-blue-400 bg-blue-400/10 px-2 py-1 rounded-md">
<i data-lucide="clock" class="w-3 h-3"></i> Ожидает
</div>
{% endif %}
{% include "editor_post_status.html" %}
</div>
<div class="flex items-center gap-2">
@@ -190,37 +174,7 @@
</div>
<!-- Actions -->
{% if p.editorial_status != 'published' %}
<div class="mt-5 pt-4 border-t border-app-border flex flex-wrap items-center justify-between gap-3">
{% if p.editorial_status == 'rejected' %}
<div>
<button class="btn btn-ghost btn-sm text-app-warning hover:bg-app-warning/10 hover:text-app-warning" type="button"
hx-post="/editor/{{ p.id }}/return" hx-target="#post-container-{{ p.id }}" hx-swap="outerHTML"
hx-vals='{"csrf_token": "{{ user.csrf_token }}"}'>
<i data-lucide="corner-up-left" class="w-4 h-4"></i> Вернуть на проверку
</button>
</div>
{% else %}
<!-- Delete Button -->
<div>
<button class="btn btn-ghost btn-sm text-app-error hover:bg-app-errorBg hover:text-app-error" type="button"
hx-post="/editor/{{ p.id }}/reject" hx-target="#post-container-{{ p.id }}" hx-swap="outerHTML"
hx-vals='{"csrf_token": "{{ user.csrf_token }}"}'>
<i data-lucide="x" class="w-4 h-4"></i> Отклонить
</button>
</div>
<div class="flex gap-2">
<button type="submit" name="action" value="save" class="btn btn-surface btn-sm">
<i data-lucide="save" class="w-4 h-4"></i> Сохранить как черновик
</button>
<button type="submit" name="action" value="accept" class="btn btn-primary btn-sm">
<i data-lucide="send" class="w-4 h-4"></i> Сохранить и Опубликовать
</button>
</div>
{% endif %}
</div>
{% endif %}
{% include "editor_post_actions.html" %}
</div>
</div>
</form>
@@ -0,0 +1,36 @@
{% if p.editorial_status != 'published' %}
<div id="post-actions-{{ p.id }}" class="mt-5 pt-4 border-t border-app-border flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-3">
{% if action_message %}
<div class="flex items-center gap-2 text-sm font-medium {% if action_tone == 'success' %}text-app-success{% elif action_tone == 'warning' %}text-app-warning{% elif action_tone == 'error' %}text-app-error{% else %}text-app-textMuted{% endif %}">
<i data-lucide="{% if action_tone == 'success' %}check-circle-2{% elif action_tone == 'warning' %}corner-up-left{% elif action_tone == 'error' %}x-circle{% else %}info{% endif %}" class="w-4 h-4"></i>
{{ action_message }}
</div>
{% endif %}
{% if p.editorial_status in ['rejected', 'accepted', 'publish_failed'] %}
<button class="btn btn-ghost btn-sm text-app-warning hover:bg-app-warning/10 hover:text-app-warning" type="button"
hx-post="/editor/{{ p.id }}/return" hx-target="#post-actions-{{ p.id }}" hx-swap="outerHTML"
hx-vals='{"csrf_token": "{{ user.csrf_token }}"}'>
<i data-lucide="corner-up-left" class="w-4 h-4"></i> Вернуть на проверку
</button>
{% else %}
<button class="btn btn-ghost btn-sm text-app-error hover:bg-app-errorBg hover:text-app-error" type="button"
hx-post="/editor/{{ p.id }}/reject" hx-target="#post-actions-{{ p.id }}" hx-swap="outerHTML"
hx-vals='{"csrf_token": "{{ user.csrf_token }}"}'>
<i data-lucide="x" class="w-4 h-4"></i> Отклонить
</button>
{% endif %}
</div>
{% if p.editorial_status not in ['rejected', 'accepted', 'publish_failed'] %}
<div class="flex gap-2">
<button type="submit" name="action" value="save" class="btn btn-surface btn-sm">
<i data-lucide="save" class="w-4 h-4"></i> Сохранить как черновик
</button>
<button type="submit" name="action" value="accept" class="btn btn-primary btn-sm">
<i data-lucide="send" class="w-4 h-4"></i> Сохранить и Опубликовать
</button>
</div>
{% endif %}
</div>
{% endif %}
@@ -0,0 +1,11 @@
<div id="post-status-{{ p.id }}" {% if status_oob %}hx-swap-oob="outerHTML"{% endif %} class="flex items-center gap-1 text-xs font-medium {% if p.editorial_status == 'accepted' or p.editorial_status == 'published' %}text-app-success bg-app-success/10{% elif p.editorial_status == 'rejected' or p.editorial_status == 'publish_failed' %}text-app-error bg-app-error/10{% elif p.editorial_status == 'regenerating' %}text-app-warning bg-app-warning/10{% else %}text-blue-400 bg-blue-400/10{% endif %} px-2 py-1 rounded-md">
{% if p.editorial_status == 'accepted' or p.editorial_status == 'published' %}
<i data-lucide="check-circle-2" class="w-3 h-3"></i> Принят
{% elif p.editorial_status == 'rejected' or p.editorial_status == 'publish_failed' %}
<i data-lucide="x-circle" class="w-3 h-3"></i> Отклонен
{% elif p.editorial_status == 'regenerating' %}
<i data-lucide="refresh-cw" class="w-3 h-3 animate-spin"></i> В работе
{% else %}
<i data-lucide="clock" class="w-3 h-3"></i> Ожидает
{% endif %}
</div>
@@ -0,0 +1,3 @@
{% include "editor_post_actions.html" %}
{% set status_oob = true %}
{% include "editor_post_status.html" %}