bible270 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +196 -237
- data/README.md +159 -79
- data/Rakefile +5 -4
- data/app/controllers/bible270/admin_controller.rb +147 -0
- data/app/controllers/bible270/application_controller.rb +24 -3
- data/app/controllers/bible270/checkoffs_controller.rb +2 -3
- data/app/controllers/bible270/comments_controller.rb +6 -2
- data/app/controllers/bible270/days_controller.rb +5 -6
- data/app/controllers/bible270/profiles_controller.rb +45 -0
- data/app/controllers/bible270/readers_controller.rb +5 -4
- data/app/controllers/bible270/sessions_controller.rb +89 -26
- data/app/helpers/bible270/plan_helper.rb +22 -12
- data/app/mailers/bible270/application_mailer.rb +4 -1
- data/app/mailers/bible270/sign_in_mailer.rb +1 -0
- data/app/models/bible270/application_record.rb +1 -0
- data/app/models/bible270/checkoff.rb +4 -3
- data/app/models/bible270/comment.rb +26 -5
- data/app/models/bible270/reader.rb +167 -17
- data/app/models/bible270/setting.rb +57 -0
- data/app/models/bible270/sign_in_token.rb +5 -2
- data/app/views/bible270/admin/comments.html.erb +44 -0
- data/app/views/bible270/admin/index.html.erb +48 -0
- data/app/views/bible270/admin/show.html.erb +104 -0
- data/app/views/bible270/days/_start_date.html.erb +1 -1
- data/app/views/bible270/days/index.html.erb +9 -21
- data/app/views/bible270/profiles/edit.html.erb +44 -0
- data/app/views/bible270/readers/index.html.erb +2 -2
- data/app/views/bible270/readers/show.html.erb +5 -5
- data/app/views/bible270/sessions/new.html.erb +17 -3
- data/app/views/bible270/shared/_day_index.html.erb +12 -0
- data/app/views/bible270/shared/_header.html.erb +2 -0
- data/app/views/bible270/shared/_styles.html.erb +17 -7
- data/app/views/layouts/bible270/application.html.erb +2 -4
- data/config/routes.rb +38 -18
- data/db/migrate/20260101000001_create_bible270_readers.rb +3 -2
- data/db/migrate/20260101000002_create_bible270_checkoffs.rb +3 -2
- data/db/migrate/20260101000003_create_bible270_comments.rb +4 -3
- data/db/migrate/20260101000004_create_bible270_sign_in_tokens.rb +4 -3
- data/db/migrate/20260101000005_add_names_to_bible270_readers.rb +12 -0
- data/db/migrate/20260101000006_add_approval_to_bible270_comments.rb +11 -0
- data/db/migrate/20260101000007_create_bible270_settings.rb +15 -0
- data/lib/bible270/avatars.rb +46 -0
- data/lib/bible270/configuration.rb +96 -24
- data/lib/bible270/email_sign_in.rb +7 -7
- data/lib/bible270/engine.rb +1 -0
- data/lib/bible270/names.rb +47 -0
- data/lib/bible270/plan.rb +356 -102
- data/lib/bible270/versification.rb +84 -67
- data/lib/bible270/version.rb +2 -1
- data/lib/bible270.rb +8 -5
- data/lib/generators/bible270/install/install_generator.rb +521 -38
- data/lib/generators/bible270/install/templates/bible270.rb.tt +2 -2
- metadata +15 -44
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84d3ca14b2813767c7f837ec1844feaaff31b1ac12e37d691c95b8975313a9e9
|
|
4
|
+
data.tar.gz: 69374a41cfaed437a5bb0367ac66b7500949cda2654e9f80e5ab46f9f8822547
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71c2ef21eb61bb68359ed3cd202ecc0278082cc97a18e4f9886093799d065409fd0529775edeb1a42f33d25a6ceaac702f44d7c53b59fda82e2c91d894cb704f
|
|
7
|
+
data.tar.gz: 1cbd38d2f361892bb1cab9f981986598d3d03bc2c04ce63506d60907aca58b57ffd96f2dc9f607ead5dc1c6966086954898e60b7826955b9960c769aa8b8c26e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,281 +1,240 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to bible270. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
4
|
-
this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html), treating pre-1.0 minor
|
|
5
|
-
bumps as the place breaking changes may land.
|
|
4
|
+
this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html), treating pre-1.0 minor bumps as the place breaking changes may land.
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## Unreleased Changes
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
- **The New Testament now has a reading every day — no days off.** 260 chapters over 270 days is
|
|
11
|
-
reconciled by dividing the 10 longest chapters in two: Luke 1, Matthew 26 and 27, Mark 14,
|
|
12
|
-
Luke 9, 12 and 22, John 6 and 8, and Acts 7. Luke 1 reads as 1–40 then 41–80. This drops the
|
|
13
|
-
longest NT reading from 80 verses to 58 (stdev 14.6 → 11.4) and removes the 10 rest days from
|
|
14
|
-
0.8.0, so all three tracks are present on all 270 days and every day needs three check-offs.
|
|
15
|
-
- The daily total is now 76–175 verses (was 76–203), averaging ~119.
|
|
8
|
+
See the changes since the last release:
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
- Shared division machinery used by both the NT and the Psalms: `Plan.divide_to_fill`,
|
|
19
|
-
`expand_readings`, `segment_length`, `format_segment`, `divided`.
|
|
20
|
-
- `Plan.nt_parts`, `nt_readings`, `nt_chapters`, `divided_nt_chapters`, `psalm_chapters`.
|
|
21
|
-
- `totals` reports `nt_readings` (270) and `nt_divided` (10).
|
|
22
|
-
|
|
23
|
-
### Removed
|
|
24
|
-
- `Plan.nt_groups`, `format_pp_segment`, `pp_segment_length` (superseded by the shared
|
|
25
|
-
`format_segment` and `segment_length`), and `totals[:nt_rest_days]`.
|
|
26
|
-
- `nt_rest_days` remains but now always returns an empty array.
|
|
27
|
-
|
|
28
|
-
## [0.8.0] — 2026-07-25
|
|
29
|
-
|
|
30
|
-
### Changed — BREAKING (the reading plan itself)
|
|
31
|
-
- **New Testament is read once**, not twice: one chapter a day with 10 evenly spaced days off
|
|
32
|
-
(every 27th). Matthew 1 on day 1, Revelation 22 on day 270. Chapters stay whole, so the NT load
|
|
33
|
-
swings with chapter length (8–80 verses: Revelation 15 to Luke 1). Verse-balancing the NT would
|
|
34
|
-
have needed 48 rest days,
|
|
35
|
-
since 260 whole chapters can't spread evenly over 270 days — one-a-day is the better trade.
|
|
36
|
-
- **Psalms once and Proverbs twice**, interleaved in the third track. Proverbs contributes
|
|
37
|
-
31 × 2 = 62 whole-chapter readings, spaced evenly, which leaves 208 days for the Psalms.
|
|
38
|
-
- **Psalm 119 is divided into 11 sections of exactly 16 verses** (176 = 11 × 16 — two of its
|
|
39
|
-
eight-verse acrostic stanzas per reading), replacing the previous two-part split.
|
|
40
|
-
- **Longer psalms are divided to fill the remaining days.** After Psalm 119's 11 sections, 48 further
|
|
41
|
-
divisions are spent on whichever psalm currently carries the heaviest reading, so the longest go
|
|
42
|
-
first: 41 psalms end up divided and no single psalm reading exceeds 20 verses.
|
|
43
|
-
- Short psalms are no longer merged with a neighbour — the track now needs more readings, not fewer,
|
|
44
|
-
so every psalm stands on its own day or is divided. Psalm 117 is a light day (2 verses) on that
|
|
45
|
-
track, though the day still carries its OT and NT readings.
|
|
46
|
-
- Proverbs 31 lands on day 135 and again on day 270; Psalm 150 on day 269.
|
|
47
|
-
- A typical day is now ~119 verses (range 76–203), down from ~157.
|
|
10
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.11.0...main)**
|
|
48
11
|
|
|
12
|
+
## [0.11.0] — 2026-07-28
|
|
13
|
+
|
|
49
14
|
### Added
|
|
50
|
-
- `Plan.psalm_parts`, `psalm_readings`, `proverbs_readings`, `pp_readings`, `proverbs_days`,
|
|
51
|
-
`divided_psalms`, `nt_rest_days`, `pp_segment_length`, `format_pp_segment`.
|
|
52
|
-
- `totals` now reports `psalms`, `psalm_readings`, `proverbs`, `proverbs_passes`,
|
|
53
|
-
`proverbs_readings`, and `nt_rest_days`.
|
|
54
|
-
|
|
55
|
-
### Removed
|
|
56
|
-
- `PP_LONG_CHAPTER`, `PP_SPLIT_PARTS`, `PP_MIN_DAY`, `PP_DAY_TARGET` (no more merging or
|
|
57
|
-
threshold-based splitting), `pp_base_portions`, `pp_cycle_length`, `format_pp`,
|
|
58
|
-
`nt_days_per_pass`, `nt_second_pass_start_day`, `nt_chapters`, and `totals[:nt_chapters_read]`.
|
|
59
|
-
- New tuning constants are `PROVERBS_PASSES` and `PSALM_119_SECTION_SIZE`.
|
|
60
|
-
|
|
61
|
-
### Notes
|
|
62
|
-
- A day counts as complete when every track with content is ticked: three normally, two on the 10 NT
|
|
63
|
-
rest days. Check-offs are keyed to day and track, so existing rows stay valid — but the readings
|
|
64
|
-
those rows point at have changed, so anyone mid-plan is now tracking a different schedule.
|
|
65
|
-
|
|
66
|
-
## [0.7.0] — 2026-07-25
|
|
67
15
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
16
|
+
- **Readers can edit their own name and picture** at `<mount>/profile`, linked from the nav. An admin
|
|
17
|
+
can edit anyone's from that reader's admin page. Both go through one rule (`Bible270::Names`):
|
|
18
|
+
first and last required, whitespace squished, display name derived — so internal capitals and
|
|
19
|
+
particles survive (`vonderLuft`, `von der Luft`). A reader who arrived via OmniAuth with only a
|
|
20
|
+
display name gets the form pre-filled by splitting it.
|
|
21
|
+
- **Avatar uploads** — PNG, JPEG, GIF or WebP up to `config.avatar_max_bytes` (2MB), with a Remove
|
|
22
|
+
button. SVG is refused, since it can carry script. Needs Active Storage in the host app; without it
|
|
23
|
+
the field is hidden, the engine still loads, and avatars come from the sign-in provider as before.
|
|
24
|
+
No resizing: the original is served at CSS dimensions.
|
|
25
|
+
- **A run can be closed to new readers** from the admin panel. Existing readers carry on signing in;
|
|
26
|
+
nobody new can join. Enforced at all three points a reader can be created — the OmniAuth callback,
|
|
27
|
+
issuing an email link, and consuming one. Runtime state in a new `bible270_settings` table, so it
|
|
28
|
+
needs no deploy; `config.enrollment_open = false` launches closed.
|
|
29
|
+
- The **All 270 days** index now appears on every page, rendered from the layout rather than only on
|
|
30
|
+
the overview.
|
|
76
31
|
|
|
77
32
|
### Changed
|
|
78
|
-
- The install generator defaults to `/daily-bread`, writes `config.mount_at` into the engine
|
|
79
|
-
initializer, and emits a config-driven `mount` line and `path_prefix` rather than literal paths.
|
|
80
|
-
`--mount-at` is still accepted to set the initial value.
|
|
81
|
-
- README documents the mount point in one section, including the initializer load-order caveat
|
|
82
|
-
(`bible270.rb` must be read before `omniauth.rb`; alphabetical ordering makes the default naming
|
|
83
|
-
work) and the two things that still need editing by hand when the path changes: OAuth callback URLs
|
|
84
|
-
and any CMS links.
|
|
85
33
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
34
|
+
- **A returning reader needs only their email to sign in.** Names are optional on the sign-in form; a
|
|
35
|
+
new reader is asked for theirs on their profile straight after clicking the link. Requiring them
|
|
36
|
+
only for unknown addresses would have made the response differ between a known and an unknown one,
|
|
37
|
+
which is an account-enumeration oracle — and the closed-run banner exists for the same reason.
|
|
38
|
+
- Closing a run says so on the sign-in page before anyone types, since the "check your inbox"
|
|
39
|
+
response deliberately cannot distinguish a known address from an unknown one.
|
|
89
40
|
|
|
90
|
-
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- Setting a reader's start date from the admin panel failed with "That doesn't look like a date"
|
|
44
|
+
whenever `config.allow_reader_start_date` was off. That setting governs what a *reader* may change
|
|
45
|
+
about their own plan and was wrongly gating the admin action, which now uses an ungated setter.
|
|
46
|
+
- The day grid ran a query per day (`read_tracks_for`), so its 270 cells cost up to 270 queries. It
|
|
47
|
+
now reads the reader's single grouped count — which matters more now the grid is on every page.
|
|
48
|
+
- The nav's "Sign out" sat below the other items: `button_to` renders a form, and the shared
|
|
49
|
+
`.b270-linkbtn` class carries a top margin, smaller font and underline meant for use under a form.
|
|
50
|
+
- `Bible270::Configuration` referenced `Avatars` without requiring it, so instantiating it raised
|
|
51
|
+
`NameError` unless something else had already loaded avatars — which the app did by luck of require
|
|
52
|
+
order and the test suite did not.
|
|
53
|
+
|
|
54
|
+
### Internal
|
|
55
|
+
|
|
56
|
+
- Tests now guard the classes of bug that bit during this run: every file under `lib/` must load on
|
|
57
|
+
its own *and* survive instantiating the configuration; every setting the code calls must exist on
|
|
58
|
+
`Configuration`; templates must not reference engine constants unqualified; a coloured link class
|
|
59
|
+
must outrank `.b270 a`; admin actions must not use reader-gated methods; and closure must be
|
|
60
|
+
enforced at all three creation points.
|
|
61
|
+
- Migrations: `20260101000007` (settings). Active Storage tables are the host app's
|
|
62
|
+
(`bin/rails active_storage:install`).
|
|
63
|
+
|
|
64
|
+
## [0.10.0] — 2026-07-26
|
|
65
|
+
|
|
66
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.9.0...v0.10.0)**
|
|
67
|
+
|
|
68
|
+
### Reading plan
|
|
69
|
+
|
|
70
|
+
- **Proverbs is read once**, not twice, and its longer chapters are divided — at the discourse
|
|
71
|
+
boundaries in chapters 1–9 and 30–31, evenly elsewhere, since 10–29 are collections of
|
|
72
|
+
independent sayings.
|
|
73
|
+
- **A psalm of 25 verses or fewer is never divided** (`PSALM_WHOLE_MAX_VERSES`), which keeps 131 of
|
|
74
|
+
the 150 psalms whole. Psalms over 25 verses break at their turns of thought.
|
|
75
|
+
- **A divided chapter is always read on consecutive days.** Nothing is inserted between the parts of
|
|
76
|
+
a split psalm.
|
|
77
|
+
- Psalms and Proverbs are now divided against a single budget, so the two books balance by verse
|
|
78
|
+
load rather than each being squeezed into a fixed number of days.
|
|
79
|
+
- The New Testament is read once with a reading every day: 260 chapters over 270 days, so the
|
|
80
|
+
longest are divided (at content boundaries via `CHAPTER_BREAKS`, e.g. Luke 1 at the annunciations,
|
|
81
|
+
Magnificat and Benedictus).
|
|
82
|
+
- `CHAPTER_BREAKS` lets any chapter's break points be set by hand, or `[]` to force it whole. Break
|
|
83
|
+
points are validated; a bad entry raises rather than silently overlapping.
|
|
84
|
+
- Break points can also come from the host app and be changed **without restarting**:
|
|
85
|
+
`config.chapter_breaks`, or a YAML file at `config.chapter_breaks_path` re-read whenever it
|
|
86
|
+
changes. Precedence: constant < config < file.
|
|
87
|
+
|
|
88
|
+
### Features
|
|
89
|
+
|
|
90
|
+
- **Interactive installer** — `bin/rails generate bible270:install` asks where to mount, which
|
|
91
|
+
sign-in methods to enable, writes the initializers, adds the `mount` line, copies the migrations
|
|
92
|
+
and runs them. Scriptable with `--defaults` and friends.
|
|
93
|
+
- **`config.mount_at`** — the mount path in one place; routes and OmniAuth both read it.
|
|
94
|
+
- **Passwordless email sign-in** with single-use magic links; only a SHA-256 digest is stored, and
|
|
95
|
+
the response never reveals whether an address exists. First and last name are required.
|
|
96
|
+
- **Configurable start dates** — community-wide or per reader, with a Today badge and a pace
|
|
97
|
+
indicator. Check-offs are keyed to day numbers, so changing a date never moves history.
|
|
98
|
+
- **Admin panel** (`/admin`, gated by `config.admin_emails` or `config.admin_resolver`; unauthorised
|
|
99
|
+
requests 404 rather than 403). Remove readers, set their progress exactly (mark complete through a
|
|
100
|
+
day, or toggle individual days), and move them to a given day of the plan — which re-maps the
|
|
101
|
+
calendar only, since check-offs are keyed to day numbers.
|
|
102
|
+
- **Comment moderation.** Reflections are **visible as soon as they are written** — moderation is for
|
|
103
|
+
taking something down afterwards, not gatekeeping every post. An admin can hide a reflection
|
|
104
|
+
(removing it from the day and community pages while keeping the writer's words, reversibly) or
|
|
105
|
+
delete it outright, from a list filterable by visible/hidden or from the writer's own page.
|
|
91
106
|
|
|
92
107
|
### Fixed
|
|
93
|
-
- **`db:migrate` failed with `ActiveRecord::DuplicateMigrationNameError`.** The engine appended its
|
|
94
|
-
own `db/migrate` to the host application's migration paths *and* exposed
|
|
95
|
-
`bible270:install:migrations`. Using the task — the documented install step — meant every
|
|
96
|
-
migration class was defined twice, once in the host's `db/migrate` and once in the gem. The engine
|
|
97
|
-
no longer touches the host's migration paths; copying via the task is the single supported path,
|
|
98
|
-
which also means the host owns the migrations and they appear in `schema.rb` normally.
|
|
99
108
|
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
- Sign-in was broken: OmniAuth 2.0+ rejects GET on its request phase, so the controls are now POST
|
|
110
|
+
forms with CSRF tokens. Open-redirect hardening on the return-to path, and `reset_session` on
|
|
111
|
+
sign-in and sign-out.
|
|
112
|
+
- `db:migrate` failed with `DuplicateMigrationNameError` — the engine both appended its migrations
|
|
113
|
+
to the host's paths and shipped `install:migrations`.
|
|
114
|
+
- Views raised `uninitialized constant Plan`: a template's lexical scope is `Object`, so engine
|
|
115
|
+
constants must be fully qualified.
|
|
116
|
+
- Views raised `undefined method 'b270_*'`: Rails only auto-includes an engine's helpers when the
|
|
117
|
+
controller's superclass is exactly `ActionController::Base`, which it isn't once
|
|
118
|
+
`config.parent_controller` points at the host.
|
|
119
|
+
- Buttons rendered dark-on-dark: `.b270 a{color:inherit}` outranked `.b270-btn`.
|
|
120
|
+
- The generated OmniAuth initializer called `path_prefix`, which `OmniAuth::Builder` does not
|
|
121
|
+
define, and read credentials at boot so a bad master key stopped the app starting.
|
|
122
|
+
- The sign-in email was rendered inside the host's mailer layout, nesting one HTML document in
|
|
123
|
+
another.
|
|
124
|
+
- Ruby 4.0 compatibility: dropped `cgi`, removed from default gems in 4.0.
|
|
125
|
+
- Posting a reflection about the whole day failed with "Track is not included in the list": the
|
|
126
|
+
form's blank option submits an empty string, which `allow_nil` rejects. Blank tracks are now
|
|
127
|
+
normalised to NULL before validation.
|
|
128
|
+
|
|
129
|
+
- `config.email_sign_in_log_link` — tri-state: nil logs the sign-in link in development and test
|
|
130
|
+
only, true forces it on (for smoke-testing a production build locally before mail is wired up),
|
|
131
|
+
false disables it. The log also distinguishes sent, rate-limited and failed delivery, which the
|
|
132
|
+
response deliberately cannot.
|
|
133
|
+
- A test asserts every setting the code calls is actually defined on `Configuration`, so a missing
|
|
134
|
+
accessor fails the suite instead of raising `NoMethodError` on whichever request touches it.
|
|
102
135
|
|
|
103
|
-
|
|
136
|
+
### Notes
|
|
104
137
|
|
|
105
|
-
|
|
106
|
-
- Gem metadata now points at the actual repository rather than reusing the homepage:
|
|
107
|
-
`source_code_uri`, `bug_tracker_uri`, and `changelog_uri` all resolve to
|
|
108
|
-
<https://github.com/avonderluft/bible270>.
|
|
109
|
-
- `rubygems_mfa_required` is set, so pushes to rubygems.org require MFA.
|
|
138
|
+
- Table names changed from `bible_reading_plan_*` in the 0.9.0 line; this is a fresh install.
|
|
110
139
|
|
|
111
|
-
|
|
112
|
-
- This changelog, packaged with the gem.
|
|
140
|
+
## [0.9.0] — 2026-07-25
|
|
113
141
|
|
|
114
|
-
|
|
142
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v0.6.2...v0.9.0)**
|
|
115
143
|
|
|
116
144
|
### Changed
|
|
117
|
-
- Author and copyright now read "Andrew vonderLuft".
|
|
118
|
-
- The display-name-from-email example in the docs and tests uses a neutral address, since the
|
|
119
|
-
algorithm can't recover internal capitals and shouldn't be shown rendering a real name wrongly.
|
|
120
145
|
|
|
121
|
-
|
|
146
|
+
* **The New Testament now has a reading every day — no days off.** 260 chapters over 270 days is reconciled by dividing the 10 longest chapters in two: Luke 1, Matthew 26 and 27, Mark 14, Luke 9, 12 and 22, John 6 and 8, and Acts 7. Luke 1 reads as 1–40 then 41–80. This drops the longest NT reading from 80 verses to 58 (stdev 14.6 → 11.4) and removes the 10 rest days from 0.8.0, so all three tracks are present on all 270 days and every day needs three check-offs.
|
|
147
|
+
* The daily total is now 76–175 verses (was 76–203), averaging ~119.
|
|
122
148
|
|
|
123
149
|
### Added
|
|
124
|
-
- **Passwordless email sign-in**, so readers without a GitHub/Google/etc. account can take part.
|
|
125
|
-
A reader enters their address, receives a single-use link, and clicks it — no password anywhere
|
|
126
|
-
in the gem.
|
|
127
|
-
- Tokens are 256-bit and URL-safe, expire after 20 minutes (`email_sign_in_ttl`), and are stored
|
|
128
|
-
**only as a SHA-256 digest**, so the table is useless to anyone reading the database.
|
|
129
|
-
- Claiming a link is a conditional `UPDATE`, so a double-clicked link cannot sign in twice.
|
|
130
|
-
- The "check your inbox" response is identical for known, unknown, and rate-limited addresses:
|
|
131
|
-
no account enumeration and no signal that a limit was hit.
|
|
132
|
-
- Rate limited per address per window (`email_sign_in_max_per_window`, `email_sign_in_window`).
|
|
133
|
-
- Readers may choose the display name shown beside their reflections
|
|
134
|
-
(`email_sign_in_ask_name`); otherwise it is derived from the address.
|
|
135
|
-
- `Bible270::SignInToken.sweep!` clears spent and stale rows from a cron or rake task.
|
|
136
|
-
- `Bible270::EmailSignIn` — Rails-free module holding the normalization and token logic, so the
|
|
137
|
-
security-relevant parts are unit testable on their own.
|
|
138
|
-
- `Bible270::SignInMailer` with text and HTML magic-link templates. The sign-in URL is built by the
|
|
139
|
-
controller, so the mailer needs no `default_url_options`.
|
|
140
|
-
- `Bible270::Reader.from_email`, using the same identity columns as OmniAuth with `provider: "email"`,
|
|
141
|
-
so every reader is treated identically downstream.
|
|
142
|
-
- New table: `bible270_sign_in_tokens` (migration `20260101000004`).
|
|
143
|
-
- `config.any_sign_in_method?`, letting views detect a deployment with no sign-in configured.
|
|
144
|
-
|
|
145
|
-
### Fixed
|
|
146
|
-
- `display_name_from` raised `ArgumentError` on any address containing an underscore:
|
|
147
|
-
`tr("._-+", …)` was parsed as a character range. The hyphen now comes last.
|
|
148
|
-
|
|
149
|
-
### Requirements
|
|
150
|
-
- Email sign-in needs working Action Mailer delivery in the host application. Set
|
|
151
|
-
`config.mailer_from`. Delivery is inline by default; set `email_sign_in_deliver_later` if a
|
|
152
|
-
queue backend is available.
|
|
153
150
|
|
|
154
|
-
|
|
151
|
+
* Shared division machinery used by both the NT and the Psalms: `Plan.divide_to_fill`, `expand_readings`, `segment_length`, `format_segment`, `divided`.
|
|
152
|
+
* `Plan.nt_parts`, `nt_readings`, `nt_chapters`, `divided_nt_chapters`, `psalm_chapters`.
|
|
153
|
+
* `totals` reports `nt_readings` (270) and `nt_divided` (10).
|
|
155
154
|
|
|
156
|
-
###
|
|
157
|
-
- Built-in OmniAuth sign-in is now fully wired as the primary auth path.
|
|
158
|
-
- `config.omniauth_providers` accepts symbols or `[provider, label]` pairs, with labels for common
|
|
159
|
-
providers and titleisation for anything custom.
|
|
160
|
-
- Sign-in page at `GET <mount>/sign_in` listing every configured provider.
|
|
161
|
-
- Sign-in controls carry the current path as `origin`, so a reader who clicks a check-off while
|
|
162
|
-
signed out returns to that same day. Origins are validated as local paths only.
|
|
163
|
-
- `rails generate bible270:install`, which writes both initializers with OmniAuth's `path_prefix`
|
|
164
|
-
already aligned to the mount point, adds the `mount` line, and prints the callback URL to register.
|
|
165
|
-
- `omniauth` (>= 2.0) and `omniauth-rails_csrf_protection` (>= 1.0) as runtime dependencies. Provider
|
|
166
|
-
strategy gems remain the host's choice.
|
|
155
|
+
### Removed
|
|
167
156
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
GET on the request phase (CVE-2015-9284). All sign-in controls are now POST forms with CSRF tokens.
|
|
171
|
-
The old link also contained a dead ternary and hardcoded the provider.
|
|
172
|
-
- Open-redirect hardening on the `origin` parameter: protocol-relative URLs, backslashes (which
|
|
173
|
-
browsers may normalise to slashes), and auth routes are all rejected.
|
|
174
|
-
- `reset_session` on sign-in and sign-out, against session fixation.
|
|
175
|
-
- `Reader.from_omniauth` no longer assumes an `OmniAuth::AuthHash`; it tolerates plain hashes and
|
|
176
|
-
missing `info`, and returns `nil` rather than raising on a malformed payload.
|
|
157
|
+
* `Plan.nt_groups`, `format_pp_segment`, `pp_segment_length` (superseded by the shared `format_segment` and `segment_length`), and `totals[:nt_rest_days]`.
|
|
158
|
+
* `nt_rest_days` remains but now always returns an empty array.
|
|
177
159
|
|
|
178
|
-
|
|
179
|
-
- `sign_out` is `DELETE` only (previously `GET` or `DELETE`).
|
|
180
|
-
- Guarded actions redirect to the sign-in page instead of `request.referer`.
|
|
160
|
+
## [0.6.2] — 2026-07-25
|
|
181
161
|
|
|
182
|
-
|
|
162
|
+
This is the initial public release.
|
|
183
163
|
|
|
184
164
|
### Added
|
|
185
|
-
- **Configurable start dates.** `config.start_date` sets a community-wide cohort date (accepting a
|
|
186
|
-
`Date`, `Time`, or `"YYYY-MM-DD"` string); `config.allow_reader_start_date` controls whether
|
|
187
|
-
individuals may set their own. The four combinations give undated, per-reader, community-with-
|
|
188
|
-
override, and fully pinned modes.
|
|
189
|
-
- Readers manage their own date from the overview (`PATCH`/`DELETE <mount>/start-date`).
|
|
190
|
-
- Calendar mapping as pure functions on `Bible270::Plan`: `date_for`, `day_for` (clamped by default,
|
|
191
|
-
`clamp: false` to detect out-of-range), `end_date_for`, `before_start?`, `after_end?`, `to_date`.
|
|
192
|
-
- Day pages show their calendar date with a **Today** badge; the overview gains a "Go to today" link
|
|
193
|
-
and a pace indicator ("3 days behind", "right on pace", "begins in 12 days").
|
|
194
|
-
|
|
195
|
-
### Notes
|
|
196
|
-
- Check-offs and comments are keyed to day numbers, never dates, so changing a start date only
|
|
197
|
-
re-maps the calendar — no reading history moves or is lost.
|
|
198
|
-
- A malformed `config.start_date` degrades to `nil` rather than raising at boot; the controller does
|
|
199
|
-
reject bad input with a flash message.
|
|
200
|
-
|
|
201
|
-
## [0.3.1] — 2026-07-24
|
|
202
165
|
|
|
203
|
-
|
|
204
|
-
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
166
|
+
* Initial release of a mountable Rails engine providing a 270-day Bible reading plan with three daily tracks: Old Testament, New Testament, and Psalms/Proverbs.
|
|
167
|
+
* Per-reader check-offs, public per-day reflections, a community leaderboard, and reader profiles.
|
|
168
|
+
* Two identity paths: built-in session sign-in, or bridging the host application's users via `config.current_reader_resolver` and `Reader.for_owner`.
|
|
169
|
+
* A pure, deterministic Ruby schedule; the database stores readers, check-offs, and comments rather than plan rows.
|
|
170
|
+
* `Bible270::Versification`, providing per-chapter verse counts for all 66 books, generated from a public-domain KJV text and validated against canonical anchors.
|
|
171
|
+
* Verse-balanced daily portions rather than chapter-count balancing, so daily reading time is approximately even.
|
|
172
|
+
* Old Testament days grouped to be even in verses, averaging approximately 73 verses per day.
|
|
173
|
+
* Per-track progress bars based on days read rather than chapter totals.
|
|
174
|
+
* The New Testament read twice, with each pass occupying half of the 270-day plan. Whole chapters are verse-balanced within each pass.
|
|
175
|
+
* A Psalms/Proverbs companion plan resolving to exactly 135 portions, making two complete passes across the 270-day plan.
|
|
176
|
+
* Chapters are generally kept whole; Psalm 119 is divided into two readings, while shorter chapters may be combined with a neighboring psalm.
|
|
177
|
+
* Configurable start dates through `config.start_date` and `config.allow_reader_start_date`, including per-reader date management.
|
|
178
|
+
* Calendar mapping functions on `Bible270::Plan`: `date_for`, `day_for`, `end_date_for`, `before_start?`, `after_end?`, and `to_date`.
|
|
179
|
+
* Calendar-aware day pages, including a **Today** badge, a **Go to today** link, and a pace indicator.
|
|
180
|
+
* Built-in OmniAuth sign-in as the primary authentication path.
|
|
181
|
+
* Configurable OmniAuth providers, including labels for common providers and titleisation for custom providers.
|
|
182
|
+
* A sign-in page at `GET <mount>/sign_in`.
|
|
183
|
+
* `rails generate bible270:install`, which creates the initializers, adds the engine mount, configures OmniAuth's path prefix, and prints the callback URL.
|
|
184
|
+
* Passwordless email sign-in using single-use magic links.
|
|
185
|
+
* Secure email sign-in tokens that are 256-bit, URL-safe, expire after 20 minutes, and are stored only as SHA-256 digests.
|
|
186
|
+
* Rate limiting for email sign-in attempts and protection against account enumeration.
|
|
187
|
+
* Optional reader-selected display names for email sign-in.
|
|
188
|
+
* `Bible270::SignInToken.sweep!` for clearing spent and stale tokens.
|
|
189
|
+
* `Bible270::EmailSignIn`, a Rails-free module containing the normalization and token logic.
|
|
190
|
+
* `Bible270::SignInMailer` with text and HTML magic-link templates.
|
|
191
|
+
* `Bible270::Reader.from_email`, using the same identity columns as OmniAuth with `provider: "email"`.
|
|
192
|
+
* The `bible270_sign_in_tokens` table.
|
|
193
|
+
* `config.any_sign_in_method?`.
|
|
194
|
+
* A centralized `config.mount_at` setting, defaulting to `/daily-bread`, with derived `config.auth_path_prefix`.
|
|
195
|
+
* Support for nested mount paths and mounting at `/`.
|
|
196
|
+
* Configuration-driven engine mounting and OmniAuth path prefixes.
|
|
197
|
+
* `spec.email` in the gemspec.
|
|
198
|
+
* Gem metadata pointing to the actual repository for `source_code_uri`, `bug_tracker_uri`, and `changelog_uri`.
|
|
199
|
+
* RubyGems MFA requirement through `rubygems_mfa_required`.
|
|
200
|
+
* This changelog, packaged with the gem.
|
|
201
|
+
* Compatibility notes and tests covering Ruby 4.0 changes, including removal of the `cgi` dependency.
|
|
208
202
|
|
|
209
|
-
###
|
|
210
|
-
- Regression test asserting the gem never loads the `cgi` library.
|
|
211
|
-
- Compatibility notes in the README: audited against the Ruby 4.0 breaking changes (`Set`/`SortedSet`,
|
|
212
|
-
`Ractor`, `Net::HTTP`, `Process::Status`, `ObjectSpace`, and the gems promoted from default to
|
|
213
|
-
bundled). Every file carries a `frozen_string_literal` comment and the suite passes with
|
|
214
|
-
`--enable-frozen-string-literal` forced.
|
|
215
|
-
|
|
216
|
-
## [0.3.0] — 2026-07-24
|
|
217
|
-
|
|
218
|
-
### Changed — BREAKING
|
|
219
|
-
- **Renamed from `bible_reading_plan` to `bible270`.** Module `Bible270`, tables `bible270_*`,
|
|
220
|
-
migrations `CreateBible270*`, CSS and helper prefix `b270`, install task
|
|
221
|
-
`bible270:install:migrations`, mount `Bible270::Engine`. Table names changed, so this is a fresh
|
|
222
|
-
install rather than an upgrade.
|
|
223
|
-
- **The New Testament is now read twice.** Each pass gets its own half of the plan (135 days), so
|
|
224
|
-
Revelation lands on day 135 and again on day 270. Whole chapters are verse-balanced within each
|
|
225
|
-
pass, tightening NT days from 11–140 verses to 20–104. The NT track now has content every day, so
|
|
226
|
-
there are no rest days and all three tracks are present on all 270 days.
|
|
227
|
-
- **Chapters are kept whole.** Only a chapter longer than `PP_LONG_CHAPTER` (100 verses) is divided,
|
|
228
|
-
which in the whole Psalter and Proverbs is Psalm 119 alone — split into exactly two readings
|
|
229
|
-
(1–88, 89–176). Psalms 78 and 89 are no longer split. Short chapters merge with a neighbour, so
|
|
230
|
-
Psalm 117 reads as "Psalm 116–117" rather than occupying a two-verse day.
|
|
231
|
-
- The Psalms/Proverbs companion resolves to exactly 135 portions, making two complete passes across
|
|
232
|
-
270 days and finishing on Proverbs 31 — so all three tracks finish together at the halfway mark
|
|
233
|
-
and at the end.
|
|
203
|
+
### Changed
|
|
234
204
|
|
|
235
|
-
|
|
236
|
-
-
|
|
237
|
-
|
|
205
|
+
* The project was renamed from `bible_reading_plan` to `bible270`, including the `Bible270` module, database tables, migrations, CSS and helper prefixes, install task, and engine name.
|
|
206
|
+
* The install generator defaults to `/daily-bread`, writes the mount path into the engine initializer, and emits configuration-driven `mount` and `path_prefix` lines.
|
|
207
|
+
* The README documents the mount point, initializer load-order requirements, OAuth callback URLs, and CMS links that may need updating when the mount path changes.
|
|
208
|
+
* The engine's sign-in paths follow the mount point at runtime through `request.script_name`.
|
|
209
|
+
* Author and copyright information now read “Andrew vonderLuft”.
|
|
210
|
+
* The display-name-from-email example uses a neutral address.
|
|
211
|
+
* `sign_out` is `DELETE` only.
|
|
212
|
+
* Guarded actions redirect to the sign-in page.
|
|
213
|
+
* URL escaping uses `URI.encode_www_form_component` rather than `CGI.escape`.
|
|
238
214
|
|
|
239
|
-
|
|
215
|
+
### Fixed
|
|
240
216
|
|
|
241
|
-
|
|
242
|
-
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
217
|
+
* **`db:migrate` failed with `ActiveRecord::DuplicateMigrationNameError`.** The engine appended its own `db/migrate` to the host application's migration paths and also exposed `bible270:install:migrations`. Using the task meant every migration class was defined twice. The engine no longer touches the host's migration paths; copying via the task is the single supported path.
|
|
218
|
+
* Sign-in was broken under OmniAuth 2.0 because the request phase no longer permits GET requests. Sign-in controls now use POST forms with CSRF tokens.
|
|
219
|
+
* Open redirects through the `origin` parameter, including protocol-relative URLs, backslashes, and authentication routes.
|
|
220
|
+
* Session fixation by resetting the session on sign-in and sign-out.
|
|
221
|
+
* `Reader.from_omniauth` now tolerates plain hashes, missing `info`, and malformed payloads without raising.
|
|
222
|
+
* `display_name_from` no longer raises `ArgumentError` for addresses containing underscores.
|
|
223
|
+
* Ruby 4.0 compatibility issues caused by the removed `cgi` default gem.
|
|
224
|
+
* Progress bars that could not reach the correct totals because they compared checked days with chapter totals.
|
|
246
225
|
|
|
247
|
-
###
|
|
248
|
-
- `Bible270::Versification` — per-chapter verse counts for all 66 books, generated from a
|
|
249
|
-
public-domain KJV text and validated against canonical anchors (1,189 chapters; Psalms 2,461
|
|
250
|
-
verses; Proverbs 915; Psalm 119 = 176; Psalm 117 = 2). Verse counts are facts about the text's
|
|
251
|
-
structure, so nothing copyrighted is bundled.
|
|
226
|
+
### Breaking Changes
|
|
252
227
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
228
|
+
* The project was renamed from `bible_reading_plan` to `bible270`; this is a fresh install rather than an in-place upgrade because database table names changed.
|
|
229
|
+
* The New Testament schedule changed from a single pass to two verse-balanced passes.
|
|
230
|
+
* The Psalms/Proverbs schedule changed to two complete 135-portion passes.
|
|
231
|
+
* Calendar and reading-plan behavior is based on day numbers rather than stored plan rows.
|
|
257
232
|
|
|
258
|
-
|
|
233
|
+
### Requirements
|
|
259
234
|
|
|
260
|
-
|
|
261
|
-
- Initial release: a mountable Rails engine providing a 270-day Bible reading plan with three daily
|
|
262
|
-
tracks (Old Testament, New Testament, Psalms/Proverbs).
|
|
263
|
-
- Per-reader check-offs, public per-day reflections, a community leaderboard, and reader profiles.
|
|
264
|
-
- Two identity paths: built-in session sign-in, or bridging the host application's users via
|
|
265
|
-
`config.current_reader_resolver` and `Reader.for_owner`.
|
|
266
|
-
- The schedule is pure, deterministic Ruby — no rows are stored for the plan itself; the database
|
|
267
|
-
holds only readers, check-offs, and comments.
|
|
235
|
+
* Email sign-in requires working Action Mailer delivery in the host application. Set `config.mailer_from`; delivery is inline by default, or set `email_sign_in_deliver_later` when a queue backend is available.
|
|
268
236
|
|
|
237
|
+
[0.11.0]: https://github.com/avonderluft/bible270/releases/tag/v0.10.0
|
|
238
|
+
[0.10.0]: https://github.com/avonderluft/bible270/releases/tag/v0.10.0
|
|
269
239
|
[0.9.0]: https://github.com/avonderluft/bible270/releases/tag/v0.9.0
|
|
270
|
-
[0.8.0]: https://github.com/avonderluft/bible270/releases/tag/v0.8.0
|
|
271
|
-
[0.7.0]: https://github.com/avonderluft/bible270/releases/tag/v0.7.0
|
|
272
|
-
[0.6.3]: https://github.com/avonderluft/bible270/releases/tag/v0.6.3
|
|
273
240
|
[0.6.2]: https://github.com/avonderluft/bible270/releases/tag/v0.6.2
|
|
274
|
-
[0.6.1]: https://github.com/avonderluft/bible270/releases/tag/v0.6.1
|
|
275
|
-
[0.6.0]: https://github.com/avonderluft/bible270/releases/tag/v0.6.0
|
|
276
|
-
[0.5.0]: https://github.com/avonderluft/bible270/releases/tag/v0.5.0
|
|
277
|
-
[0.4.0]: https://github.com/avonderluft/bible270/releases/tag/v0.4.0
|
|
278
|
-
[0.3.1]: https://github.com/avonderluft/bible270/releases/tag/v0.3.1
|
|
279
|
-
[0.3.0]: https://github.com/avonderluft/bible270/releases/tag/v0.3.0
|
|
280
|
-
[0.2.0]: https://github.com/avonderluft/bible270/releases/tag/v0.2.0
|
|
281
|
-
[0.1.0]: https://github.com/avonderluft/bible270/releases/tag/v0.1.0
|