Jul 24 - Update Rich-text editor to support uploading images and inserting table
This commit is contained in:
@@ -106,16 +106,28 @@ shows only `is_published` topics (sections with no published topics are hidden).
|
||||
|
||||
## 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.
|
||||
- **Rich text:** Quill 2.0.3 vendored at `static/vendor/quill.min.js` +
|
||||
`quill.snow.css` (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. The submit handler keeps the body when it contains an
|
||||
`img`/`table` even though `getText()` is empty for embed-only content.
|
||||
- **Images & tables:** the custom `#editor-toolbar` has a `ql-image` button and a
|
||||
`.ql-table-op` button group. Images upload via `POST /admin/upload`
|
||||
(`login_required`, CSRF via `X-CSRFToken` header): extension allowlist +
|
||||
magic-byte sniff (`_sniff_image`, SVG excluded), 8 MB cap, saved as a random
|
||||
`uuid4().hex.<ext>` under `static/uploads/`, returns `{url}`; the handler
|
||||
`insertEmbed`s it (no base64 → DB stays small). Tables use Quill 2's *built-in*
|
||||
`table: true` module (`getModule('table')` → insertTable/insertRow…/deleteTable) —
|
||||
no third-party plugin. Table buttons `preventDefault` on mousedown to keep the
|
||||
cell selection; cell-dependent ops are wrapped in try/catch.
|
||||
- **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.
|
||||
write — allowlist `ALLOWED_TAGS`/`ALLOWED_ATTRS` (now includes `img` + table
|
||||
tags + `data-row`), `strip=True`; bleach restricts URL protocols on both `href`
|
||||
and `img src` to http/https/mailto, blocking `javascript:` and `data:` (uploads
|
||||
are relative `/static` paths). Empty / `<p><br></p>` editor content is stored as
|
||||
NULL. The public page renders `body_html` via `Markup`, 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
|
||||
@@ -139,7 +151,8 @@ 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 # includes bleach
|
||||
sudo systemctl restart jqc-features
|
||||
sudo -u jqc mkdir -p static/uploads # in-body image uploads (writable)
|
||||
sudo systemctl restart jqc-features # Quill 2 assets are static — no other step
|
||||
# fail2ban:
|
||||
sudo cp deploy/fail2ban/filter.d/jqc-admin.conf /etc/fail2ban/filter.d/
|
||||
sudo cp deploy/fail2ban/jail.d/jqc-admin.local /etc/fail2ban/jail.d/
|
||||
|
||||
Reference in New Issue
Block a user