Latest Chapter correction: one numeric input, owner-gated (#149)

This commit is contained in:
2026-08-22 09:04:24 +07:00
parent 889f0f3f38
commit c9b1f2a334
10 changed files with 423 additions and 19 deletions
+13 -6
View File
@@ -41,7 +41,8 @@ type SeriesFilter struct {
// must never leave the store package — so the projection does not select it,
// and only the anonymous boolean in raisedByReaderAnswer crosses it.
const adminSeriesColumns = `s.site, s.series_id, s.title, s.series_url, s.cover_address,
s.kind, s.latest_chapter, s.latest_chapter_num, s.latest_checked_at, s.force_poll_at`
s.kind, s.latest_chapter, s.latest_chapter_num, s.latest_checked_at, s.force_poll_at,
s.latest_corrected_at`
// raisedByReaderAnswer answers "did a Reader's report set this number" without
// naming which Reader. Kept apart from adminSeriesColumns so the column list —
@@ -71,9 +72,15 @@ type AdminSeries struct {
// ForcePollAt is the owner's "check now" request stamp (issue #146), zero
// meaning never asked. Pending is derived, never stored: a request is
// pending while ForcePollAt is newer than LatestCheckedAt.
ForcePollAt int64
ReaderCount int
RaisedByReader bool // a Reader's report set LatestChapterNum
ForcePollAt int64
// LatestCorrectedAt is the correction stamp (issue #149): non-zero means
// the Latest Chapter is the owner's, zero means never corrected. The
// provenance line (#152) derives from it, so the zero-means-never meaning
// is load-bearing.
LatestCorrectedAt int64
ReaderCount int
RaisedByReader bool // a Reader's report set LatestChapterNum
}
// SeriesPage is one page of the owner's filtered Series list plus the count
@@ -189,7 +196,7 @@ func (s *Store) SeriesPage(f SeriesFilter) (SeriesPage, error) {
`+where+`
GROUP BY s.site, s.series_id, s.title, s.series_url, s.cover_address,
s.kind, s.latest_chapter, s.latest_chapter_num, s.latest_checked_at,
s.force_poll_at, s.latest_raised_by
s.force_poll_at, s.latest_corrected_at, s.latest_raised_by
`+having+`
ORDER BY s.latest_checked_at, s.site, s.series_id
LIMIT $`+strconv.Itoa(base+1)+` OFFSET $`+strconv.Itoa(base+2), args...)
@@ -264,7 +271,7 @@ func scanAdminSeries(scan func(...any) error) (AdminSeries, int, error) {
if err := scan(
&a.Site, &a.SeriesID, &a.Title, &a.SeriesURL, &a.CoverAddress,
&a.Kind, &a.LatestChapter, &latestChapterNum, &a.LatestCheckedAt,
&a.ForcePollAt,
&a.ForcePollAt, &a.LatestCorrectedAt,
&a.RaisedByReader, &a.ReaderCount, &total,
); err != nil {
return AdminSeries{}, 0, err