summaryrefslogtreecommitdiff
path: root/test/models
AgeCommit message (Collapse)Author
2026-08-07Move the pending address from the node onto the drafterdgeist
2026-08-06Re-structure sitemap, all subpages collapsed by default, visually tightenederdgeist
2026-08-06Let editors set a node external homepage, gated and witnessederdgeist
2026-08-05Search assets and events, and order events by when they happenerdgeist
2026-08-04Witness every promotion and demotion made through the roles formerdgeist
2026-08-03Believe the file over the browser about what was uploadederdgeist
2026-08-03Display stale accounts in users#indexerdgeist
2026-08-02Witness calendar entrieserdgeist
2026-08-02Test the neighbour revision pair arithmeticerdgeist
2026-08-02Test that aggregate? keeps the attributes the editor permitserdgeist
2026-08-01Require a second factor for elevation, not for holding adminerdgeist
2026-08-01Allow aggregate to order by slug and paint chapters list more nicelyerdgeist
2026-07-31Warn before the gate refuses, and check restore destinationserdgeist
nodes#new marks the kinds that place under /updates, derived from each kind's own path_prefix. The three parent pickers mark candidates the current user cannot publish into; menu_search returns needs_redaktion per result, computed per user rather than as a bare restricted flag, and the menu-item picker opts out. restore_from_trash! checks its destination: the restore is the move, applied rather than staged, so no later publish would have caught it. The node returns as a draft either way.
2026-07-31Show the gate before it refuses, and check the destinationerdgeist
nodes#show renders publish and trash as disabled_action spans with a hint naming what an editor can still do, matching how locked_by_other already reads. Editing and reverting stay live: drafting is free everywhere.
2026-07-31Bind aggregates over scoped tags to their subtreeerdgeist
CccConventions::TAG_SCOPES maps "update" and "pressemitteilung" to /updates and "disclosure" to /disclosure. Page.aggregate applies the mapping, so an aggregate over one of those tags is bounded by its subtree regardless of what the shortcode says. Tags stay unrestricted; positions are publish-gated. Both RSS actions call Page.aggregate rather than repeating its tag join. Empty feeds no longer crash: Atom falls back to the current time for the required <updated>, and the optional dc:date is omitted.
2026-07-31Gate live-content changes on restricted surfaceserdgeist
publish_draft!, trash!, destroy_from_trash!, attach_asset! and Asset#destroy_witnessed! now refuse unless the acting user holds redaktion, and only when the subject is on a restricted surface: the front page, the updates tree that feeds ~100k subscribers, or disclosure. Drafting, autosaving, tagging and creating stay free everywhere for everyone. Enforcement is in the models rather than the controllers, since attach_asset! and the rest are reachable from rake tasks and internal paths. It follows the errors.add-plus-bare-raise pattern the rest of Node already uses, so every existing RecordInvalid rescue reports it with a localised message; only assets_controller#destroy needed a rescue added. A nil user is treated as a system context and bypasses the gate. The default nil on three of those verbs is what makes that reachable, and removing those defaults once every call site passes a user is the next tightening.
2026-07-31Retire the unused per-node permission subsystemerdgeist
Every path through Permission raised or lied: validates_presence_of on a boolean made granted = false unsaveable, since false.blank? is true; get_permission_for read a nonexistent identifier attribute; has_permission? called an undefined plural method and returned a truthy relation in every case; and set_permission mutated granted without saving. Nothing outside the model referenced it and the table was empty.
2026-07-30Localise model validation messages and refusal reasonserdgeist
2026-07-27Surface held locks in the dashboard's work-in-progress widgeterdgeist
A lock with no draft or autosave behind it was invisible to everyone including its holder, until the next editor collided with it. work_in_progress now admits those nodes, and the widget names the holder rather than the last editor on any locked row. Also flips the ordering to stalest-first, so a backlog reads as a queue rather than a feed, and gives the heading a real total: the count came from the already-limited relation and could never exceed five.
2026-07-24Add TOTP enrollment and verification to User, witnessed in the action logerdgeist
2026-07-23Record asset deltas at publish, with changed assets as participantserdgeist
2026-07-23Witness asset uploads and out-of-band attaches in the action logerdgeist
2026-07-23Witness asset destruction, naming every node it stripserdgeist
2026-07-23Add action_participants, recording every node a trash/destroy toucheserdgeist
2026-07-22Add Node#attach_asset! attaching across all lifecycle rowserdgeist
2026-07-22Retire nodes#recent, superseded by the action logerdgeist
2026-07-22Fix Node#title ignoring autosaveerdgeist
head ? head.title : draft.title never accounted for a node with only an autosave, reuses editable_page
2026-07-21Render PDF headlines as document cards, not lightbox imageserdgeist
A starred PDF previously ran through the same crop-and-lightbox path a photo does -- exactly the awkward treatment explicit headline designation was meant to avoid. _headline_image.html.erb now branches on @headline_asset.pdf?: a PDF renders as a linked card (a :medium thumbnail, a file icon, its name), no gallery participation at all. The existing image-headline and gallery-fallback logic is otherwise unchanged, now scoped to an image-specific headline only. Other attached PDFs -- headlined or not -- list below as plain links, same reasoning as why non-headline photos still get a gallery trigger: an attached document shouldn't go invisible just because nothing's been starred yet. headline_image's own render guard needed widening to cover a page with PDFs attached but no images and no headline at all -- the one case none of the existing conditions accounted for.
2026-07-21PDFs currently should have no credits attached to them in displayerdgeist
2026-07-21More PDF headline eligibilityerdgeist
2026-07-21Make PDFs eligible for headline and allow searching assets by filenameerdgeist
2026-07-21Remove Page#update_assetserdgeist
Only caller left was the sort_images action removed last commit. Kept alive only as a test-setup convenience for diff_against coverage, which is what it actually was -- an implicit API with no deliberate contract, sitting there for anyone to call. Rewrote the one test to set up its fixture state directly via related_assets rather than through a method whose real job was already done.
2026-07-20Make headline images explicit, add asset creditserdgeist
- related_assets gains a `headline` boolean (DB-enforced: at most one per page), replacing "first image by position" as the headline rule. A rake task backfills the current first image on every live head/draft, so nothing changes visually until an editor changes it. - The image picker sidebar gets a star toggle reflecting the flag; the TinyMCE inline-image picker's badge now reads it too, instead of assuming position 0. - No headline chosen (or none attached) now falls back to the gallery-count caption itself becoming the lightbox trigger, instead of the gallery being unreachable. - Assets gain creator, source_url, and license_key (against a new config/asset_licenses.yml dictionary). asset_credit renders a degrading attribution line, reused as a hidden per-image glightbox caption so credit is one click away for every image, not only the headline's always-visible one. - Fixed: asset thumbnails rendered unconditionally regardless of whether a real variant exists on disk. Asset#has_variant? checks file existence, not content type -- some legacy PDFs have real pre-rewrite thumbnails a content-type check would have hidden. - assets#new/edit rebuilt onto the same node_description/node_content layout as assets#show, picking up the three new fields in the process.
2026-07-18Accept blank template names in the allowlist validationserdgeist
2026-07-18Give action log entries per-verb iconserdgeist
A muted glyph before each sentence makes both log surfaces scannable by verb: create, publish, move, trash, restore, destroy, and the discard pair. Rollback publishes get their own icon (history) distinct from ordinary promotion. Unknown verbs fall back to a dashed circle.
2026-07-18Annotate the History list with each revision's lifecycleerdgeist
Each row in nodes#show's History section now carries terse badges from the action log: created, published, and restored (rollback re-promotion), with date and actor, rendered from entry metadata alone. Backfilled entries wear the inferred marker, so reconstructed provenance stays distinguishable from witnessed history. A revision that was published and later restored shows both badges chronologically -- its true biography. Only create and publish entries carry page_id; trash, restore, and destroy annotate the node's own log zoom instead of any single revision, by design.
2026-07-18Give Trash a proper title on lazy constructionerdgeist
2026-07-18Keep the Trash out of the drafts surfaceserdgeist
2026-07-18Teach the action log reader the Trash vocabularyerdgeist
Sentences for trash (with the pre-trash path), restore_from_trash (with the destination), and destroy (with the final path, read from its flat create-symmetric key).
2026-07-18Add Trash affordances: cockpit, listing, dashboard entryerdgeist
nodes#show gains a Trash section on trashed nodes: provenance from the trash entry, a restore form whose parent picker pre-fills the old parent while it still lives, and permanent deletion. A Move-to-Trash button joins the status actions on living nodes. nodes#trashed lists trashed subtree roots with weight, provenance, and deletion; the dashboard housekeeping row links to it, and trash/destroy redirect there. Deletion from Trash now removes the whole subtree, deepest first, each node through a real destroy! so every per-node cascade runs -- amending the never-recursive rule for this one sanctioned path (both confirms state the count; the root entry carries destroyed_descendants). Bare Node#destroy still refuses children.
2026-07-17Add trash!, restore_from_trash!, and destroy_from_trash! with log entrieserdgeist
Also update the node action contract to include the trash related verbs.
2026-07-17Bootstrap the Trash node: reserved slug, identity, guardserdgeist
2026-07-17Refuse destroying nodes that still have childrenerdgeist
NestedTree's before_destroy silently delete_all'd the whole subtree, bypassing every per-node cleanup. Nodes are never destroyed recursively; descendants must be removed individually.
2026-07-17Allowlist aggregate order columns and template nameserdgeist
Page.aggregate interpolated order_by into SQL unchecked while already allowlisting order_direction; the column is now normalized and checked against the sortable columns, falling back to pages.id. Its values arrive from editor-authored aggregate shortcodes, so this was editor-gated, but the asymmetry was wrong regardless. template_name and default_template_name now validate inclusion in Page.custom_templates -- names render as filesystem paths, so only names actually present in the template directory are acceptable. Validated only on change: legacy rows whose template file has since vanished stay saveable, and valid_template's render-time fallback to standard_template continues to cover them. Two tests that wrote fabricated template names through the front door now arrange their state correctly (update_column for the stale-name fallback test, a real template for the update-persists test).
2026-07-17Allow updating migrated users without supplying a passworderdgeist
password_required? treated a blank crypted_password as "needs a password", but after bcrypt migration crypted_password is nil by design -- every subsequent save of a migrated or new user failed validation. The predicate now requires a password only when both the legacy and the bcrypt credential are absent, or when one is actually being set.
2026-07-17Implement transparent password hash migrationerdgeist
Add has_secure_password and bcrypt while retaining compatibility with legacy SHA-1 password hashes. Existing users are upgraded to password_digest on their next successful login. Add regression tests covering both legacy and modern authentication paths.
2026-07-17Add some more tests for the login basics while refactoringerdgeist
2026-07-17Improve test coverage for two-ordinal week selection in rrule humaniziererdgeist
2026-07-16Aggregate selected weeks in a more human friendly formerdgeist
Weekdays appearing on a subset of the weeks of the month are now aggregated into a simpler form.
2026-07-16managed RRULE constructs now include week selectionerdgeist
Improve the humanizer to also understand weekly patters that an editor can manually select, on top of the single week rules. Extend template and javascript controller to reflect these changes.