beginnings of the Edit Profile page, dialog field and rendering additions
This commit is contained in:
@@ -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
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user