fix(17): WR-03 require a reference for a menu entry whose type takes one

An entry of a registry type with References saved without a reference
passed the dependent recheck (null is always among the options), then
resolved to nothing and vanished from the public tree with its children.
The admin save now refuses it (errors.reference_required).
This commit is contained in:
2026-10-12 21:33:36 +02:00
parent 7255d34ae0
commit 64215f2bf3
5 changed files with 16 additions and 5 deletions

View File

@@ -3,6 +3,7 @@ package controllers
import (
"context"
"errors"
"strings"
"git.golem15.com/golem15/sm-menu-plugin/classes"
"git.golem15.com/golem15/sm-menu-plugin/models"
@@ -22,6 +23,7 @@ const (
errURLScheme = "golem15.menu::lang.errors.url_scheme"
errTarget = "golem15.menu::lang.errors.target"
errTypeUnknown = "golem15.menu::lang.errors.type_unknown"
errReference = "golem15.menu::lang.errors.reference_required"
errMenuRequired = "golem15.menu::lang.errors.menu_required"
errParentCycle = "golem15.menu::lang.errors.parent_cycle"
errParentMenu = "golem15.menu::lang.errors.parent_menu"
@@ -150,8 +152,10 @@ func (c menuEntriesAdminController) FormBeforeUpdate(_ context.Context, model an
return c.checkEntry(model)
}
// checkEntry refuses an unknown type, a URL outside the scheme allowlist
// (errors.url_scheme, Pitfall 15) and a target other than _self or _blank.
// checkEntry refuses an unknown type, a registry type that takes a
// reference saved without one (it would resolve to nothing and vanish from
// the public tree), a URL outside the scheme allowlist (errors.url_scheme,
// Pitfall 15) and a target other than _self or _blank.
func (c menuEntriesAdminController) checkEntry(model any) error {
entry, ok := model.(*models.MenuEntry)
if !ok || entry == nil {
@@ -159,8 +163,12 @@ func (c menuEntriesAdminController) checkEntry(model any) error {
}
details := map[string]any{}
if entry.Type != "" && !models.Builtin(entry.Type) {
if _, known := c.registry().Type(entry.Type); !known {
t, known := c.registry().Type(entry.Type)
switch {
case !known:
details["type"] = []string{errTypeUnknown}
case t.References != nil && strings.TrimSpace(models.Text(entry.Reference)) == "":
details["reference"] = []string{errReference}
}
}
if !classes.AllowedURL(models.Text(entry.URL)) {