Commit Graph

15 Commits

Author SHA1 Message Date
Jakub Zych
2200e46d98 fix: rebuilds collect under one lock and keep moved lastmods
A rebuild takes the transaction-scoped advisory lock
golem15.sitemap.rebuild before it reads the settings and collects, and
applies in the same transaction, so a second rebuild collects only after
the first has committed. apply no longer writes the lastmod of a content
row it did not create, so a lastmod RecordSaved moved meanwhile stays.
2026-11-04 23:04:01 +01:00
Jakub Zych
f58d55555c fix: IndexNow hears of deleted and edited records
RecordDeleted marks the listed rows it excludes and RecordSaved the rows
whose lastmod it moves (indexnow_pending_at); the next rebuild sends
them to IndexNow as removed or changed and clears the marks. RecordSaved
checks for a nil event before reading it. TestIndexNow now deletes and
edits through the record events, as the admin does.
2026-11-04 23:02:09 +01:00
Jakub Zych
6b67ab759b feat: contract.Rebuilder asks for a debounced rebuild
The sitemap publishes classes.Listing as contract.Rebuilder too, so a
plugin whose Filter reads data of its own can queue the debounced rebuild
a record event queues when that data changes.
2026-11-04 22:39:14 +01:00
Jakub Zych
096b6f6bfe fix: list an additional address once when a content record has it
- an additional address whose absolute URL a listed record already has is
  left out with the new reason duplicate (models.ReasonDuplicate)
- the settings screen counts it under Already listed by a content type
- a record left out by the filter or the type switch does not count
2026-11-04 19:22:56 +01:00
Jakub Zych
9e5c393709 feat: the listing names the content types switched off
contract.ListingSettings.TypesOff lists the signpost keys of the content
types switched off in the sitemap settings, so another plugin (the SEO
tab's sitemap status) can tell an address left out with ReasonType
without reading the sitemap's tables. Additive.
2026-11-04 13:35:17 +01:00
Jakub Zych
291cf176db docs: images, News, IndexNow, HTML sitemap and MCP in README
- routes, buckets, the image and News sitemaps, IndexNow (key, jobs,
  answers, status), the HTML sitemap API's JSON, the management API and
  the MCP tools, the new settings tabs, identifiers and tests
- plugin.yaml regenerated for the new summary
2026-11-04 12:40:37 +01:00
Jakub Zych
64453d2a91 docs: README for the per-type sitemap format
- routes, site address, lastmod rules, rebuilds, the contract package
  with a Filter example, the Listing, the settings screen, config keys
- the breaking change from v0.1 and the definitions migration
- plugin.yaml regenerated from the new summary
2026-11-04 11:23:19 +01:00
Jakub Zych
96c790df39 feat: console help, examples and named loggers (SummerCMS v0.4.0)
Every command gets long help and examples, descriptions in imperative
sentence case, and a warn-only TestCommandsDocumented over bonfire.CheckDocs.
The plugin logs through a diary component logger instead of the process
default logger. Requires SummerCMS v0.4.0; command names and flags unchanged.
2026-10-21 17:35:43 +02:00
Jakub Zych
1bb89ce006 fix(17): T-17-15 refuse an unsafe frontend_url on save and import
- Settings.BeforeValidate answers a cabana validation error on
  frontend_url, so the settings save is a 422 and the row is unchanged
- sitemap:import-winter stops on a frontend_url that
  models.AllowedFrontendURL refuses, before the dry-run branch and before
  any database use; the value is printed quoted
- errors.frontend_url phrase in en and pl
- TestSettingsBeforeValidate, TestWinterSettingsFrontendURL and the save
  and import refusals in the Postgres smokes
2026-10-13 00:59:24 +02:00
Jakub Zych
b9804ddf17 fix(17): T-17-15 apply the frontend_url rewrite only for a safe http(s) URL
- models.AllowedFrontendURL: empty, or an absolute http(s) URL with a host
  and without whitespace, control characters, a double quote, <, > or &
- classes.Rewrite leaves the document unchanged for a refused value,
  inserts through EscapeText/EscapeAttr and keeps a loc or href that would
  not stay an http(s) URL
- TestRewriteUnsafeFrontendURL, TestAllowedFrontendURL and a stored-row
  check in TestSitemapImportSmoke
2026-10-13 00:57:02 +02:00
cf5c40e442 fix(17): WR-05 throttle /sitemap.xml and cache its output
The anonymous route resolved every registry item on each request with no
throttle and no cache.

- surf bucket sitemap-xml: 60 requests a minute per client IP.
- The generated XML is cached for golem15.sitemap.cache_seconds (default
  60, 0 off), keyed by root URL, definition and settings so a save shows
  at once; one generation runs at a time.
2026-10-12 21:38:39 +02:00
433202bbc8 fix(17): WR-03 require a reference for a sitemap row whose type takes one
A registry row saved without a reference resolved to nothing and was
left out of /sitemap.xml without a word. The definitions form now
refuses it on the row (data.<i>.reference, item.reference_required).
The admin smoke test also covers the CR-01 row refusals.
2026-10-12 21:34:30 +02:00
c42bc265c8 fix(17): CR-01 refuse non-http sitemap URLs on save, import and output
A url item stored as javascript://%0aalert(1)%0a//x passed Url::to and
reached <loc>, which sitemap.xsl renders as a link on the site origin.

- The definitions form refuses, per row, a url that is not a path or an
  http(s) URL (classes.AllowedItemURL) and a urlPattern that is not a
  path (signpost.ValidItemPattern), keyed data.<i>.url / .urlPattern.
- Generator.addItem drops a loc or alternate that is not http(s).
- sitemap:import-winter drops such url items and clears such patterns
  with a report line; sitemap:import refuses such an entry.
2026-10-12 21:28:28 +02:00
5a260db51b feat(17-05): sitemap:import-winter --page-url copies a CMS page item as a url item
- a Winter cms-page or static-page item whose reference is named by
  --page-url reference=/path becomes a url item with that URL (reported
  as remapped) instead of being dropped
- smoke test and README cover the flag
2026-10-12 18:07:53 +02:00
7d937e3cf5 feat(17-03): sitemap admin, permissions, lang and README
- definitions singleton controller (theme default, first or create) with a
  repeater on data: type dropdown (url plus registry types), reference
  dependsOn type through signpost.ReferenceOptions
- Settings page entries: Sitemap (link to the controller) and Sitemap
  settings (form), both behind golem15.sitemap.access_definitions
- en and pl phrasebooks with the PHP keys
- README with the PHP parity rules, tiers, hooks, commands and the Winter
  YAML adaptations
- TestSitemapAdminSmoke: singleton, PHP-keyed rows, 422 on a foreign
  reference, settings save, 403 without the permission
2026-10-12 17:14:04 +02:00