Jul 22 - Update - add Rich-text editor, draft/publish, drag-to-reorder
This commit is contained in:
@@ -40,10 +40,11 @@ Ubuntu 24.04. Fonts via Google Fonts (Bricolage Grotesque, IBM Plex Sans/Mono).
|
||||
- `section(id, num UNIQUE, title, subtitle, sort_order)`
|
||||
- `topic(id, section_id FK cascade, slug UNIQUE, title, body_html, link_url,
|
||||
link_label, media_type[none|image|video|embed], media_url, media_caption,
|
||||
sort_order)`
|
||||
sort_order, is_published)`
|
||||
- `audit_log(id, actor, action, entity, entity_id, detail, created_at)`
|
||||
|
||||
Public page orders sections by `sort_order, num`; topics by `sort_order`.
|
||||
Public page orders sections by `sort_order, num`; topics by `sort_order`, and
|
||||
shows only `is_published` topics (sections with no published topics are hidden).
|
||||
|
||||
## Conventions (follow every change)
|
||||
|
||||
@@ -103,12 +104,41 @@ Public page orders sections by `sort_order, num`; topics by `sort_order`.
|
||||
- CSRF-less POST floods get HTTP 400 before the view, so they don't reach the
|
||||
auth log — add nginx `limit_req` on `/admin/login` if that traffic matters.
|
||||
|
||||
## Content editing (rich text / publish / reorder)
|
||||
|
||||
- **Rich text:** Quill 1.3.7 vendored at `static/vendor/` (no CDN — survives a
|
||||
locked-down server or strict CSP). It's a *progressive enhancement over a real
|
||||
`<textarea name="body_html" id="body_src">`*: `body.quill-on` is added only
|
||||
after `new Quill()` succeeds (hides the textarea, shows the editor). If Quill
|
||||
fails to load, the textarea stays usable and a save never wipes the body.
|
||||
- **Sanitize on save:** `sanitize_html()` (bleach) runs on every `body_html`
|
||||
write — allowlist `ALLOWED_TAGS`/`ALLOWED_ATTRS`, `strip=True`, and bleach
|
||||
restricts link protocols to http/https/mailto (blocks `javascript:`). Empty /
|
||||
`<p><br></p>` editor content is stored as NULL. The public page still renders
|
||||
`body_html` via `Markup`, but the content is now sanitized at the source.
|
||||
- **Draft/publish:** `topic.is_published` (default 1, so existing rows stay
|
||||
live). Public route filters to `Section.published_topics` and drops sections
|
||||
with none. Admin: per-topic `/topic/<id>/toggle` (quick button) + a Published
|
||||
checkbox on the form; dashboard shows a `draft` badge. New topics default
|
||||
published (least surprise); uncheck to stage a draft.
|
||||
- **Drag reorder:** SortableJS 1.15.2 vendored. Dashboard drags post JSON to
|
||||
`/admin/reorder` with the CSRF token from `<meta name="csrf-token">` sent as
|
||||
the `X-CSRFToken` header (Flask-WTF accepts that header for AJAX). Payloads:
|
||||
`{type:'topic',section_id,order:[ids]}` (within-section only) or
|
||||
`{type:'section',order:[ids]}`; sort values rewritten 10,20,30…. The topic
|
||||
branch filters `Topic.section_id == section_id` so a spoofed cross-section id
|
||||
is ignored. Cross-section moves are done via the section dropdown on the form.
|
||||
- **CDN caveat (testing):** the build sandbox proxy 403s all external CDNs incl.
|
||||
Google Fonts — that's why libs are vendored. Fonts still load fine on the real
|
||||
server; they degrade to system fonts if blocked.
|
||||
|
||||
## Deploy delta cheatsheet
|
||||
|
||||
```bash
|
||||
sudo mysql < add_admin.sql # audit_log (existing DBs)
|
||||
sudo mysql < add_publish.sql # topic.is_published (existing DBs)
|
||||
# .env: SECRET_KEY, ADMIN_USERNAME, ADMIN_PASSWORD_HASH, SESSION_COOKIE_SECURE=1
|
||||
sudo ./venv/bin/pip install -r requirements.txt
|
||||
sudo ./venv/bin/pip install -r requirements.txt # includes bleach
|
||||
sudo systemctl restart jqc-features
|
||||
# fail2ban:
|
||||
sudo cp deploy/fail2ban/filter.d/jqc-admin.conf /etc/fail2ban/filter.d/
|
||||
|
||||
Reference in New Issue
Block a user