<feed xmlns='http://www.w3.org/2005/Atom'>
<title>cccms/app/models, 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-16T17:45:42Z</updated>
<entry>
<title>Implement transparent password hash migration</title>
<updated>2026-07-16T17:45:42Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T17:45:42Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=220ed6c7914f5977d36b7617e9c38999317f57e5'/>
<id>urn:sha1:220ed6c7914f5977d36b7617e9c38999317f57e5</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>Aggregate selected weeks in a more human friendly form</title>
<updated>2026-07-16T14:49:25Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T14:49:25Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=aa752d4839375f313f0d3e0070e85fbbac13ced9'/>
<id>urn:sha1:aa752d4839375f313f0d3e0070e85fbbac13ced9</id>
<content type='text'>
Weekdays appearing on a subset of the weeks of the month are now
aggregated into a simpler form.
</content>
</entry>
<entry>
<title>managed RRULE constructs now include week selection</title>
<updated>2026-07-16T14:43:11Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T14:43:11Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=35dc05de97677d57123617a7c4e78aad1611b28d'/>
<id>urn:sha1:35dc05de97677d57123617a7c4e78aad1611b28d</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>Split current_unique_name in a setter and an accessor</title>
<updated>2026-07-16T13:12:07Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T13:12:07Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=b701669d0d9a5d7be01f99b8e725c05c6c5d52ce'/>
<id>urn:sha1:b701669d0d9a5d7be01f99b8e725c05c6c5d52ce</id>
<content type='text'>
Also clean up some instance variable assignments on the way.
</content>
</entry>
<entry>
<title>Condense the action log into a scannable table</title>
<updated>2026-07-16T11:50:15Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-16T11:50:15Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=603ccfbd5fe96f0b83aaf3d5118aded2a39992fb'/>
<id>urn:sha1:603ccfbd5fe96f0b83aaf3d5118aded2a39992fb</id>
<content type='text'>
Several minor improvements to the action log presentation:
* Now a table with date and human readable presentation as
  rows is displayed
* If no changes in a title were detected, the old version
  is omitted
* The "inferred" flag is demoted to the end of the line
* You can zoom in on the node's history directly from a
  log line
* byline for the first publish action is preserved
* Revisions are directly linked to when a new one i
  published
</content>
</entry>
<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>Add NodeAction: an append-only log of who did what to a node</title>
<updated>2026-07-15T02:23:09Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-14T23:41:34Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=d56155231814633e04f856d22646fea24ef97011'/>
<id>urn:sha1:d56155231814633e04f856d22646fea24ef97011</id>
<content type='text'>
node_id/page_id/user_id are lookup and ordering only -- all three
nullify on delete, so an entry outlives its actor and its subject.
Everything that must survive those deletions lives in a mandatory
metadata jsonb written once at creation: the actor's username, the
node's human-readable name (pinned to the default locale), and
action-specific extras such as publish's title from/to.

NodeAction.record! is the single constructor, so every entry gets
the same baseline metadata without each call site re-implementing
it. occurred_at is one field for live and backfilled entries alike;
inferred_from distinguishes them -- nil means witnessed at the
moment it happened, populated names how a backfilled entry was
estimated.

Instrumented so far: publish (crediting the actual publisher,
threaded through from the controller -- previously nobody had the
act of publishing recorded anywhere), revert's discard_autosave and
destroy_draft branches, and translation destroy. publish_draft! now
runs in a transaction so the promotion and its log entry land
together. The remaining verbs follow once this mechanism has proven
itself.
</content>
</entry>
<entry>
<title>Crop headline images to aspect ratio instead of distorting them</title>
<updated>2026-07-14T13:25:11Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-14T13:25:11Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=c7ed30918154d801c44f77645ead38d4759d2778'/>
<id>urn:sha1:c7ed30918154d801c44f77645ead38d4759d2778</id>
<content type='text'>
STYLES restructured from a single geometry: string per style to a
full args: array, since this fix needs -gravity and -extent
alongside -resize, which one geometry string can't express.
</content>
</entry>
<entry>
<title>Add a :large FileAttachment style for full-width inline body images</title>
<updated>2026-07-14T13:10:33Z</updated>
<author>
<name>erdgeist</name>
<email>erdgeist@erdgeist.org</email>
</author>
<published>2026-07-14T13:10:33Z</published>
<link rel='alternate' type='text/html' href='https://erdgeist.org/gitweb/cccms/commit/?id=810cddcb122462d62b31b03295e001ea5f0252ba'/>
<id>urn:sha1:810cddcb122462d62b31b03295e001ea5f0252ba</id>
<content type='text'>
Sized generously (1600x1600&gt;) rather than against today's cramped
490px content column specifically -- shrinking an oversized source
to fit a narrow container is free and looks fine; a source too
small for a future, wider redesign has no fix short of re-uploading
every image. Purely additive: nothing reads :large yet, and
generate_variants already loops over the whole STYLES hash
generically, so no other code needed to change for new uploads to
start getting it. Test suite's own hardcoded style lists updated in
the same commit so they don't quietly drift out of sync with what
the app actually defines.
</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>
</feed>
