summaryrefslogtreecommitdiff
path: root/test/models
AgeCommit message (Collapse)Author
2026-08-08Move the external homepage onto the drafterdgeist
2026-08-08Pin the disclosure partial against a silent fallbackerdgeist
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