shared

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CONTROLLER_USER_MANAGER     = "user-manager"
	CONTROLLER_USER_CREATE      = "user-create"
	CONTROLLER_USER_DELETE      = "user-delete"
	CONTROLLER_USER_UPDATE      = "user-update"
	CONTROLLER_USER_IMPERSONATE = "user-impersonate"
)

Controller names used in the ?controller= query parameter

View Source
const CatchAll = "/*"

CatchAll is the catch-all route suffix

View Source
const ERROR_LOGGER_IS_NIL = "logger cannot be nil"
View Source
const ERROR_USER_STORE_IS_NIL = "user store cannot be nil"

Error messages

View Source
const KeyAdminHomeURL = "admin_home_url"
View Source
const KeyEndpoint = "endpoint"

Context keys for config values injected by Handle()

View Source
const KeyUserAdminURL = "user_admin_url"
View Source
const KeyUserHomeURL = "user_home_url"
View Source
const VueLoaderJS = `` /* 479-byte string literal not displayed */

VueLoaderJS is a JavaScript snippet that defines loadVueIfNeeded(). It checks whether Vue is already loaded (e.g. by the layout) and, if not, loads it from the CDN dynamically before invoking the callback.

Every controller that needs Vue includes this snippet once (via the layout or directly). Component JS files then wrap their mount call in:

loadVueIfNeeded((err) => {
  if (err) { console.error('Vue load failed:', err); return; }
  const { createApp } = Vue;
  const el = document.getElementById('my-app');
  if (el) createApp(MyApp).mount('#my-app');
});

This avoids double-loading Vue when the layout already provides it.

Variables

This section is empty.

Functions

func AdminHomeURL

func AdminHomeURL(r *http.Request) string

AdminHomeURL returns the admin home URL from request context

func Breadcrumbs(breadcrumbs []Breadcrumb) hb.TagInterface

Breadcrumbs renders a breadcrumb navigation from the given items

func Endpoint

func Endpoint(r *http.Request) string

Endpoint returns the request endpoint URL from context

func ErrorAlert

func ErrorAlert(message string) string

ErrorAlert returns an inline HTML error alert for the given message. This replaces the former ToFlashError flash-message pattern, which required a cache store and a /flash route handler that did not exist in the standalone module.

func ErrorPopup

func ErrorPopup(errorMessage string) hb.TagInterface

ErrorPopup returns a SweetAlert2 error popup tag.

func FlashError

func FlashError(flashRedirect FlashRedirectFunc, w http.ResponseWriter, r *http.Request, message, redirectURL string, seconds int) string

FlashError performs a flash redirect for an error message. If flashRedirect is nil, it falls back to a plain http.Redirect.

func FlashSuccess

func FlashSuccess(flashRedirect FlashRedirectFunc, w http.ResponseWriter, r *http.Request, message, redirectURL string, seconds int) string

FlashSuccess performs a flash redirect for a success message. If flashRedirect is nil, it falls back to a plain http.Redirect.

func JSEscapeString

func JSEscapeString(s string) string

JSEscapeString escapes a string for safe embedding inside a JavaScript single-quoted string literal. It escapes backslash, single quote, and newlines so that user-supplied values (e.g. user IDs from URL params) cannot break out of the string context.

func Layout

func Layout(w http.ResponseWriter, r *http.Request, webpageTitle, webpageHtml string, options struct {
	Styles     []string
	StyleURLs  []string
	Scripts    []string
	ScriptURLs []string
}) string

Layout is the default layout renderer. It builds a complete HTML page using hb.NewWebpage() with Bootstrap + Vue CDN, matching the blogadmin/shopadmin pattern. If a FuncLayout is provided in AdminOptions, it takes precedence over this default.

func SuccessPopup

func SuccessPopup(successMessage string) hb.TagInterface

SuccessPopup returns a SweetAlert2 success popup tag.

func SuccessPopupWithRedirect

func SuccessPopupWithRedirect(successMessage string, redirectUrl string, redirectSeconds int) hb.TagInterface

SuccessPopupWithRedirect returns a SweetAlert2 success popup with an optional redirect. If redirectUrl is empty, no redirect is configured.

func URL

func URL(endpoint string, controller string, params map[string]string) string

