added contact info support and the code for sending a password reminder
This commit is contained in:
+12
-8
@@ -59,14 +59,16 @@ type AmConfig struct {
|
||||
Dsn string `yaml:"dsn"`
|
||||
} `yaml:"database"`
|
||||
Email struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Tls string `yaml:"tls"`
|
||||
AuthType string `yaml:"authType"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
Signature string `yaml:"signature"`
|
||||
Disclaimer string `yaml:"disclaimer"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Tls string `yaml:"tls"`
|
||||
AuthType string `yaml:"authType"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
MailFromAddr string `yaml:"mailFromAddr"`
|
||||
MailFromName string `yaml:"mailFromName"`
|
||||
Signature string `yaml:"signature"`
|
||||
Disclaimer string `yaml:"disclaimer"`
|
||||
} `yaml:"email"`
|
||||
Rendering struct {
|
||||
TemplateDir string `yaml:"templatedir"`
|
||||
@@ -130,6 +132,8 @@ func overlayConfig(dest *AmConfig, loaded *AmConfig, defaults *AmConfig) {
|
||||
dest.Email.AuthType = overlayString(loaded.Email.AuthType, defaults.Email.AuthType)
|
||||
dest.Email.User = overlayString(loaded.Email.User, defaults.Email.User)
|
||||
dest.Email.Password = overlayString(loaded.Email.Password, defaults.Email.Password)
|
||||
dest.Email.MailFromAddr = overlayString(loaded.Email.MailFromAddr, defaults.Email.MailFromAddr)
|
||||
dest.Email.MailFromName = overlayString(loaded.Email.MailFromName, defaults.Email.MailFromName)
|
||||
dest.Email.Signature = overlayString(loaded.Email.Signature, defaults.Email.Signature)
|
||||
dest.Email.Disclaimer = overlayString(loaded.Email.Disclaimer, defaults.Email.Disclaimer)
|
||||
dest.Rendering.TemplateDir = overlayString(loaded.Rendering.TemplateDir, defaults.Rendering.TemplateDir)
|
||||
|
||||
@@ -23,6 +23,8 @@ email:
|
||||
authType: plain
|
||||
user: jrn
|
||||
password: foobiebletch
|
||||
mailFromAddr: "nobody@example.com"
|
||||
mailFromName: "Amsterdam E-Mail Service"
|
||||
signature: |-
|
||||
Amsterdam - community services, conferencing and more. <http://git.erbosoft.com/amy/amsterdam>
|
||||
disclaimer: |-
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
// The database package contains database management and storage logic.
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
// ContactInfo stores the contact information for a user or community.
|
||||
type ContactInfo struct {
|
||||
ContactId int32 `db:"contactid"`
|
||||
GivenName string `db:"given_name"`
|
||||
FamilyName string `db:"family_name"`
|
||||
MiddleInit string `db:"middle_init"`
|
||||
Prefix *string `db:"prefix"`
|
||||
Suffix *string `db:"suffix"`
|
||||
Company *string `db:"company"`
|
||||
Addr1 *string `db:"addr1"`
|
||||
Addr2 *string `db:"addr2"`
|
||||
Locality *string `db:"locality"`
|
||||
Region *string `db:"region"`
|
||||
PostalCode *string `db:"pcode"`
|
||||
Country *string `db:"country"`
|
||||
Phone *string `db:"phone"`
|
||||
Fax *string `db:"fax"`
|
||||
Mobile *string `db:"mobile"`
|
||||
Email *string `db:"email"`
|
||||
PrivateAddr bool `db:"pvt_addr"`
|
||||
PrivatePhone bool `db:"pvt_phone"`
|
||||
PrivateFax bool `db:"pvt_fax"`
|
||||
PrivateEmail bool `db:"pvt_email"`
|
||||
OwnerUid int32 `db:"owner_uid"`
|
||||
OwnerCommId int32 `db:"owner_commid"`
|
||||
PhotoURL *string `db:"photo_url"`
|
||||
URL *string `db:"url"`
|
||||
LastUpdate *time.Time
|
||||
}
|
||||
|
||||
// contactCache is the cache for ContactInfo objects.
|
||||
var contactCache *lru.TwoQueueCache = nil
|
||||
|
||||
// getContactMutex is a mutex on AmGetContactInfo.
|
||||
var getContactMutex sync.Mutex
|
||||
|
||||
// init initializes the contact info cache.
|
||||
func init() {
|
||||
var err error
|
||||
contactCache, err = lru.New2Q(100)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// internalContactInfo retrieves the contact info from the database.
|
||||
func internalContactInfo(id int32) (*ContactInfo, error) {
|
||||
var dbdata []ContactInfo
|
||||
err := amdb.Select(&dbdata, "SELECT * from contacts WHERE contactid = ?", id)
|
||||
if err == nil {
|
||||
if len(dbdata) > 1 {
|
||||
err = fmt.Errorf("internalContactInfo(%d): Too many responses (%d)", id, len(dbdata))
|
||||
} else if len(dbdata) == 0 {
|
||||
return nil, nil
|
||||
} else {
|
||||
return &(dbdata[0]), nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* AmGetContactInfo retrieves the contact info for a given identifier.
|
||||
* Parameters:
|
||||
* id - The contact info ID top retrieve.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
func AmGetContactInfo(id int32) (*ContactInfo, error) {
|
||||
getContactMutex.Lock()
|
||||
defer getContactMutex.Unlock()
|
||||
rc, ok := contactCache.Get(id)
|
||||
if ok {
|
||||
return rc.(*ContactInfo), nil
|
||||
}
|
||||
rc2, err := internalContactInfo(id)
|
||||
if err == nil {
|
||||
if rc2 != nil {
|
||||
contactCache.Add(id, rc2)
|
||||
}
|
||||
return rc2, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,6 +60,14 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// ContactInfo returns the contact info structure for the user.
|
||||
func (u *User) ContactInfo() (*ContactInfo, error) {
|
||||
if u.ContactID < 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return AmGetContactInfo(u.ContactID)
|
||||
}
|
||||
|
||||
/* AmGetUser returns a reference to the specified user.
|
||||
* Parameters:
|
||||
* uid - The UID of the user.
|
||||
|
||||
@@ -13,6 +13,7 @@ package email
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/config"
|
||||
"git.erbosoft.com/amy/amsterdam/util"
|
||||
"github.com/CloudyKit/jet/v6"
|
||||
)
|
||||
@@ -126,6 +127,7 @@ func AmNewEmailMessage(sender int32, ip string) Message {
|
||||
}
|
||||
rc.uid = sender
|
||||
rc.ip = ip
|
||||
rc.SetFrom(config.GlobalConfig.Email.MailFromAddr, config.GlobalConfig.Email.MailFromName)
|
||||
return rc
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ If this reminder is not sufficient for you to remember what your password is,
|
||||
then the system can change your password for you. To do so, please visit
|
||||
the following URL:
|
||||
|
||||
http://example.com/passrecovery/{{ change_uid }}.{{ change.auth }}
|
||||
http://example.com/passrecovery/{{ change_uid }}.{{ change_auth }}
|
||||
|
||||
Your password will be changed and a new password will be E-mailed to you
|
||||
at this address.
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
"git.erbosoft.com/amy/amsterdam/email"
|
||||
"git.erbosoft.com/amy/amsterdam/ui"
|
||||
)
|
||||
|
||||
@@ -72,13 +74,30 @@ func Login(ctxt ui.AmContext) (string, any, error) {
|
||||
if action == "remind" { // Password Reminder button pressed
|
||||
user, uerr := database.AmGetUserByName(dlg.Field("user").Value)
|
||||
if uerr == nil {
|
||||
_ = user
|
||||
// TODO: send password reminder
|
||||
|
||||
var ci *database.ContactInfo
|
||||
ci, uerr = user.ContactInfo()
|
||||
if uerr == nil {
|
||||
if ci != nil && ci.Email != nil && *ci.Email != "" {
|
||||
msg := email.AmNewEmailMessage(user.Uid, ctxt.RemoteIP())
|
||||
msg.AddTo(*ci.Email, "")
|
||||
msg.SetTemplate("pass_remind.jet")
|
||||
msg.AddVariable("username", user.Username)
|
||||
msg.AddVariable("reminder", user.PassReminder)
|
||||
msg.AddVariable("change_uid", user.Uid)
|
||||
msg.AddVariable("change_auth", "TODO") // TODO: add change auth link
|
||||
msg.Send()
|
||||
} else {
|
||||
uerr = errors.New("cannot find email address")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dlg.Field("pass").Value = ""
|
||||
return dlg.RenderError(ctxt, "Password reminder has been sent to your E-mail address.")
|
||||
if uerr == nil {
|
||||
return dlg.RenderInfo(ctxt, "Password reminder has been sent to your E-mail address.")
|
||||
} else {
|
||||
return dlg.RenderError(ctxt, uerr.Error())
|
||||
}
|
||||
}
|
||||
if action == "login" { // Login button pressed
|
||||
// authenticate the user
|
||||
|
||||
@@ -146,6 +146,20 @@ func (d *Dialog) RenderError(ctxt AmContext, errormessage string) (string, any,
|
||||
return d.Render(ctxt)
|
||||
}
|
||||
|
||||
/* RenderInfo sets up the rendering parameters to send this dialog to the output with an info message.
|
||||
* Parameters:
|
||||
* ctxt - The AmContext for this request.
|
||||
* infoMessage - The info 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) RenderInfo(ctxt AmContext, infoMessage string) (string, any, error) {
|
||||
ctxt.VarMap().Set("amsterdam_infoMessage", infoMessage)
|
||||
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.
|
||||
|
||||
@@ -38,6 +38,19 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if isset(amsterdam_infoMessage) }}
|
||||
<!-- Info Message Banner -->
|
||||
<div class="bg-blue-100 border border-blue-400 text-blue-700 px-4 py-3 rounded mb-6 hidden" id="info-banner">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<span class="text-blue-500 text-xl">ℹ️</span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium" id="info-message">{{ amsterdam_infoMessage }}.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="bg-gray-50 p-6 rounded-lg">
|
||||
<div class="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user