feat: middleware to return error as html

This commit is contained in:
efim
2023-10-09 07:45:29 +00:00
parent ec47c9d610
commit 8842235372
8 changed files with 202 additions and 73 deletions

View File

@@ -6,6 +6,7 @@ import (
"html/template"
"math/rand"
"net/http"
"strconv"
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
@@ -21,7 +22,8 @@ var staticFilesFS embed.FS
func AddPageRoutes(app *pocketbase.PocketBase) {
app.OnBeforeServe().Add(getIndexPageRoute(app))
app.OnBeforeServe().Add(somePageRoute)
app.OnBeforeServe().Add(getSomePageRoute(app))
app.OnBeforeServe().Add(getErrorPageRoute(app))
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.StaticFS("/static", staticFilesFS)
@@ -41,40 +43,13 @@ func getIndexPageRoute(app *pocketbase.PocketBase) func(*core.ServeEvent) error
return func(e *core.ServeEvent) error {
e.Router.GET("/", func(c echo.Context) error {
// first collect data
info := apis.RequestInfo(c)
admin := info.Admin // nil if not authenticated as admin
record := info.AuthRecord // nil if not authenticated as regular auth record
isGuest := admin == nil && record == nil
username := ""
switch {
case admin != nil:
username = admin.Email
case record != nil:
username = record.Username()
}
oauthProviders := app.Settings().NamedAuthProviderConfigs()
oauthProviderNames := make([]string, 0, len(oauthProviders))
for name, config := range oauthProviders {
if config.Enabled {
oauthProviderNames = append(oauthProviderNames, name)
}
}
navInfoData := initNavInfoData(app, c)
indexPageData := struct {
IsGuest, IsAdmin bool
Username string
EnabledOauthProviders []string
NavInfo navInfo
BackendMessage string
NavInfo navInfo
}{
IsAdmin: admin != nil,
NavInfo: navInfo{
IsGuest: isGuest,
Username: username,
EnabledOauthProviders: oauthProviderNames,
},
BackendMessage: "Hello from the backend!",
NavInfo: navInfoData,
}
// then render template with it
@@ -101,44 +76,112 @@ func stringWithCharset(length int, charset string) string {
}
return string(b)
}
func somePageRoute(e *core.ServeEvent) error {
e.Router.GET("/somepage", func(c echo.Context) error {
// get data
// and since i'm using 'base.gohtml' with Nav, i'll need Nav info
func getSomePageRoute(app *pocketbase.PocketBase) func(*core.ServeEvent) error {
return func(e *core.ServeEvent) error {
e.Router.GET("/somepage", func(c echo.Context) error {
// get data
// and since i'm using 'base.gohtml' with Nav, i'll need Nav info
navInfoData := initNavInfoData(app, c)
info := apis.RequestInfo(c)
admin := info.Admin // nil if not authenticated as admin
record := info.AuthRecord // nil if not authenticated as regular auth record
somePageData := struct {
RandomNumber int
RandomString string
NavInfo navInfo
}{
RandomNumber: rand.Int(),
RandomString: stringWithCharset(25, charset),
NavInfo: navInfoData,
}
username := ""
switch {
case admin != nil:
username = admin.Email
case record != nil:
username = record.Username()
}
// then render template with it
templateName := "templates/somepage.gohtml"
tmpl := template.Must(template.ParseFS(templatesFS, "templates/base.gohtml", templateName))
var instantiatedTemplate bytes.Buffer
if err := tmpl.Execute(&instantiatedTemplate, somePageData); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"message": "error parsing template"})
}
somePageData := struct {
RandomNumber int
RandomString string
NavInfo navInfo
}{
RandomNumber: rand.Int(),
RandomString: stringWithCharset(25, charset),
NavInfo: navInfo{
Username: username,
},
}
// then render template with it
templateName := "templates/somepage.gohtml"
tmpl := template.Must(template.ParseFS(templatesFS, "templates/base.gohtml", templateName))
var instantiatedTemplate bytes.Buffer
if err := tmpl.Execute(&instantiatedTemplate, somePageData); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"message": "error parsing template"})
}
return c.HTML(http.StatusOK, instantiatedTemplate.String())
}, apis.RequireAdminOrRecordAuth())
return nil
return c.HTML(http.StatusOK, instantiatedTemplate.String())
}, apis.RequireAdminOrRecordAuth())
return nil
}
}
func getErrorPageRoute(app *pocketbase.PocketBase) func(*core.ServeEvent) error {
return func(e *core.ServeEvent) error {
e.Router.GET("/error/:code", func(c echo.Context) error {
// get data
code := c.PathParam("code")
codeNum, err := strconv.ParseInt(code, 10, 64)
if err != nil {
codeNum = 500
}
errorText := http.StatusText(int(codeNum))
if errorText == "" {
codeNum = 500
errorText = http.StatusText(500)
}
// and since i'm using 'base.gohtml' with Nav, i'll need Nav info
navInfoData := initNavInfoData(app, c)
somePageData := struct {
NavInfo navInfo
ErrorCode int64
ErrorText string
}{
NavInfo: navInfoData,
ErrorCode: codeNum,
ErrorText: errorText,
}
// then render template with it
templateName := "templates/errors/error.gohtml"
switch codeNum {
case 404:
templateName = "templates/errors/404.gohtml"
case 401:
templateName = "templates/errors/401.gohtml"
}
tmpl := template.Must(template.ParseFS(templatesFS, "templates/base.gohtml", templateName))
var instantiatedTemplate bytes.Buffer
if err := tmpl.Execute(&instantiatedTemplate, somePageData); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"message": "error parsing template"})
}
return c.HTML(int(codeNum), instantiatedTemplate.String())
})
return nil
}
}
func initNavInfoData(app *pocketbase.PocketBase, c echo.Context) navInfo {
// first collect data
info := apis.RequestInfo(c)
admin := info.Admin // nil if not authenticated as admin
record := info.AuthRecord // nil if not authenticated as regular auth record
isGuest := admin == nil && record == nil
username := ""
switch {
case admin != nil:
username = admin.Email
case record != nil:
username = record.Username()
}
oauthProviders := app.Settings().NamedAuthProviderConfigs()
oauthProviderNames := make([]string, 0, len(oauthProviders))
for name, config := range oauthProviders {
if config.Enabled {
oauthProviderNames = append(oauthProviderNames, name)
}
}
return navInfo{
IsGuest: isGuest,
Username: username,
EnabledOauthProviders: oauthProviderNames,
}
}

View File

@@ -0,0 +1,10 @@
{{ define "title" }}
Not Authorized
{{ end }}
{{ define "main" }}
<main hx-boost="true" class="px-10 pt-10 flex flex-col gap-y-10">
The page you are trying to access requires authorization.
Please log in.
</main>
{{ end }}

View File

@@ -0,0 +1,9 @@
{{ define "title" }}
Page Not Found
{{ end }}
{{ define "main" }}
<main hx-boost="true" class="px-10 pt-10 flex flex-col gap-y-10">
Error 404 means the page was not found
</main>
{{ end }}

View File

@@ -0,0 +1,10 @@
{{ define "title" }}
Error occurred
{{ end }}
{{ define "main" }}
<main hx-boost="true" class="px-10 pt-10 flex flex-col gap-y-10">
<p> Error {{ .ErrorCode }} occurred! </p>
<p> {{ .ErrorText }} </p>
</main>
{{ end }}

View File

@@ -13,6 +13,7 @@
</li>
</ul>
{{ else }}
<p>Rendering this on the backend, passing values from the code: {{ .BackendMessage }}</p>
<p>There will be some content only for authorized users</p>
{{ end }}
</main>