From d28f02f8d657d682ff2d859f964b650a29eb2e9f Mon Sep 17 00:00:00 2001 From: mikestefanello Date: Sat, 18 Dec 2021 16:55:35 -0500 Subject: [PATCH] Moved pager to the controller package. Added additional documentation. --- Makefile | 5 ++ context/context.go | 13 +++- controller/controller.go | 8 ++- controller/page.go | 120 ++++++++++++++++++++++++--------- {pager => controller}/pager.go | 11 ++- 5 files changed, 117 insertions(+), 40 deletions(-) rename {pager => controller}/pager.go (79%) diff --git a/Makefile b/Makefile index e734ec9..f76da19 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,11 @@ up: docker-compose up -d sleep 3 +.PHONY: reset +reset: + docker-compose down + make up + .PHONY: run run: clear diff --git a/context/context.go b/context/context.go index 92a3b96..177bf30 100644 --- a/context/context.go +++ b/context/context.go @@ -1,8 +1,15 @@ package context const ( + // AuthenticatedUserKey is the key value used to store the authenticated user in context AuthenticatedUserKey = "auth_user" - UserKey = "user" - FormKey = "form" - PasswordTokenKey = "password_token" + + // UserKey is the key value used to store a user in context + UserKey = "user" + + // FormKey is the key value used to store a form in context + FormKey = "form" + + // PasswordTokenKey is the key value used to store a password token in context + PasswordTokenKey = "password_token" ) diff --git a/controller/controller.go b/controller/controller.go index e2937ff..8d2b016 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -27,12 +27,13 @@ import ( ) var ( - // Cache of compiled page templates + // templates stores a cache of parsed page templates templates = sync.Map{} - // Template function map + // funcMap stores the Template function map funcMap = funcmap.GetFuncMap() + // templatePath stores the complete path to the templates directory templatePath = getTemplatesDirectoryPath() ) @@ -170,6 +171,7 @@ func (t *Controller) SetValidationErrorMessages(c echo.Context, err error, data } // Provide better error messages depending on the failed validation tag + // This should be expanded as you use additional tags in your validation switch ve.Tag() { case "required": message = "%s is required." @@ -187,7 +189,7 @@ func (t *Controller) SetValidationErrorMessages(c echo.Context, err error, data // getTemplatesDirectoryPath gets the templates directory path // This is needed incase this is called from a package outside of main, -// such as testing +// such as within tests func getTemplatesDirectoryPath() string { _, b, _, _ := runtime.Caller(0) d := path.Join(path.Dir(b)) diff --git a/controller/page.go b/controller/page.go index ed89a40..ed388dc 100644 --- a/controller/page.go +++ b/controller/page.go @@ -7,51 +7,112 @@ import ( "goweb/context" "goweb/msg" - "goweb/pager" echomw "github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4" ) -const ( - DefaultItemsPerPage = 20 -) - +// Page consists of all data that will be used to render a page response for a given controller. +// While it's not required for a controller to render a Page on a route, this is the common data +// object that will be passed to the templates, making it easy for all controllers to share +// functionality both on the back and frontend. The Page can be expanded to include anything else +// your app wants to support. +// Methods on this page also then become available in the templates, which can be more useful than +// the funcmap if your methods require data stored in the page, such as the context. type Page struct { - AppName string - Title string - Context echo.Context - Reverse func(name string, params ...interface{}) string - Path string - Data interface{} - Layout string - Name string - IsHome bool - IsAuth bool + // AppName stores the name of the application. + // If omitted, the configuration value will be used. + AppName string + + // Title stores the title of the page + Title string + + // Context stores the request context + Context echo.Context + + // ToURL is a function to convert a route name and optional route parameters to a URL + ToURL func(name string, params ...interface{}) string + + // Path stores the path of the current request + Path string + + // URL stores the URL of the current request + URL string + + // Data stores whatever additional data that needs to be passed to the templates. + // This is what the controller uses to pass the content of the page. + Data interface{} + + // Layout stores the name of the layout base template file which will be used when the page is rendered. + // This should match a template file located within the layouts directory inside the templates directory. + // The template extension should not be included in this value. + Layout string + + // Name stores the name of the page as well as the name of the template file which will be used to render + // the content portion of the layout template. + // This should match a template file located within the pages directory inside the templates directory. + // The template extension should not be included in this value. + Name string + + // IsHome stores whether the requested page is the home page or not + IsHome bool + + // IsAuth stores whether or not the user is authenticated + IsAuth bool + + // StatusCode stores the HTTP status code that will be returned StatusCode int - Metatags struct { + + // Metatags stores metatag values + Metatags struct { + // Description stores the description metatag value Description string - Keywords []string + + // Keywords stores the keywords metatag values + Keywords []string } - Pager pager.Pager - CSRF string + + // Pager stores a pager which can be used to page lists of results + Pager Pager + + // CSRF stores the CSRF token for the given request. + // This will only be populated if the CSRF middleware is in effect for the given request. + // If this is populated, all forms must include this value otherwise the requests will be rejected. + CSRF string + + // Headers stores a list of HTTP headers and values to be set on the response Headers map[string]string - Cache struct { - Enabled bool - Expiration time.Duration - Tags []string - } + + // RequestID stores the ID of the given request. + // This will only be populated if the request ID middleware is in effect for the given request. RequestID string + + // Cache stores values for caching the response of this page + Cache struct { + // Enabled dictates if the response of this page should be cached. + // Cached responses are served via middleware. + Enabled bool + + // Expiration stores the amount of time that the cache entry should live for before expiring. + // If omitted, the configuration value will be used. + Expiration time.Duration + + // Tags stores a list of tags to apply to the cache entry. + // These are useful when invalidating cache for dynamic events such as entity operations. + Tags []string + } } +// NewPage creates and initiatizes a new page for a given request context func NewPage(c echo.Context) Page { p := Page{ Context: c, - Reverse: c.Echo().Reverse, + ToURL: c.Echo().Reverse, Path: c.Request().URL.Path, + URL: c.Request().URL.String(), StatusCode: http.StatusOK, - Pager: pager.NewPager(c, DefaultItemsPerPage), + Pager: NewPager(c), Headers: make(map[string]string), RequestID: c.Response().Header().Get(echo.HeaderXRequestID), } @@ -62,7 +123,6 @@ func NewPage(c echo.Context) Page { p.CSRF = csrf.(string) } - // TODO: Use container? if u := c.Get(context.AuthenticatedUserKey); u != nil { p.IsAuth = true } @@ -70,10 +130,8 @@ func NewPage(c echo.Context) Page { return p } -func (p Page) SetMessage(typ msg.Type, value string) { - msg.Set(p.Context, typ, value) -} - +// GetMessages gets all flash messages for a given type. +// This allows for easy access to flash messages from the templates. func (p Page) GetMessages(typ msg.Type) []template.HTML { strs := msg.Get(p.Context, typ) ret := make([]template.HTML, len(strs)) diff --git a/pager/pager.go b/controller/pager.go similarity index 79% rename from pager/pager.go rename to controller/pager.go index d9b87ef..7e0158c 100644 --- a/pager/pager.go +++ b/controller/pager.go @@ -1,4 +1,4 @@ -package pager +package controller import ( "math" @@ -7,6 +7,11 @@ import ( "github.com/labstack/echo/v4" ) +const ( + // DefaultItemsPerPage stores the default amount of items per page + DefaultItemsPerPage = 20 +) + type Pager struct { Items int Page int @@ -14,9 +19,9 @@ type Pager struct { Pages int } -func NewPager(c echo.Context, itemsPerPage int) Pager { +func NewPager(c echo.Context) Pager { p := Pager{ - ItemsPerPage: itemsPerPage, + ItemsPerPage: DefaultItemsPerPage, Page: 1, }