<feed xmlns='http://www.w3.org/2005/Atom'>
<title>cccms/test/controllers/nodes_controller_test.rb, branch erdgeist-modernize-auth</title>
<subtitle>[no description]</subtitle>
<id>https://erdgeist.org/gitweb/cccms/atom?h=erdgeist-modernize-auth</id>
<link rel='self' href='https://erdgeist.org/gitweb/cccms/atom?h=erdgeist-modernize-auth'/>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/'/>
<updated>2026-07-16T00:40:03Z</updated>
<entry>
<title>Record the full lifecycle contract in NodeAction entries</title>
<updated>2026-07-16T00:40:03Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T00:40:03Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=c0c9250141c2fa64fed967b8b9ad9bada3694c3d'/>
<id>urn:sha1:c0c9250141c2fa64fed967b8b9ad9bada3694c3d</id>
<content type='text'>
A contract comment above NodeAction.record! now specifies every
verb's metadata shape. NodeAction.head_diff computes the publish
diff between an outgoing head and its replacement -- default-locale
title pair always, author/tags pairs and template/assets/abstract/
body flags only when changed, and a per-locale translation_diff
with added/removed/changed status. It is a pure function of its two
pages, shared by publish, rollback, and the future backfill, and
reads translation rows directly so fallbacks never masquerade as
content.

publish entries carry via ("draft" or "revision"); restore_revision!
is now transactional, takes the acting user, and logs through the
same diff. Staged slug/parent changes applied at publish log a move
entry with the path pair. Node creation logs a create entry with
initial title and path. The draft-scoped translation_destroy writer
is retired -- locale removal is recorded by the publish diff, where
it becomes public fact.
</content>
</entry>
<entry>
<title>Retire wipe_draft! and find_or_create_draft from production code</title>
<updated>2026-07-14T12:31:18Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-14T12:31:18Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=cca0e57b21d506cd341b927984bcb68f0e461783'/>
<id>urn:sha1:cca0e57b21d506cd341b927984bcb68f0e461783</id>
<content type='text'>
Both had already lost their reason to exist as production API:
wipe_draft!'s one remaining callsite (nodes#show) was removed two
sessions ago, and find_or_create_draft had zero production callers
left at all -- confirmed by a fresh grep, not assumed -- every one of
its ~65 call sites was test setup, unrelated to what those tests
actually cover.

wipe_draft! is deleted outright, along with its two tests -- the
lock/draft/autosave cleanup it silently performed already has
explicit, always-visible manual equivalents (Unlock, Discard
Autosave, Destroy Draft), so nothing real is lost.

find_or_create_draft moves to test_helper.rb as a plain method on
ActiveSupport::TestCase, alongside the create_node_with_draft/
create_node_with_published_page helpers already living there --
extending the framework's own designated test-extension point
rather than reopening the Node model from test code. Its three
tests of real dispatch behavior (idempotency on repeat calls, and
raising when a second user contends for the lock) are kept, since
~65 other tests depend on this helper actually working correctly;
only the call syntax changed, from node.find_or_create_draft(user)
to find_or_create_draft(node, user).
</content>
</entry>
<entry>
<title>Rebuild the admin dashboard: icon nav, search, signposts, widgets</title>
<updated>2026-07-12T21:42:43Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-12T21:42:43Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=b271648f89cba7cafafa1b73b1658b1c1bc0e4b0'/>
<id>urn:sha1:b271648f89cba7cafafa1b73b1658b1c1bc0e4b0</id>
<content type='text'>
Replaces the old admin#index wizard -- accreted over years, never
designed as a whole -- with the dashboard settled on this session:
a three-icon nav (dashboard/search/log out, no locale selector), a
nodes-first search bar, four task signposts, and two symmetric
widgets (drafts/autosaves, recent changes) with a quiet housekeeping
row beneath them.

Node.recently_changed now filters and orders by the head page's own
updated_at instead of the node's blanket timestamp, so a lock/unlock
cycle with no actual publish no longer surfaces here, and the
original publisher is no longer misattributed to someone else's
housekeeping action. This also restores the "published" qualifier on
each entry, which the query previously couldn't guarantee was true.

@mynodes and its dedicated "My Work" table are retired along with the
old wizard -- "Continue my work" is a link to the existing, already-
correct NodesController#mine instead of a second, duplicate query.
Its one dedicated test (dedup across multiple revisions by the same
user) is ported to nodes_controller_test.rb, since mine already
carries the same .distinct protection the old query did; it just had
no test of its own until now.
</content>
</entry>
<entry>
<title>Give the sitemap its own view, with collapse and descendant counts</title>
<updated>2026-07-12T00:15:44Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-12T00:15:44Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=45bf65d04d046c0ea4a1150096b2a9b846d6c0b8'/>
<id>urn:sha1:45bf65d04d046c0ea4a1150096b2a9b846d6c0b8</id>
<content type='text'>
Extracted from admin#index's inline table into NodesController#sitemap.
Nested &lt;details&gt;/&lt;summary&gt; per branch, one linear pass over the
existing flat [node, level] list (no added queries) -- each node's own
descendant count computed the same way, via a small stack rather than
re-walking the tree per node. Branches under updates/, club/erfas,
club/chaostreffs, and disclosure start collapsed by default
(CccConventions::SITEMAP_COLLAPSED_PATHS); any branch currently
collapsed, whether by that default or because someone just closed it,
is highlighted via a plain :not([open]) selector -- no state tracked
outside the DOM itself.

