Commit Graph

26 Commits

Author SHA1 Message Date
a3551f2bdf fix(classes): sanitize content_html with bluemonday instead of regex checks
- FormatHTML sanitizes the goldmark output with a bluemonday UGC policy
  extended only with what goldmark and the imported posts and categories
  use; unsafe markup is stripped, as Winter's Html::clean strips it
- HTML the policy keeps whole is stored byte for byte (token comparison)
- CheckHTML keeps its signature and 422 contract, refusing HTML the
  policy would change
- the three regexes are gone: the CR-01 bypasses are neutralized and
  "Data:" or "metadata:" text is no longer refused (WR-01)
2026-10-09 23:35:23 +02:00
03907ee387 test: FormatHTML keep and refuse coverage, admin re-save keeps HTML
- TestFormatHTMLKeepsRawHTML: imported-style bodies (paragraphs, attributes, https links and images, entities) round-trip; markdown keeps a trailing raw footer and style
- TestFormatHTMLRejectsUnsafeHTML: every unsafe case must return an error now that the gate is the only defence; adds svg onload, mixed-case schemes and tags, object, embed, script in an HTML block and raw data URLs
- TestPostsAdminResaveKeepsHTML: an admin update of HTML content keeps content_html
2026-10-09 22:48:59 +02:00
a675f2f197 chore(deps): require summercms v0.1.16 2026-10-09 21:32:49 +02:00
528d2d8451 fix(classes): keep raw HTML in content_html behind the safety gate
- FormatHTML renders with goldmark html.WithUnsafe(), as Winter's
  Markdown::parse passes raw HTML through, so an admin save, an import or
  an API write no longer turns imported HTML into raw HTML omitted
- rejectUnsafe still runs after the render and refuses script, iframe,
  object and embed tags, event handlers and javascript, vbscript and data
  URLs; API response shapes are unchanged
- TestFormatHTMLKeepsRawHTML covers HTML paragraphs and a raw footer
2026-10-09 20:58:49 +02:00
3d533d49f0 test(updates): expect category content in the Category.Fillable list pinned by TestJournalTables
TestJournalTables pins the exact Category.Fillable allow-list, like
models/fillable_test.go. The admin form needs content in Fillable (D-21).
v0.1.1
2026-10-09 16:26:58 +02:00
f22d08902e feat(admin): edit category content in the admin form behind the HTML gate
- add a content textarea (size huge) after description, with en and pl phrases
- add content to Category.Fillable
- export classes.CheckHTML and run it from FormBeforeCreate and FormBeforeUpdate:
  unsafe category content answers 422 on content, blank content is stored as NULL
