beginnings of the Edit Profile page, dialog field and rendering additions

This commit is contained in:
2025-10-10 21:26:01 -06:00
parent 6cdb0ffacf
commit 6eec9f77d9
8 changed files with 290 additions and 9 deletions
+1
View File
@@ -52,6 +52,7 @@ func setupEcho() *echo.Echo {
e.GET("/verify", ui.AmWrap(VerifyEmailForm))
e.POST("/verify", ui.AmWrap(VerifyEMail))
e.GET("/passrecovery/:uid/:auth", ui.AmWrap(PasswordRecovery))
e.GET("/profile", ui.AmWrap(EditProfileForm))
return e
}
+11 -5
View File
@@ -218,11 +218,12 @@ func (d *Dialog) RenderInfo(ctxt AmContext, infoMessage string) (string, any, er
func (d *Dialog) LoadFromForm(ctxt AmContext) {
for i, fld := range d.Fields {
d.Fields[i].Value = ""
if fld.Type == "header" || fld.Type == "button" {
switch fld.Type {
case "header":
continue
}
if fld.Type == "date" {
d.Fields[i].Value = ""
case "button":
continue
case "date":
dvals := make([]int, 3)
var err error
dvals[0], err = ctxt.FormFieldInt(fmt.Sprintf("%s_month", fld.Name))
@@ -256,7 +257,9 @@ func (d *Dialog) LoadFromForm(ctxt AmContext) {
}
}
d.Fields[i].AuxData = dvals
} else {
case "userphoto":
d.Fields[i].Value = ctxt.FormField(fmt.Sprintf("%s_data", fld.Name))
default:
d.Fields[i].Value = ctxt.FormField(fld.Name)
}
}
@@ -419,8 +422,11 @@ var validators = map[string]validatorFunc{
"header": nilValidator,
"hidden": nilValidator,
"integer": validateIntegerField,
"localelist": nilValidator, // TODO
"password": validateTextField,
"text": validateTextField,
"tzlist": nilValidator, // TODO
"userphoto": nilValidator,
}
/* Validate validates the values in the dialog.
+200
View File
@@ -0,0 +1,200 @@
#
# Amsterdam Web Communities System
# Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
#
name: "profile"
formName: "profform"
menuSelector: "nochange"
title: "Edit Your Profile"
action: "/profile"
fields:
- type: "hidden"
name: "tgt"
value: ""
- type: "header"
name: "header1"
caption: "Name"
subcaption: "To change your password, enter a new password into the fields below."
- type: "password"
name: "pass1"
caption: "Password"
required: true
size: 32
maxlength: 128
- type: "password"
name: "pass2"
caption: "Password"
subcaption: "(retype)"
required: true
size: 32
maxlength: 128
- type: "text"
name: "remind"
caption: "Password reminder phrase"
size: 32
maxlength: 255
- type: "header"
name: "header2"
caption: "Name"
- type: "text"
name: "prefix"
caption: "Prefix"
subcaption: "(Mr., Ms., etc.)"
size: 8
maxlength: 8
- type: "text"
name: "first"
caption: "First Name"
required: true
size: 32
maxlength: 64
- type: "text"
name: "mid"
caption: "Middle Initial"
size: 1
maxlength: 1
- type: "text"
name: "last"
caption: "Last Name"
required: true
size: 32
maxlength: 64
- type: "text"
name: "suffix"
caption: "Suffix"
subcaption: "(Jr., III, etc.)"
size: 8
maxlength: 8
- type: "header"
name: "header3"
caption: "Location"
- type: "text"
name: "company"
caption: "Company"
size: 32
maxlength: 255
- type: "text"
name: "addr1"
caption: "Address"
size: 32
maxlength: 255
- type: "text"
name: "addr2"
caption: "Address"
subcaption: "(line 2)"
size: 32
maxlength: 255
- type: "checkbox"
name: "pvt_addr"
caption: "Hide address in profile"
- type: "text"
name: "loc"
caption: "City"
required: true
size: 32
maxlength: 64
- type: "text"
name: "reg"
caption: "State/Province"
required: true
size: 32
maxlength: 64
- type: "text"
name: "pcode"
caption: "Zip/Postal Code"
required: true
size: 32
maxlength: 64
- type: "countrylist"
name: "country"
caption: "Country"
required: true
- type: "header"
name: "header4"
caption: "Phone Numbers"
- type: "text"
name: "phone"
caption: "Telephone"
size: 32
maxlength: 32
- type: "text"
name: "mobile"
caption: "Mobile/cellphone"
size: 32
maxlength: 32
- type: "checkbox"
name: "pvt_phone"
caption: "Hide phone/mobile numbers in profile"
- type: "text"
name: "fax"
caption: "Fax"
size: 32
maxlength: 32
- type: "checkbox"
name: "pvt_fax"
caption: "Hide fax number in profile"
- type: "header"
name: "header5"
caption: "Internet"
- type: "email"
name: "email"
caption: "E-Mail Address"
required: true
size: 32
maxlength: 255
- type: "checkbox"
name: "pvt_email"
caption: "Hide E-mail address in profile"
- type: "text"
name: "url"
caption: "Home Page"
subcaption: "(URL)"
size: 32
maxlength: 255
- type: "header"
name: "header6"
caption: "Personal"
- type: "date"
name: "dob"
caption: "Date of Birth"
param: "year:-100"
- type: "text"
name: "descr"
caption: "Personal description"
size: 32
maxlength: 255
- type: "userphoto"
name: "photo"
caption: "User Photo"
param: "/profile_photo"
- type: "header"
name: "header7"
caption: "User Preferences"
- type: "checkbox"
name: "pic_in_post"
caption: "Display user photos next to conference posts"
subcaption: "(where applicable)"
- type: "checkbox"
name: "no_mass_mail"
caption: "Don't send me mass E-mail from community/conference hosts"
- type: "localelist"
name: "locale"
caption: "Default locale"
subcaption: "(for formatting dates/times)"
required: true
- type: "tzlist"
name: "tz"
caption: "Default time zone"
required: true
- type: "button"
name: "update"
caption: "Update"
param: "blue"
- type: "button"
name: "cancel"
caption: "Cancel"
param: "red"
-2
View File
@@ -103,8 +103,6 @@ func (st *AmsterdamStore) New(r *http.Request, name string) (*sessions.Session,
* Standard Go error status.
*/
func (st *AmsterdamStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
st.mutex.Lock()
defer st.mutex.Unlock()
cookie := sessions.NewCookie(session.Name(), session.ID, session.Options)
http.SetCookie(w, cookie)
return nil
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

+34 -1
View File
@@ -100,7 +100,8 @@
<div class="flex items-center">
<div class="w-24 text-right pr-4">
<input type="checkbox" id="{{ .Name }}" name="{{ .Name }}"
value="Y" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />
value="Y" {{ if .Value != "" }}checked{{ end }}
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />
</div>
<label for="{{ .Name }}" class="flex-1 text-black text-sm">
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
@@ -123,6 +124,28 @@
{{ end }}
</select>
</div>
{{ else if .Type == "localelist" }}
<div class="flex items-center">
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
</label>
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }}
class="flex-1 max-w-md px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="XX">Unknown</option>{* TODO *}
</select>
</div>
{{ else if .Type == "tzlist" }}
<div class="flex items-center">
<label for="{{ .Name }}" class="w-64 text-right pr-4 text-black text-sm">
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
{{ if .Required }}<span class="text-red-600">*</span>{{ end }}
</label>
<select id="{{ .Name }}" name="{{ .Name }}" {{ if .Required }}required{{ end }}
class="flex-1 max-w-md px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="XX">Unknown</option>{* TODO *}
</select>
</div>
{{ else if .Type == "date" }}
{{ dv := .DateValues() }}
<div class="flex items-center">
@@ -152,6 +175,16 @@
</select>
</div>
</div>
{{ else if .Type == "userphoto" }}
<div class="flex items-start">
<label class="w-64 text-right pr-4 text-black text-sm pt-2">{{ .Caption }}
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
<a href="{{ .Param }}" class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
<img src="/img/builtin/no-user.png"
alt="Click to upload photo" class="w-25 h-25">
</a>
</div>
{{ else if .Type == "header" }}
<h2 class="text-lg font-bold text-black mb-4">{{ .Caption }}</h2>
{{ else if .Type != "hidden" && .Type != "button" }}
+1 -1
View File
@@ -70,7 +70,7 @@
<span class="mx-2">-</span>
<a href="/logout" class="text-yellow-300 hover:text-yellow-400">Log Out</a>
<span class="mx-2">|</span>
<a href="/TODO/profile" class="text-yellow-300 hover:text-yellow-400">Profile</a>
<a href="/profile" class="text-yellow-300 hover:text-yellow-400">Profile</a>
{{ end }}
{{ end }}
</span>
+43
View File
@@ -0,0 +1,43 @@
/*
* Amsterdam Web Communities System
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Package main contains the high-level Amsterdam logic.
package main
import (
"errors"
"git.erbosoft.com/amy/amsterdam/ui"
)
/* EditProfileForm renders the Amsterdam profile editing form.
* 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 EditProfileForm(ctxt ui.AmContext) (string, any, error) {
// Get target URI.
target := ctxt.Parameter("tgt")
if target == "" {
target = "/"
}
u := ctxt.CurrentUser()
if u.IsAnon {
return ui.ErrorPage(ctxt, errors.New("you are not logged in"))
}
dlg, err := ui.AmLoadDialog("profile")
if err == nil {
dlg.Field("tgt").Value = target
// TODO: load fields from current user
return dlg.Render(ctxt)
}
return ui.ErrorPage(ctxt, err)
}