feat: noindex paths from the route report leave the sitemaps (tracer)

The route report takes an optional noindex list of static paths. When
the key is present the stored set (golem15_seo_noindex_paths) is
replaced, and the sitemap filter leaves those paths out with the reason
noindex; a changed set asks the sitemap for a debounced rebuild through
contract.Rebuilder. A listed noindex address without a CMS record now
names sitemap_update_settings, or fix: code without the sitemap plugin.
This commit is contained in:
Jakub Zych
2026-11-04 22:44:26 +01:00
parent 075cf17007
commit 9de6b2ec83
12 changed files with 458 additions and 26 deletions

View File

@@ -16,23 +16,42 @@ import (
"gorm.io/gorm"
)
// maxRouteReportBody caps the route report body: 2000 paths of 2048 bytes
// with their JSON quoting.
const maxRouteReportBody = classes.MaxReportedRoutes*(classes.MaxRouteBytes+8) + 1024
// maxRouteReportBody caps the route report body: two lists (routes and
// noindex) of 2000 paths of 2048 bytes with their JSON quoting.
const maxRouteReportBody = 2*classes.MaxReportedRoutes*(classes.MaxRouteBytes+8) + 1024
// routeReport is the route report body.
// routeReport is the route report body. Noindex is nil when the key is
// absent and non-nil (also empty) when it is present.
type routeReport struct {
Routes []string `json:"routes"`
Routes []string `json:"routes"`
Noindex *[]string `json:"noindex"`
}
// routeReportAnswer is the route report answer: the counts of the routes
// and the number of stored noindex paths.
type routeReportAnswer struct {
classes.RouteReport
Noindex int `json:"noindex"`
}
// RouteReport serves POST /_seo/api/v1/registry/routes (D-33, P33-20): the
// frontend server reports its static routes with "Authorization: Bearer
// <token>", golem15.seo.route_report_token (else notfound_token), compared
// in constant time. Unknown paths become registry pages (origin reported),
// known ones get reported_at; nothing is deleted or overwritten. It answers
// 200 with the counts, 401 for a missing or wrong token, 404 when no token
// is configured (the report is off), and 422 for a malformed body or more
// than 2000 paths.
// known ones get reported_at; nothing is deleted or overwritten.
//
// The optional noindex key (P33-58) lists the static paths the frontend
// serves noindex: when it is present (also as []), the stored set becomes
// exactly its valid entries, normalised like the routes, in the same
// transaction (an invalid entry is skipped and counted in skipped); when it
// is absent the stored set is unchanged. The sitemap filter leaves those
// paths out of the sitemaps, and a changed set asks the sitemap for one
// debounced rebuild.
//
// It answers 200 with the counts and noindex, the number of stored noindex
// paths; 401 for a missing or wrong token, 404 when no token is configured
// (the report is off), and 422 for a malformed body or more than 2000
// paths in either list, storing nothing.
func RouteReport(service func() *classes.Service) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
svc := service()
@@ -56,14 +75,24 @@ func RouteReport(service func() *classes.Service) http.HandlerFunc {
wire.WriteJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": errInvalidBody})
return
}
if len(in.Routes) > classes.MaxReportedRoutes {
if len(in.Routes) > classes.MaxReportedRoutes || (in.Noindex != nil && len(*in.Noindex) > classes.MaxReportedRoutes) {
wire.WriteJSON(w, http.StatusUnprocessableEntity, map[string]any{"error": "too_many_routes", "max": classes.MaxReportedRoutes})
return
}
var out classes.RouteReport
var out routeReportAnswer
err := write(r.Context(), svc, func(ctx context.Context, tx *gorm.DB) error {
var err error
out, err = svc.ReportRoutes(ctx, tx, in.Routes)
out.RouteReport, err = svc.ReportRoutes(ctx, tx, in.Routes)
if err != nil {
return err
}
if in.Noindex != nil {
var skipped int
out.Noindex, skipped, _, err = svc.ReportNoindex(ctx, tx, *in.Noindex)
out.Skipped += skipped
return err
}
out.Noindex, err = classes.NoindexPathCount(tx)
return err
})
if err != nil {