From a7309d5268cfa48753b3c6a59108146ce4723524 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Fri, 3 Feb 2023 15:12:52 +0100 Subject: [PATCH] component.DummyMenuItem: Force early replacement --- internal/dis/component/auth/panel/user.go | 9 +++-- internal/dis/component/menu.go | 33 ++++++++++++++++--- .../dis/component/server/admin/components.go | 13 +++++--- internal/dis/component/server/admin/grants.go | 13 +++++--- .../dis/component/server/admin/instance.go | 18 ++++++---- .../dis/component/server/templating/base.go | 2 -- .../dis/component/server/templating/flags.go | 14 +++++--- 7 files changed, 75 insertions(+), 27 deletions(-) diff --git a/internal/dis/component/auth/panel/user.go b/internal/dis/component/auth/panel/user.go index 066c6f0..36a87e6 100644 --- a/internal/dis/component/auth/panel/user.go +++ b/internal/dis/component/auth/panel/user.go @@ -34,7 +34,12 @@ type GrantWithURL struct { URL template.URL } +var ( + totpActionItem = component.DummyMenuItem() +) + func (panel *UserPanel) routeUser(ctx context.Context) http.Handler { + tpl := userTemplate.Prepare( panel.Dependencies.Templating, templating.Crumbs( @@ -42,7 +47,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler { ), templating.Actions( component.MenuItem{Title: "Change Password", Path: "/user/password/"}, - component.DummyMenuItem, + totpActionItem, component.MenuItem{Title: "SSH Keys", Path: "/user/ssh/"}, ), ) @@ -68,7 +73,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler { } } funcs = []templating.FlagFunc{ - templating.ReplaceAction(1, totpAction), + templating.ReplaceAction(totpActionItem, totpAction), templating.Title(uc.AuthUser.User.User), } diff --git a/internal/dis/component/menu.go b/internal/dis/component/menu.go index 42da728..d48b471 100644 --- a/internal/dis/component/menu.go +++ b/internal/dis/component/menu.go @@ -3,6 +3,7 @@ package component import ( "html/template" "net/http" + "sync/atomic" ) // Menuable is a component that provides a menu @@ -16,13 +17,35 @@ type MenuItem struct { Path template.URL Active bool - Priority MenuPriority // menu priority + Priority MenuPriority + + replaceID uint64 // internal id used to replace an item } -// DummyMenuItem is a dummy menu item -// It should be replaced before being displayed to the user -var DummyMenuItem = MenuItem{ - Title: "* to be replaced *", +var dummyCounter uint64 + +// DummyMenuItem creates a new Dummy Menu Item to be replaced +func DummyMenuItem() MenuItem { + return MenuItem{ + replaceID: atomic.AddUint64(&dummyCounter, 1), + } +} + +// ReplaceWith replaces this MenuItem with a different MenuItem. +// This method returns true if an appropriate DummyMenuItem exists. +func (mi MenuItem) ReplaceWith(new MenuItem, items []MenuItem) bool { + if mi.replaceID == 0 { + // never replace non-dummy items + return false + } + for i, item := range items { + if mi.replaceID == item.replaceID { + items[i] = new + return true + } + } + + return false } func MenuItemSort(a, b MenuItem) bool { diff --git a/internal/dis/component/server/admin/components.go b/internal/dis/component/server/admin/components.go index 4808fc4..37916d0 100644 --- a/internal/dis/component/server/admin/components.go +++ b/internal/dis/component/server/admin/components.go @@ -47,14 +47,19 @@ func (admin *Admin) components(ctx context.Context) http.Handler { }) } +var ( + instanceCrumb = component.DummyMenuItem() + ingredientsCrumb = component.DummyMenuItem() +) + func (admin *Admin) ingredients(ctx context.Context) http.Handler { tpl := analTemplate.Prepare( admin.Dependencies.Templating, templating.Crumbs( component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, - component.DummyMenuItem, - component.DummyMenuItem, + instanceCrumb, + ingredientsCrumb, ), ) @@ -70,8 +75,8 @@ func (admin *Admin) ingredients(ctx context.Context) http.Handler { return ac, nil, err } funcs = []templating.FlagFunc{ - templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), - templating.ReplaceCrumb(3, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")}), + templating.ReplaceCrumb(instanceCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), + templating.ReplaceCrumb(ingredientsCrumb, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")}), templating.Title(instance.Name() + " - Ingredients"), } diff --git a/internal/dis/component/server/admin/grants.go b/internal/dis/component/server/admin/grants.go index 23d200f..21845ca 100644 --- a/internal/dis/component/server/admin/grants.go +++ b/internal/dis/component/server/admin/grants.go @@ -41,14 +41,19 @@ type grantsContext struct { Drupals []string // unusued drupal usernames } +var ( + instancePageCrumb = component.DummyMenuItem() + grantsPageCrumb = component.DummyMenuItem() +) + func (admin *Admin) grants(ctx context.Context) http.Handler { tpl := grantsTemplate.Prepare( admin.Dependencies.Templating, templating.Crumbs( component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, - component.DummyMenuItem, - component.DummyMenuItem, + instancePageCrumb, + grantsPageCrumb, ), ) @@ -137,8 +142,8 @@ func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (funcs // replace the functions funcs = []templating.FlagFunc{ - templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), - templating.ReplaceCrumb(3, component.MenuItem{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")}), + templating.ReplaceCrumb(instancePageCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), + templating.ReplaceCrumb(grantsPageCrumb, component.MenuItem{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")}), templating.Title(gc.Instance.Slug + " - Grants"), } return funcs, nil diff --git a/internal/dis/component/server/admin/instance.go b/internal/dis/component/server/admin/instance.go index 429db76..39c40fb 100644 --- a/internal/dis/component/server/admin/instance.go +++ b/internal/dis/component/server/admin/instance.go @@ -31,17 +31,23 @@ type instanceContext struct { Info status.WissKI } +var ( + instancesPageCrumb = component.DummyMenuItem() + grantsAction = component.DummyMenuItem() + ingredientsAction = component.DummyMenuItem() +) + func (admin *Admin) instance(ctx context.Context) http.Handler { tpl := instanceTemplate.Prepare( admin.Dependencies.Templating, templating.Crumbs( component.MenuItem{Title: "Admin", Path: "/admin/"}, component.MenuItem{Title: "Instances", Path: "/admin/instance/"}, - component.DummyMenuItem, + instancesPageCrumb, ), templating.Actions( - component.DummyMenuItem, - component.DummyMenuItem, + grantsAction, + ingredientsAction, ), ) @@ -65,9 +71,9 @@ func (admin *Admin) instance(ctx context.Context) http.Handler { } funcs = []templating.FlagFunc{ - templating.ReplaceCrumb(2, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), - templating.ReplaceAction(0, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}), - templating.ReplaceAction(1, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton}), + templating.ReplaceCrumb(instancesPageCrumb, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}), + templating.ReplaceAction(grantsAction, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}), + templating.ReplaceAction(ingredientsAction, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton}), templating.Title(instance.Slug), } diff --git a/internal/dis/component/server/templating/base.go b/internal/dis/component/server/templating/base.go index 4247893..9a9613d 100644 --- a/internal/dis/component/server/templating/base.go +++ b/internal/dis/component/server/templating/base.go @@ -203,7 +203,6 @@ const ( ) func (ctx *tContext[C]) doMain(err error) (template.HTML, error) { - zerolog.Ctx(ctx.ctx).Info().Msg("doMain") if err != nil { zerolog.Ctx(ctx.ctx).Err(err).Msg("error lazy loading template") return errUnknown, nil @@ -220,7 +219,6 @@ func (ctx *tContext[C]) doMain(err error) (template.HTML, error) { } func (ctx *tContext[C]) AfterBody() (template.HTML, error) { - zerolog.Ctx(ctx.ctx).Info().Msg("AfterBody()") // everything was done already if !ctx.cWaiting { return "", nil diff --git a/internal/dis/component/server/templating/flags.go b/internal/dis/component/server/templating/flags.go index 9c7de8e..e05908d 100644 --- a/internal/dis/component/server/templating/flags.go +++ b/internal/dis/component/server/templating/flags.go @@ -1,12 +1,14 @@ package templating import ( + "fmt" "html/template" "net/http" "time" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets" + "github.com/rs/zerolog" "github.com/tkw1536/goprogram/lib/reflectx" "golang.org/x/exp/slices" ) @@ -77,17 +79,21 @@ func Actions(actions ...component.MenuItem) FlagFunc { } // ReplaceAction replaces a specific action -func ReplaceAction(index int, action component.MenuItem) FlagFunc { +func ReplaceAction(old component.MenuItem, action component.MenuItem) FlagFunc { return func(flags Flags, r *http.Request) Flags { - flags.Actions[index] = action + if !old.ReplaceWith(action, flags.Actions) { + zerolog.Ctx(r.Context()).Warn().Str("action", fmt.Sprint(action)).Str("actions", fmt.Sprint(flags.Actions)).Msg("did not replace menu item") + } return flags } } // ReplaceCrumb replaces a specific crum -func ReplaceCrumb(index int, action component.MenuItem) FlagFunc { +func ReplaceCrumb(old component.MenuItem, action component.MenuItem) FlagFunc { return func(flags Flags, r *http.Request) Flags { - flags.Crumbs[index] = action + if !old.ReplaceWith(action, flags.Crumbs) { + zerolog.Ctx(r.Context()).Warn().Str("action", fmt.Sprint(action)).Str("actions", fmt.Sprint(flags.Actions)).Msg("did not replace menu item") + } return flags } }