URL builds a URL for the given endpoint and controller with params. The controller is placed in the params map under the "controller" key. The params map is copied before mutation (does not modify caller's map).

func URLR

func URLR(r *http.Request, controller string, params map[string]string) string

URLR builds a URL using the endpoint from the request context.

func UserAdminURL

func UserAdminURL(r *http.Request) string

UserAdminURL returns the user admin base URL from request context

func UserHomeURL

func UserHomeURL(r *http.Request) string

UserHomeURL returns the user home URL from request context. Used by the impersonate controller to redirect after a successful impersonation.

func VueLoaderScript

func VueLoaderScript() hb.TagInterface

VueLoaderScript returns the loadVueIfNeeded definition as an hb.Tag so controllers can inject it into their container divs. This ensures the guard is available even when a host project provides a custom FuncLayout that does not include VueLoaderJS.

Types

type Breadcrumb struct {
	Name string
	URL  string
}

Breadcrumb represents a single breadcrumb navigation item

type FlashRedirectFunc

type FlashRedirectFunc func(w http.ResponseWriter, r *http.Request, messageType, message, redirectURL string, seconds int) string

FlashRedirectFunc redirects the user with a flash message. Host projects that have a flash-message system (cache store + /flash route) provide this callback so useradmin can surface messages across redirects. If nil, useradmin falls back to a plain http.Redirect and the message is dropped.

messageType is one of "error", "success", "info", "warning".

type Links struct {
	// contains filtered or unexported fields
}

Links provides URL helpers for useradmin controllers. The base URL is read from request context (injected by Handle()), not hardcoded. This follows the blogadmin/shopadmin pattern.

func NewLinks(baseURL string) *Links

NewLinks creates a Links helper with the given base URL. If baseURL is empty, defaults to "/admin/users".

func NewLinksFromRequest

func NewLinksFromRequest(r *http.Request) *Links

NewLinksFromRequest creates a Links helper using the user admin URL from the request context.

func (*Links) Home

func (l *Links) Home(params map[string]string) string

Home builds the URL for the user manager controller (default)

func (*Links) UserCreate

func (l *Links) UserCreate(params map[string]string) string

UserCreate builds the URL for the user create controller

func (*Links) UserDelete

func (l *Links) UserDelete(params map[string]string) string

UserDelete builds the URL for the user delete controller

func (*Links) UserImpersonate

func (l *Links) UserImpersonate(params map[string]string) string

UserImpersonate builds the URL for the user impersonate controller

func (*Links) UserManager

func (l *Links) UserManager(params map[string]string) string

UserManager builds the URL for the user manager controller

func (*Links) UserUpdate

func (l *Links) UserUpdate(params map[string]string) string

UserUpdate builds the URL for the user update controller

type UiBase

type UiBase struct {
	UserStoreField                  userstore.StoreInterface
	GeoStoreField                   geostore.StoreInterface
	LoggerField                     *slog.Logger
	SessionStoreField               sessionstore.StoreInterface
	BlindIndexFirstNameField        blindindexstore.StoreInterface
	BlindIndexLastNameField         blindindexstore.StoreInterface
	BlindIndexEmailField            blindindexstore.StoreInterface
	TaskStoreField                  taskstore.StoreInterface
	BlindIndexRebuildTaskAliasField string
	VaultTokenizerField             VaultTokenizer
	AuthUserField                   func(r *http.Request) userstore.UserInterface
	FlashRedirectField              FlashRedirectFunc
	SecureCookieField               bool
	LayoutField                     func(w http.ResponseWriter, r *http.Request, webpageTitle, webpageHtml string, options struct {
		Styles     []string
		StyleURLs  []string
		Scripts    []string
		ScriptURLs []string
	}) string
}

UiBase is a base struct that implements shared.UiInterface. Subcontroller ui structs can embed this to get all the accessor methods for free, following the blogadmin/shopadmin pattern.

func NewUiBase

func NewUiBase(config UiConfig) UiBase

NewUiBase creates a UiBase from a UiConfig

func (UiBase) AuthUser

func (u UiBase) AuthUser(r *http.Request) userstore.UserInterface

func (UiBase) BlindIndexEmail

func (u UiBase) BlindIndexEmail() blindindexstore.StoreInterface

func (UiBase) BlindIndexFirstName

func (u UiBase) BlindIndexFirstName() blindindexstore.StoreInterface

func (UiBase) BlindIndexLastName

func (u UiBase) BlindIndexLastName() blindindexstore.StoreInterface

func (UiBase) BlindIndexRebuildTaskAlias

func (u UiBase) BlindIndexRebuildTaskAlias() string

func (UiBase) FlashRedirect

func (u UiBase) FlashRedirect() FlashRedirectFunc

func (UiBase) GeoStore

func (u UiBase) GeoStore() geostore.StoreInterface

func (UiBase) Layout

func (u UiBase) Layout(w http.ResponseWriter, r *http.Request, webpageTitle, webpageHtml string, options struct {
	Styles     []string
	StyleURLs  []string
	Scripts    []string
	ScriptURLs []string
}) string

func (UiBase) Logger

func (u UiBase) Logger() *slog.Logger

func (UiBase) SecureCookie

func (u UiBase) SecureCookie() bool

func (UiBase) SessionStore

func (u UiBase) SessionStore() sessionstore.StoreInterface

func (UiBase) TaskStore

func (u UiBase) TaskStore() taskstore.StoreInterface

func (UiBase) UserStore

func (u UiBase) UserStore() userstore.StoreInterface

func (UiBase) VaultTokenizer

func (u UiBase) VaultTokenizer() VaultTokenizer

type UiConfig

type UiConfig struct {
	UserStore userstore.StoreInterface
	GeoStore  geostore.StoreInterface
	Logger    *slog.Logger

	// SessionStore is required for the impersonate controller.
	SessionStore sessionstore.StoreInterface

	// BlindIndexFirstName/LastName/Email enable filtered search by
	// the corresponding field. Optional.
	BlindIndexFirstName blindindexstore.StoreInterface
	BlindIndexLastName  blindindexstore.StoreInterface
	BlindIndexEmail     blindindexstore.StoreInterface

	// TaskStore is used to enqueue a blind index rebuild when a user's
	// email changes and vault tokenization is enabled. Optional.
	TaskStore taskstore.StoreInterface

	// BlindIndexRebuildTaskAlias is the task alias enqueued on email
	// change. If empty, the enqueue is skipped.
	BlindIndexRebuildTaskAlias string

	// VaultTokenizer abstracts vault tokenization. Optional — when
	// nil, user fields are treated as plain text.
	VaultTokenizer VaultTokenizer

	// AuthUser returns the authenticated user from the request, or
	// nil if unauthenticated. Used by the create/delete/impersonate
	// controllers for authorization checks.
	AuthUser func(r *http.Request) userstore.UserInterface

	// FlashRedirect redirects with a flash message. Optional — when
	// nil, plain http.Redirect is used.
	FlashRedirect FlashRedirectFunc

	// SecureCookie controls whether the impersonation cookie is marked
	// Secure. Set to false for HTTP (development), true for HTTPS
	// (production). Defaults to true.
	SecureCookie bool

	// Layout is the layout renderer callback.
	Layout func(w http.ResponseWriter, r *http.Request, webpageTitle, webpageHtml string, options struct {
		Styles     []string
		StyleURLs  []string
		Scripts    []string
		ScriptURLs []string
	}) string
}

UiConfig holds the dependencies passed to subcontroller UI factories. This follows the blogadmin/shopadmin pattern.

UserStore, GeoStore, and Logger are required for core controllers. SessionStore is required for the impersonate controller. The blind index stores are optional — when nil, the corresponding search filter is disabled. VaultTokenizer is optional — when nil, user fields are treated as plain text. TaskStore is optional — when nil, blind index rebuild enqueue on email change is skipped.

type UiInterface

type UiInterface interface {
	UserStore() userstore.StoreInterface
	GeoStore() geostore.StoreInterface
	Logger() *slog.Logger
	SessionStore() sessionstore.StoreInterface
	BlindIndexFirstName() blindindexstore.StoreInterface
	BlindIndexLastName() blindindexstore.StoreInterface
	BlindIndexEmail() blindindexstore.StoreInterface
	TaskStore() taskstore.StoreInterface
	BlindIndexRebuildTaskAlias() string
	VaultTokenizer() VaultTokenizer
	AuthUser(r *http.Request) userstore.UserInterface
	FlashRedirect() FlashRedirectFunc
	SecureCookie() bool

	Layout(w http.ResponseWriter, r *http.Request, webpageTitle, webpageHtml string, options struct {
		Styles     []string
		StyleURLs  []string
		Scripts    []string
		ScriptURLs []string
	}) string
}

UiInterface defines the methods every subcontroller UI must implement. This follows the blogadmin/shopadmin pattern.

type VaultTokenizer

type VaultTokenizer interface {
	// Tokenize upserts tokens for the given user fields and returns
	// the resulting token strings to store on the user record.
	Tokenize(
		ctx context.Context,
		user userstore.UserInterface,
		firstName, lastName, email, phone, businessName string,
	) (firstNameToken, lastNameToken, emailToken, phoneToken, businessNameToken string, err error)

	// Untokenize resolves the tokenized fields on the given user back
	// to their plain-text values.
	Untokenize(
		ctx context.Context,
		user userstore.UserInterface,
	) (firstName, lastName, email, phone, businessName string, err error)
}

VaultTokenizer abstracts vault tokenization/untokenization of user fields (first name, last name, email, phone, business name).

Host projects that use a vault store provide an implementation so useradmin can read and write tokenized user data without depending on any specific vault config or key management. If nil, useradmin treats user fields as plain text.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL