Fix editor action updates
This commit is contained in:
+51
-20
@@ -2709,6 +2709,30 @@ async def fetch_single_editor_row(pool, post_id: int):
|
|||||||
post_id
|
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)
|
@app.get("/editor", response_class=HTMLResponse)
|
||||||
async def editor_feed(
|
async def editor_feed(
|
||||||
request: Request,
|
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)
|
await audit(user["id"], "editor.accept", "raw_post", post_id)
|
||||||
if request.headers.get("hx-request"):
|
if request.headers.get("hx-request"):
|
||||||
row = await fetch_single_editor_row(pool, post_id)
|
return await editor_post_update_response(request, user, pool, post_id, "Принято к публикации", "success")
|
||||||
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 redirect("/editor")
|
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)
|
await audit(user["id"], "editor.reject", "raw_post", post_id)
|
||||||
if request.headers.get("hx-request"):
|
if request.headers.get("hx-request"):
|
||||||
row = await fetch_single_editor_row(pool, post_id)
|
return await editor_post_update_response(request, user, pool, post_id, "Отклонено", "error")
|
||||||
if row:
|
return redirect("/editor")
|
||||||
categories = await writer_category_options()
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
"editor_post.html",
|
@app.post("/editor/{post_id}/return")
|
||||||
base_context(request, user, p=prepare_editor_post(row), categories=categories)
|
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")
|
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)
|
await audit(user["id"], "editor.save" if status_value == "edited" else "editor.save_accept", "raw_post", post_id)
|
||||||
if request.headers.get("hx-request"):
|
if request.headers.get("hx-request"):
|
||||||
row = await fetch_single_editor_row(pool, post_id)
|
message = "Принято к публикации" if status_value == "accepted" else "Сохранено как черновик"
|
||||||
if row:
|
return await editor_post_update_response(request, user, pool, post_id, message, "success")
|
||||||
categories = await writer_category_options()
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
"editor_post.html",
|
|
||||||
base_context(request, user, p=prepare_editor_post(row), categories=categories)
|
|
||||||
)
|
|
||||||
return redirect("/editor")
|
return redirect("/editor")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 }}">
|
<input type="hidden" name="csrf_token" value="{{ user.csrf_token }}">
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<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="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">
|
<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>
|
<span class="text-xs font-mono text-app-textMuted tracking-wider">#{{ p.id }}</span>
|
||||||
{% if p.editorial_status == 'accepted' or p.editorial_status == 'published' %}
|
{% include "editor_post_status.html" %}
|
||||||
<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 %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -190,37 +174,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
{% if p.editorial_status != 'published' %}
|
{% include "editor_post_actions.html" %}
|
||||||
<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 %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</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" %}
|
||||||
Reference in New Issue
Block a user