linkrobins/blogreleases/tag/v1.0.2
MaxDob permission based posting function added to the frontend. No more "Admin only" blog posts.
Changelog
1.0.2 — 2026-05-15
This release shifts the blog from "only admins can post" to a real multi-author setup, and replaces the manual newsletter button with publish-time auto-broadcast keyed on category. The admin Posts tab is removed; everything authoring lives at /blog now.
Added
- Permissions:
linkrobins-blog.start and linkrobins-blog.moderate. Exposed in Flarum's standard Permissions page. .start grants authoring rights (create posts, edit and delete your own). .moderate grants edit/delete on any post (and implies .start). Admins always pass both.
- Compose button in the blog sidebar (pen icon). Visible to anyone with
.start. Opens the post-editor modal — same UI on desktop and mobile.
- Drafts page at
/blog/drafts. Sidebar link visible to anyone with .start. Authors see their own drafts; moderators see everyone's. Cards have a "Draft" badge and a dashed outline.
- Manage menu on the article view. Standard Flarum
… dropdown (matching the look of discussion-post controls), with Edit and Delete items gated per permission.
- Auto-broadcast on publish, keyed by category. Each category has a new "Send newsletter when a post is published in this category" toggle. When a post in such a category transitions from draft to published, the newsletter dispatches automatically. Save-as-draft never triggers a send. The
broadcast_sent_at timestamp prevents duplicates across unpublish/republish cycles.
- Confirm-then-unsubscribe flow on the public unsubscribe page. Defeats prefetch scanners (Office 365, anti-phishing tools) from silently unsubscribing users when their mail provider scans the email.
canCreateBlogPost and canModerateBlogPosts boolean flags exposed on the forum payload so the frontend can render the right affordances per actor.
- Delete-success toast. A toast confirms the deletion after using "Delete Post" in the editor or the article's Manage → Delete.
- Refresh broadcast. Saving or deleting a post from any blog view triggers a refresh on the currently-mounted blog page (index, drafts, or article) so new posts show up immediately without a manual reload.
- Skill:
linkrobins/toc companion extension (separate package, optional) for heading-based table-of-contents generation inside blog post bodies.
Changed
- Admin "Posts" tab removed. The admin extension page now has Categories / Subscribers / Settings only. Post authoring and moderation moves to
/blog.
BlogPostResource::scope rewritten with three branches: admin/moderator see all; .start authors see published + own drafts; everyone else sees only published. Honors ?isPublished=true|false to narrow further, with the visibility group correctly wrapped so query params can't escape scoping. ScopeBlogPostVisibility model-policy scope mirrors the same logic.
- Compose button is the primary sidebar control. The subscribe star moved into the normal sidebar flow as a full-width row, so it no longer stacks on top of the Compose FAB on mobile.
- Category modal lays out Color, Icon, and Position in their own rows instead of a three-column flex.
coverImageCredit column widened from VARCHAR(300) to TEXT. Schema ->maxLength(300) removed. The credit field is now a textarea. Render is still plain-text-escaped — the help text no longer claims HTML support.
- Extension icon changed from
fas fa-feather-alt to fas fa-ghost. Brand colors unchanged (#07adcc on #1a2535).
Fixed
- Author impersonation via JSON:API relationship.
BlogPostResource::creating() now force-overrides user_id to the acting user regardless of what the request body says; updating() reverts any attempted change. user_id removed from $fillable as a belt-and-suspenders measure.
- Mass-assignment guard on
broadcast_sent_at, view_count, comment_count, unsubscribe_token (all kept out of $fillable).
- Forum-payload error handling. Policy probes for
canCreateBlogPost and canModerateBlogPosts now have the same try/catch + throttled log wrapper as linkrobinsBlogSubscribed. A broken policy can't 500 the entire forum.
- Unsubscribe scanner-prefetch vulnerability — single-GET unsubscribe links could be silently followed by mail security scanners. Two-step confirm flow added: bare URL shows a "Confirm unsubscribe" page, only
?confirm=1 does the delete.
- Manage-dropdown listener leak. Outside-click handler on the article view is now tracked on the page component and cleaned up on
onremove so navigating away with the menu still open doesn't leave a stale listener attached to document.
- Drafts list visibility for non-
.start users. The empty state message is tailored when the user can't actually create posts (e.g. visiting /blog/drafts directly after losing the permission).
Removed
POST /api/linkrobins-blog/posts/{id}/broadcast endpoint removed. Broadcasts now fire on publish-into-newsletter-enabled-category. No more manual "Send newsletter" button on the post editor.
BroadcastPostController class deleted.
makePostEditorModal factory moved out of js/admin.js (it lives in js/forum.js now). Admin extension page no longer exports window.LinkRobinsBlogPostEditorModal.
Migrations (run php flarum migrate after upgrade)
2026_05_15_000004_widen_cover_image_credit — cover_image_credit VARCHAR(300) → TEXT.
2026_05_15_000005_add_newsletter_enabled_to_blog_categories — boolean column defaulting to false.
Both are additive. No data is dropped or transformed.
Upgrade notes
If you're upgrading from 1.0.0 with no group permissions configured, behavior stays the same — only admins can author posts. To open authoring up to other groups, grant linkrobins-blog.start from Admin → Permissions.
The manual newsletter broadcast button is gone. To send newsletters, enable the "Send newsletter when a post is published in this category" toggle on the appropriate category and publish posts there. If you'd previously relied on the broadcast endpoint from an external script, it'll 404 starting in 1.0.1.
Security audit
Independent audit pass covered 20 findings, of which 4 required code changes (the impersonation fix, the prefetch unsubscribe flow, the forum-payload error handling, and the listener leak). Remaining findings were verified safe (SQL injection, CSRF, email template XSS, recursive event loops, brute-force token guesses) or documented as acceptable risks (category-level publish gates not enforced — granting .start is trust, same as any other permission grant).