got most of the login functionality together

This commit is contained in:
2025-09-27 23:07:16 -06:00
parent 03f1d9f717
commit 9427535eb5
8 changed files with 283 additions and 5 deletions
+15
View File
@@ -32,7 +32,9 @@ type AmContext interface {
RC() int
OutputType() string
Parameter(string) string
RemoteIP() string
Render(string) error
ReplaceUser(*database.User)
SubRender(string) ([]byte, error)
Session() *sessions.Session
SetOutputType(string)
@@ -121,6 +123,11 @@ func (c *amContext) Parameter(name string) string {
return rc
}
// RemoteIP returns the remote IP address.
func (c *amContext) RemoteIP() string {
return c.echoContext.RealIP()
}
/* Render renders a template to the output. Called at the top level only.
* Parameters:
* name = The name of the tempate to be rendered.
@@ -131,6 +138,14 @@ func (c *amContext) Render(name string) error {
return c.echoContext.Render(c.httprc, name, c)
}
/* ReplaceUser replaces the current user in the context.
* Parameters:
* u - New user to associate with the context.
*/
func (c *amContext) ReplaceUser(u *database.User) {
c.session.Values["user_id"] = u.Uid
}
// Scratchpad returns the per-request scratchpad for values.
func (c *amContext) Scratchpad() map[string]any {
if c.scratchpad == nil {
+14
View File
@@ -124,6 +124,20 @@ func (d *Dialog) Render(ctxt AmContext) (string, any, error) {
return "framed_template", "dialog.jet", nil
}
/* RenderError sets up the rendering parameters to send this dialog to the output with an error message.
* Parameters:
* ctxt - The AmContext for this request.
* errormessage - The error message to be displayed.
* Returns:
* Command string dictating what to be rendered.
* Data as a parameter for the command string.
* Standard Go error status.
*/
func (d *Dialog) RenderError(ctxt AmContext, errormessage string) (string, any, error) {
ctxt.VarMap().Set("amsterdam_errorMessage", errormessage)
return d.Render(ctxt)
}
/* LoadFromForm loads the values in a dialog from the form fields in the request.
* Parameters:
* ctxt - The AmContext for this request.
+24
View File
@@ -21,6 +21,7 @@ import (
"strings"
"sync"
"time"
"unicode"
"git.erbosoft.com/amy/amsterdam/config"
"github.com/CloudyKit/jet/v6"
@@ -36,10 +37,13 @@ var static_views embed.FS
// views is the main Jet template repository.
var views *jet.Set
// cachedCountryList is the cached country list after sorting.
var cachedCountryList []countries.CountryCode = nil
// countryListMutex control access to internalGetCountryList.
var countryListMutex sync.Mutex
// internalGetCountryList is a wrapper around countries.All() that sorts it by country name.
func internalGetCountryList() []countries.CountryCode {
countryListMutex.Lock()
defer countryListMutex.Unlock()
@@ -126,6 +130,21 @@ func makeYearRange(a jet.Arguments) reflect.Value {
}
}
/* CapitalizeString changes the first character of trhe string to a capital.
* Parameters:
* s - The string to be capitalized.
* Returns:
* The capitalized string.
*/
func CapitalizeString(s string) string {
runes := []rune(s)
if len(runes) > 0 {
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}
return ""
}
// SetupTemplates is called to set up the template renderer after the configuration is loaded.
func SetupTemplates() {
views = jet.NewSet(
@@ -143,6 +162,11 @@ func SetupTemplates() {
views.AddGlobalFunc("MakeIntRange", makeIntRange)
views.AddGlobalFunc("MakeYearRange", makeYearRange)
views.AddGlobalFunc("CapitalizeString", func(a jet.Arguments) reflect.Value {
s := a.Get(0).Convert(reflect.TypeFor[string]()).String()
return reflect.ValueOf(CapitalizeString(s))
})
// preload the country list in the background
go internalGetCountryList()
}
+14
View File
@@ -25,6 +25,20 @@
<p class="text-black text-sm mb-6">Required fields are marked with a <span class="text-red-600">*</span>.</p>
{{ end }}
{{ if isset(amsterdam_errorMessage) }}
<!-- Error Message Banner -->
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6 hidden" id="error-banner">
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-red-500 text-xl">⚠️</span>
</div>
<div class="ml-3">
<p class="text-sm font-medium" id="error-message">{{ CapitalizeString(amsterdam_errorMessage) }}.</p>
</div>
</div>
</div>
{{ end }}
<div class="bg-gray-50 p-6 rounded-lg">
<div class="space-y-4">
{{ range amsterdam_dialog.Fields }}
+1 -1
View File
@@ -12,7 +12,7 @@
<h1 class="text-blue-800 text-4xl font-bold mb-2">Amsterdam Internal Server Error</h1>
<hr class="border-2 border-gray-400 w-4/5 mb-4">
<p class="text-black text-sm mb-4">
The Amsterdam server encountered an error: {{ error }}
The Amsterdam server encountered an error: {{ CapitalizeString(error) }}.
</p>
<p class="text-black text-sm mb-4">
<a href="/">Click here</a> to return to the home page.