Dropped the update?-post exclusion this view used to rely on -- no
longer needed now that updates/ collapses instead of being filtered
out, so its real children (previously silently absent) now show up
correctly. admin#index's own, separate @sitemap query is unchanged;
that view has no collapse mechanism to compensate and wasn't part of
this.
</content>
</entry>
<entry>
<title>Add drafts/recent/mine/chapters admin node views</title>
<updated>2026-07-11T21:43:02Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-11T21:43:02Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=92c394b43a0603743b914c6298aab986805ca990'/>
<id>urn:sha1:92c394b43a0603743b914c6298aab986805ca990</id>
<content type='text'>
Four NodesController actions -- drafts, recent, mine, chapters --
each building its own base scope, sharing one private method
(index_matching) for search narrowing and pagination. Wizard rewrite
to link into these instead of rendering its own tables is a separate,
later step.

Node.editor_search backs the shared "q" narrowing: an ILIKE substring
match against title/abstract on whichever of head or draft is
present, splitting the term on whitespace and requiring every word to
match somewhere independently, not as one phrase, since real words can
end up separated by markup in the underlying HTML. Deliberately
separate from Node.search, the public content search, which stays
tsvector-based and head-only.

chapters generalizes into /admin/nodes/tags/:tags for an arbitrary
tag list (OR'd, not AND'd), sharing the controller action but
rendering its own template rather than branching inside one view.
</content>
</entry>
<entry>
<title>Do not offer to destroy the only draft of a never-published node</title>
<updated>2026-07-10T23:33:07Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-10T23:33:07Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=15aff3eff51809d1ce21caab406a0ef8b13624b6'/>
<id>urn:sha1:15aff3eff51809d1ce21caab406a0ef8b13624b6</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Add the missing assertions two tests were silently running without</title>
<updated>2026-07-10T16:10:57Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-10T16:10:57Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=48eed5f35ea798c91f1e0a77c13e751145acfc48'/>
<id>urn:sha1:48eed5f35ea798c91f1e0a77c13e751145acfc48</id>
<content type='text'>
Both ran real code and checked nothing -- Minitest's "missing
assertions" warning has been firing on every run this session.

test_find_or_create_draft_if_draft_exists_and_is_owned_by_user called
the method twice but never checked what came back; now confirms the
second call returns the same draft rather than creating a new one,
and leaves the lock and page count untouched.

test_destroy_a_published_node destroyed a node and loaded the admin
index but never checked the response, unlike its two neighbors
covering the same destroy path (dangling pages, orphaned
occurrences). Added the assert_response :success its own shape
already implied.

No behavior changed -- both were passing before for the same reason
they're passing now, they just weren't proving anything.
</content>
</entry>
<entry>
<title>Destroying Draft or Discarding Autosave drops you where you left</title>
<updated>2026-07-10T00:13:02Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-10T00:13:02Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=c2b2648d327e1c1749c37fe2e58cd051ed871547'/>
<id>urn:sha1:c2b2648d327e1c1749c37fe2e58cd051ed871547</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix authorship and published_at loss in autosave promotion</title>
<updated>2026-07-08T15:31:15Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-08T15:31:15Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=6ad96c44d04df01e6abde097c681e824dd5fe745'/>
<id>urn:sha1:6ad96c44d04df01e6abde097c681e824dd5fe745</id>
<content type='text'>
Two real bugs surfaced by the full test suite, not by the new tests
written for this feature -- both were latent the moment lock_for_editing!
and save_draft! replaced find_or_create_draft, and only visible once an
existing test exercised the exact path each one lived in.

lock_for_editing! never stamped user/editor onto a draft that already
existed when the lock was acquired. find_or_create_draft used to do this
as part of acquiring the lock; splitting lock acquisition from draft
creation dropped it entirely, since it looked like draft-creation logic
rather than locking logic. Restored as an explicit step: claim authorship
only if none is set yet, editorship unconditionally, matching the old
behavior exactly.

save_draft!'s "no draft yet" branch set user/editor before calling
clone_attributes_from, whose first line is an unconditional self.reload
-- silently discarding both, since neither had been persisted yet.
clone_attributes_from also always copies published_at from its source
without the ||= guard used for template_name, and the source here is
always the autosave, whose published_at is never anything but nil --
meaning every single promotion, not just the first, was quietly
resetting a published page's published_at, which publish_draft!'s own
||= Time.now would then treat as never-published and re-stamp. Fixed by
running clone_attributes_from first on both branches, then applying
user/editor/published_at afterward, exactly as the existing-draft branch
already happened to do by accident.

Four controller tests updated to insert a real put :update between
get :edit and assertions that used to be true immediately after
visiting edit -- deferred draft creation means edit alone no longer
produces one, which is the intended consequence of this whole
redesign, not something these tests were meant to catch.
</content>
</entry>
<entry>
<title>Fix node_content count in show-with-published-draft test</title>
<updated>2026-07-08T14:24:52Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-08T14:24:52Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=a5d7fb9730aa629b3eb8244ee1b3dd863fbfbed5'/>
<id>urn:sha1:a5d7fb9730aa629b3eb8244ee1b3dd863fbfbed5</id>
<content type='text'>
Fallout from the earlier nodes#show heading change, which replaced the
Title row with an &lt;h1&gt; -- unrelated to the autosave work in the
preceding commits.
</content>
</entry>
</feed>