2026-10-09 16:26:12 +02:00
740dcd086d feat(api): serve the category content field on GET /_journal/api/v1/categories
- add the nullable TEXT column golem15_journal_categories.content (migration 202610090001)
- map it as models.Category.Content and emit category content on every categories row
- document the categories row shape and the stored-as-is HTML semantics
2026-10-09 16:24:20 +02:00
57a347c97b feat(api): list an author's published posts at /authors/{author}/posts
- AuthorPosts reuses the /posts published predicate, per_page clamp, sort allow-list and row serializer
- Bearer tokens are ignored; drafts and scheduled posts never appear
- Both author routes share one resolve-or-respond helper for identical 404/500 paths
- Document query keys, envelope and 404 in README
2026-10-09 13:20:39 +02:00
908ade9c78 feat(api): anonymous author profile at /_journal/api/v1/authors/{author}
- Resolve {author} by golem15_bloghub_author_slug, then by login for users with a published post
- Project only id, names, login and author slug from backend_users; payload is id, slug, first_name, last_name
- JSON 404 {"error":"Author not found"} for unknown, soft-deleted and malformed values
- Document the route in README
2026-10-09 13:19:35 +02:00
Jakub Zych
f5cd5b16fe fix(admin): title the posts list Posts, not New post
The admin names a list page, its heading and breadcrumb after the first
side-menu item of its controller. The new_post item pointed at the posts
list too, came first and won. A side item cannot open the create form, so
drop it; the list toolbar's Create button stays.
2026-10-07 18:02:36 +02:00
Jakub Zych
9327e1e4f3 chore: pin v0.1.0 plugin dependencies v0.1.0 2026-10-07 11:11:07 +02:00
Jakub Zych
be4f33a72e fix(admin): apply Journal form follow-ups 2026-10-07 11:11:02 +02:00
Jakub Zych
d09edde080 test(15-04): complete PHPUnit map, migrations, FormatHTML, and search-gate tests
Named JOURNAL-001/002 fillable, FormatHTML unsafe tags, rollback/remigrate, RSS/categories/tags/media, and TestSearchGateOff with zero Typesense HTTP.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 19:18:53 +02:00
Jakub Zych
c5b44b6a5d test(15-04): prove journal migrate-admin-list-write-draft path on Postgres
- Add TestJournalEndToEnd through party/surf/cabana on real Postgres
- Extract the admin harness and activate user+translate+journal in Requires order
- Anonymous list hides drafts; Bearer writes; JOURNAL-005 404 has no data key

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 19:11:52 +02:00
Jakub Zych
bdd1c1be61 feat(15-03): add journal media upload, RSS, and off-by-default Typesense gate
- POST /_journal/api/v1/media/upload requires access_posts and stays under journal/
- Anonymous GET rss is RSS 2.0 honoring rss_* settings; unpublished posts are omitted
- beachcomber Gate reads search_use_typesense (default false) so a fresh save makes no Typesense HTTP

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 19:03:35 +02:00
Jakub Zych
3a1dda45ec feat(15-03): enforce JOURNAL-005 draft 404 and backend-Bearer writes
- Show unpublished or future posts as 404 without a data key unless owner or access_other_posts
- POST/PUT/DELETE posts and featured-images require a backend-audience JWT and PHP {error} strings
- Anonymous GET categories and tags return the PHP list keys; frontend-audience tokens cannot write

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:59:12 +02:00
Jakub Zych
f2e5b3d072 feat(15-03): serve anonymous GET /_journal/api/v1/posts as a published list
- Public and write groups under /_journal/api/v1 with journal-public-api and journal-api buckets (Max 120)
- Index omits drafts and future published_at; per_page default 9 max 30
- Optional backend JWT on GET; missing Bearer on writes returns PHP {error:Authentication required}

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:54:41 +02:00
Jakub Zych
4ff98f7de8 feat(15-02): register journal export/import commands and Posts toolbar
JSON CLI matching PHP ExportPosts/ImportPosts ships as HasCommands, and Posts toolbar actions reuse that logic behind access_import_export.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:47:53 +02:00
Jakub Zych
ab06569641 fix(15-02): gofmt journal settings validation rules
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:42:39 +02:00
Jakub Zych
afd0a2cafc feat(15-02): add Categories, Tags, and journal settings admin
Register the remaining YAML admin screens and the settings singleton
so a host can boot Posts, Categories, Tags, and Code journal. Posts
update and delete refuse other authors without access_other_posts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:42:29 +02:00
Jakub Zych
dea0934950 feat(15-02): add Posts admin with mlmarkdown and FormatHTML
YAML-driven Posts screen stores translatable markdown and regenerates
content_html in the plugin. Publish writes without access_publish are
refused; list and form queries stay on the principal without
access_other_posts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:41:10 +02:00
Jakub Zych
0bf2d39323 fix(15-01): create backend_users before author_slug in models tests
TestPostTranslatableSmoke ran Plugin.Migrations() on an empty Postgres, so the author_slug ALTER failed. Match TestJournalTables and migrate lagoon backend_users first.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:32:20 +02:00
Jakub Zych
bb903a6850 feat(15-01): add journal en/pl phrasebooks and plugin README
Operators get UI catalogs for plugin, journal, post, category, and tag
keys, plus an application-neutral README for the compiled plugin.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:29:20 +02:00
Jakub Zych
9ae4b9141e feat(15-01): add journal categories, tags, settings, and author slug
Squash the remaining golem15_journal_* tables plus the backend_users
author slug so a host migrate matches the frozen PHP schema.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:28:17 +02:00
Jakub Zych
445022ef71 fix(15-01): keep models tests off the updates leaf
summer build rejects models importing a sibling updates package, and a
go.mod translate replace collides with the host workspace module path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:25:32 +02:00
Jakub Zych
54322128fb feat(15-01): clone journal plugin with translatable Post tracer
- Register golem15.journal requiring exactly golem15.translate
- Squash golem15_journal_posts DDL with unique slug and JSONB columns
- Persist one en/pl Post through translate helpers on real Postgres

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 18:22:47 +02:00