From 03f1d9f7176e21835b75b4b059bca5dac929c964 Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Sat, 27 Sep 2025 17:39:32 -0600 Subject: [PATCH] debugged form loading and got part of the Login code in --- login.go | 36 +++++++++++++++++--- main.go | 1 + ui/amcontext.go | 17 +++++++++- ui/dialog.go | 67 +++++++++++++++++++++++++++----------- ui/dialogs/login.yaml | 2 +- ui/dialogs/newaccount.yaml | 2 +- 6 files changed, 99 insertions(+), 26 deletions(-) diff --git a/login.go b/login.go index 66282d0..6bd90b7 100644 --- a/login.go +++ b/login.go @@ -38,12 +38,41 @@ func LoginForm(ctxt ui.AmContext) (string, any, error) { dlg, err := ui.AmLoadDialog("login") if err == nil { dlg.Field("tgt").Value = target - ctxt.VarMap().Set("amsterdam_pageTitle", "Log In") return dlg.Render(ctxt) } return ui.ErrorPage(ctxt, err) } +/* Login handles logging in to Amsterdam. + * Parameters: + * ctxt - The AmContext for the request. + * Returns: + * Command string dictating what to be rendered. + * Data as a parameter for the command string. + * Standard Go error status. + */ +func Login(ctxt ui.AmContext) (string, any, error) { + dlg, err := ui.AmLoadDialog("login") + if err == nil { + dlg.LoadFromForm(ctxt) + target := dlg.Field("tgt").Value + if target == "" { + target = "/" + } + + action := dlg.WhichButton(ctxt) + if action == "cancel" { + return "redirect", target, nil + } + if action == "remind" { + // TODO: send password reminder + return dlg.Render(ctxt) + } + + } + return ui.ErrorPage(ctxt, err) +} + /* NewAccountUserAgreement renders the Amsterdam user agreement for new accounts. * Parameters: * ctxt - The AmContext for the request. @@ -61,7 +90,7 @@ func NewAccountUserAgreement(ctxt ui.AmContext) (string, any, error) { // If user is already logged in, this is an error. if !ctxt.CurrentUser().IsAnon { - return ui.ErrorPage(ctxt, fmt.Errorf("You cannot create a bew account while logged in on an existing one. You must log out first.")) + return ui.ErrorPage(ctxt, fmt.Errorf("You cannot create a new account while logged in on an existing one. You must log out first.")) } ctxt.VarMap().Set("target", target) @@ -86,14 +115,13 @@ func NewAccountForm(ctxt ui.AmContext) (string, any, error) { // If user is already logged in, this is an error. if !ctxt.CurrentUser().IsAnon { - return ui.ErrorPage(ctxt, fmt.Errorf("You cannot create a bew account while logged in on an existing one. You must log out first.")) + return ui.ErrorPage(ctxt, fmt.Errorf("You cannot create a new account while logged in on an existing one. You must log out first.")) } dlg, err := ui.AmLoadDialog("newaccount") if err == nil { dlg.Field("tgt").Value = target dlg.Field("country").Value = "XX" - ctxt.VarMap().Set("amsterdam_pageTitle", "Create New Account") return dlg.Render(ctxt) } return ui.ErrorPage(ctxt, err) diff --git a/main.go b/main.go index 8ecc6ed..9a21210 100644 --- a/main.go +++ b/main.go @@ -43,6 +43,7 @@ func setupEcho() *echo.Echo { e.GET("/", ui.AmWrap(TopPage)) e.GET("/about", ui.AmWrap(AboutPage)) e.GET("/login", ui.AmWrap(LoginForm)) + e.POST("/login", ui.AmWrap(Login)) e.GET("/newacct", ui.AmWrap(NewAccountUserAgreement)) e.GET("/newacct2", ui.AmWrap(NewAccountForm)) diff --git a/ui/amcontext.go b/ui/amcontext.go index a734187..516e91a 100644 --- a/ui/amcontext.go +++ b/ui/amcontext.go @@ -28,6 +28,7 @@ type AmContext interface { CurrentUser() *database.User FormField(string) string FormFieldInt(string) (int, error) + FormFieldIsSet(string) bool RC() int OutputType() string Parameter(string) string @@ -71,7 +72,7 @@ func (c *amContext) FormField(name string) string { return c.echoContext.FormValue(name) } -/* FormField returns the value of a form field from the request, as an integer. +/* FormFieldInt returns the value of a form field from the request, as an integer. * Parameters: * name - The name of the field to retrieve. * Returns: @@ -82,6 +83,20 @@ func (c *amContext) FormFieldInt(name string) (int, error) { return strconv.Atoi(c.echoContext.FormValue(name)) } +/* FormFieldIsSet returns true if a given form field is set. + * Parameters: + * name - The name of the field to test. + * Returns: + * true if the field is set, false if not. + */ +func (c *amContext) FormFieldIsSet(name string) bool { + req := c.echoContext.Request() + if req.Form == nil { + _ = req.FormValue(name) // force form to be loaded + } + return req.Form.Has(name) +} + // RC returns the HTTP result code for the current operation. func (c *amContext) RC() int { return c.httprc diff --git a/ui/dialog.go b/ui/dialog.go index 8a6b3a9..0b3672a 100644 --- a/ui/dialog.go +++ b/ui/dialog.go @@ -61,12 +61,12 @@ func AmLoadDialog(name string) (*Dialog, error) { if d.MenuSelector == "" { d.MenuSelector = "nochange" } - for _, fld := range d.Fields { + for i, fld := range d.Fields { if fld.Type == "button" && fld.Param == "" { - fld.Param = "blue" + d.Fields[i].Param = "blue" } if fld.Type == "date" && fld.Param == "" { - fld.Param = "year:-100" + d.Fields[i].Param = "year:-100" } } return &d, nil @@ -94,8 +94,8 @@ func (fld *DialogItem) DateValues() []int { * Pointer to the field, or nil. */ func (d *Dialog) Field(name string) *DialogItem { - for i := 0; i < len(d.Fields); i++ { - if d.Fields[i].Name == name { + for i, f := range d.Fields { + if f.Name == name { return &(d.Fields[i]) } } @@ -120,6 +120,7 @@ func (d *Dialog) Render(ctxt AmContext) (string, any, error) { } ctxt.VarMap().Set("amsterdam_required", required) ctxt.VarMap().Set("amsterdam_dialog", d) + ctxt.VarMap().Set("amsterdam_pageTitle", d.Title) return "framed_template", "dialog.jet", nil } @@ -128,48 +129,76 @@ func (d *Dialog) Render(ctxt AmContext) (string, any, error) { * ctxt - The AmContext for this request. */ func (d *Dialog) LoadFromForm(ctxt AmContext) { - for _, fld := range d.Fields { + for i, fld := range d.Fields { + d.Fields[i].Value = "" + if fld.Type == "header" || fld.Type == "button" { + continue + } if fld.Type == "date" { - fld.Value = "" + d.Fields[i].Value = "" dvals := make([]int, 3) var err error dvals[0], err = ctxt.FormFieldInt(fmt.Sprintf("%s_month", fld.Name)) if err != nil { dvals[0] = -1 - fld.Value = fmt.Sprintf("!undefined month %s: %v", fld.Name, err) + d.Fields[i].Value = fmt.Sprintf("!undefined month %s: %v", fld.Name, err) } dvals[1], err = ctxt.FormFieldInt(fmt.Sprintf("%s_day", fld.Name)) if err != nil { dvals[1] = -1 - if fld.Value == "" { - fld.Value = fmt.Sprintf("!undefined day %s: %v", fld.Name, err) + if d.Fields[i].Value == "" { + d.Fields[i].Value = fmt.Sprintf("!undefined day %s: %v", fld.Name, err) } } dvals[2], err = ctxt.FormFieldInt(fmt.Sprintf("%s_year", fld.Name)) if err != nil { dvals[2] = -1 - if fld.Value == "" { - fld.Value = fmt.Sprintf("!undefined year %s: %v", fld.Name, err) + if d.Fields[i].Value == "" { + d.Fields[i].Value = fmt.Sprintf("!undefined year %s: %v", fld.Name, err) } } if dvals[0] > 0 && dvals[1] > 0 && dvals[2] > 0 { - fld.Value = fmt.Sprintf("%04d%02d%02d", dvals[2], dvals[0], dvals[1]) - } else if fld.Value == "" && fld.Required { + d.Fields[i].Value = fmt.Sprintf("%04d%02d%02d", dvals[2], dvals[0], dvals[1]) + } else if d.Fields[i].Value == "" && fld.Required { if dvals[0] <= 0 { - fld.Value = fmt.Sprintf("!month not set %s", fld.Name) + d.Fields[i].Value = fmt.Sprintf("!month not set %s", fld.Name) } else if dvals[1] <= 0 { - fld.Value = fmt.Sprintf("!day not set %s", fld.Name) + d.Fields[i].Value = fmt.Sprintf("!day not set %s", fld.Name) } else if dvals[2] <= 0 { - fld.Value = fmt.Sprintf("!year not set %s", fld.Name) + d.Fields[i].Value = fmt.Sprintf("!year not set %s", fld.Name) } } - fld.AuxData = dvals + d.Fields[i].AuxData = dvals } else { - fld.Value = ctxt.FormField(fld.Name) + d.Fields[i].Value = ctxt.FormField(fld.Name) } } } +// Values returns all a dialog's values as a map. +func (d *Dialog) Values() map[string]string { + rc := map[string]string{} + for _, fld := range d.Fields { + rc[fld.Name] = fld.Value + } + return rc +} + +/* WhichButton returns an indication of which button on the dialog was clicked. + * Parameters: + * ctxt - The AmContext associated with the request. + * Returns: + * The name of the button field on this dialog that was clicked. If none were, the empty string is returned. + */ +func (d *Dialog) WhichButton(ctxt AmContext) string { + for _, fld := range d.Fields { + if fld.Type == "button" && ctxt.FormFieldIsSet(fld.Name) { + return fld.Name + } + } + return "" +} + // validatorFunc is a function that validates the contents of a dialog item. type validatorFunc func(*DialogItem) error diff --git a/ui/dialogs/login.yaml b/ui/dialogs/login.yaml index 29c99f8..41a7d93 100644 --- a/ui/dialogs/login.yaml +++ b/ui/dialogs/login.yaml @@ -10,7 +10,7 @@ name: "login" formName: "loginform" menuSelector: "top" title: "Log In" -action: "/TODO/login" +action: "/login" instructions: > Forgot your password? Enter your user name and click the Reminder button to receive a password reminder via E-mail. diff --git a/ui/dialogs/newaccount.yaml b/ui/dialogs/newaccount.yaml index 7755fe1..4a0772e 100644 --- a/ui/dialogs/newaccount.yaml +++ b/ui/dialogs/newaccount.yaml @@ -9,7 +9,7 @@ name: "newaccount" formName: "createform" menuSelector: "top" -title: "Create Account" +title: "Create New Account" action: "/TODO/newacct2" instructions: > To create a new account, please enter your information below.