added user photo upload page
This commit is contained in:
@@ -127,7 +127,7 @@ func Login(ctxt ui.AmContext) (string, any, error) {
|
|||||||
if user.VerifyEMail {
|
if user.VerifyEMail {
|
||||||
return "redirect", target, nil
|
return "redirect", target, nil
|
||||||
} else {
|
} else {
|
||||||
return "redirect", "/verify?tgt=" + url.PathEscape(target), nil
|
return "redirect", "/verify?tgt=" + url.QueryEscape(target), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dlg.RenderError(ctxt, "No known button click on POST to login function.")
|
return dlg.RenderError(ctxt, "No known button click on POST to login function.")
|
||||||
@@ -393,7 +393,7 @@ func NewAccount(ctxt ui.AmContext) (string, any, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// user is now logged in! redirect to E-mail verification
|
// user is now logged in! redirect to E-mail verification
|
||||||
ctxt.ReplaceUser(user)
|
ctxt.ReplaceUser(user)
|
||||||
return "redirect", "/verify?tgt=" + url.PathEscape(target), nil
|
return "redirect", "/verify?tgt=" + url.QueryEscape(target), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ func setupEcho() *echo.Echo {
|
|||||||
e.GET("/passrecovery/:uid/:auth", ui.AmWrap(PasswordRecovery))
|
e.GET("/passrecovery/:uid/:auth", ui.AmWrap(PasswordRecovery))
|
||||||
e.GET("/profile", ui.AmWrap(EditProfileForm))
|
e.GET("/profile", ui.AmWrap(EditProfileForm))
|
||||||
e.POST("/profile", ui.AmWrap(EditProfile))
|
e.POST("/profile", ui.AmWrap(EditProfile))
|
||||||
|
e.GET("/profile_photo", ui.AmWrap(ProfilePhotoForm))
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -106,7 +106,7 @@ func AmWrap(myfunc func(AmContext) (string, any, error)) echo.HandlerFunc {
|
|||||||
if !user.VerifyEMail {
|
if !user.VerifyEMail {
|
||||||
// bounce to E-mail verification before we go anywhere
|
// bounce to E-mail verification before we go anywhere
|
||||||
return sendPageData(ctxt, amctxt, "redirect",
|
return sendPageData(ctxt, amctxt, "redirect",
|
||||||
"/verify?tgt="+url.PathEscape(ctxt.Request().URL.Path))
|
"/verify?tgt="+url.QueryEscape(ctxt.Request().URL.Path))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("login cookie bogus, do not use: %v", cerr)
|
log.Errorf("login cookie bogus, do not use: %v", cerr)
|
||||||
|
|||||||
+2
-1
@@ -186,7 +186,8 @@
|
|||||||
<label class="w-64 text-right pr-4 text-black text-sm pt-2">{{ .Caption }}
|
<label class="w-64 text-right pr-4 text-black text-sm pt-2">{{ .Caption }}
|
||||||
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
|
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
|
||||||
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
|
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
|
||||||
<a href="{{ .Param }}" class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
<a href="/profile_photo?tgt={{ target | url }}"
|
||||||
|
class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
||||||
<img src="/img/builtin/no-user.png"
|
<img src="/img/builtin/no-user.png"
|
||||||
alt="Click to upload photo" class="w-25 h-25">
|
alt="Click to upload photo" class="w-25 h-25">
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{*
|
||||||
|
* 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/.
|
||||||
|
*}
|
||||||
|
<!-- Page Title -->
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="mb-6">
|
||||||
|
<h1 class="text-blue-800 text-4xl font-bold mb-2">Upload User Photo</h1>
|
||||||
|
<hr class="border-2 border-gray-400 w-4/5 mb-4">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Form -->
|
||||||
|
<form method="POST" enctype="multipart/form-data" action="/profile_photo" class="max-w-2xl">
|
||||||
|
<input type="hidden" name="tgt" value="{{ target }}">
|
||||||
|
|
||||||
|
<div class="bg-gray-50 p-6 rounded-lg">
|
||||||
|
<div class="flex items-start gap-6">
|
||||||
|
<!-- Current Photo -->
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="border-2 border-gray-300 rounded">
|
||||||
|
<img src="{{ photo_url }}" alt="Current user photo" class="w-25 h-25">
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-600 text-center mt-2">Current Photo</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Controls -->
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="thepic" class="block text-black text-sm font-medium mb-2">
|
||||||
|
New user photo:
|
||||||
|
</label>
|
||||||
|
<input type="file" id="thepic" name="thepic" accept="image/*"
|
||||||
|
class="block w-full text-sm text-gray-900 border border-gray-300 rounded cursor-pointer bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-blue-600 file:text-white hover:file:bg-blue-700">
|
||||||
|
<p class="mt-2 text-xs text-gray-600">
|
||||||
|
Recommended: Square images work best. Maximum file size: 2MB. Supported formats: JPG, PNG, GIF.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<button type="submit"
|
||||||
|
name="upload"
|
||||||
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
||||||
|
Upload Photo
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
name="cancel"
|
||||||
|
class="bg-red-600 hover:bg-red-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
name="remove"
|
||||||
|
class="bg-red-600 hover:bg-red-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Additional Instructions -->
|
||||||
|
<div class="mt-6 p-4 bg-blue-50 border border-blue-200 rounded">
|
||||||
|
<h3 class="text-sm font-bold text-blue-900 mb-2">Photo Guidelines:</h3>
|
||||||
|
<ul class="text-xs text-blue-800 space-y-1 list-disc list-inside">
|
||||||
|
<li>Your photo will be visible to other users in the community</li>
|
||||||
|
<li>Photos should be appropriate for a professional community setting</li>
|
||||||
|
<li>The image will be automatically resized to fit the profile display</li>
|
||||||
|
<li>You can update or remove your photo at any time</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
+32
-1
@@ -39,6 +39,7 @@ func EditProfileForm(ctxt ui.AmContext) (string, any, error) {
|
|||||||
dlg, err := ui.AmLoadDialog("profile")
|
dlg, err := ui.AmLoadDialog("profile")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
dlg.Field("tgt").Value = target
|
dlg.Field("tgt").Value = target
|
||||||
|
ctxt.VarMap().Set("target", target)
|
||||||
var ci *database.ContactInfo
|
var ci *database.ContactInfo
|
||||||
ci, err = u.ContactInfo()
|
ci, err = u.ContactInfo()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -93,6 +94,7 @@ func EditProfile(ctxt ui.AmContext) (string, any, error) {
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
target = "/"
|
target = "/"
|
||||||
}
|
}
|
||||||
|
ctxt.VarMap().Set("target", target)
|
||||||
|
|
||||||
action := dlg.WhichButton(ctxt)
|
action := dlg.WhichButton(ctxt)
|
||||||
if action == "cancel" { // Cancel button pressed
|
if action == "cancel" { // Cancel button pressed
|
||||||
@@ -162,7 +164,7 @@ func EditProfile(ctxt ui.AmContext) (string, any, error) {
|
|||||||
if emailChange {
|
if emailChange {
|
||||||
err = sendEmailConfirmationEmail(u, ci, ctxt.RemoteIP())
|
err = sendEmailConfirmationEmail(u, ci, ctxt.RemoteIP())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return "redirect", "/verify?tgt=" + url.PathEscape(target), nil
|
return "redirect", "/verify?tgt=" + url.QueryEscape(target), nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "redirect", target, nil
|
return "redirect", target, nil
|
||||||
@@ -174,3 +176,32 @@ func EditProfile(ctxt ui.AmContext) (string, any, error) {
|
|||||||
}
|
}
|
||||||
return ui.ErrorPage(ctxt, err)
|
return ui.ErrorPage(ctxt, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ProfilePhotoForm renders the Amsterdam profile photo upload 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 ProfilePhotoForm(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"))
|
||||||
|
}
|
||||||
|
ci, err := u.ContactInfo()
|
||||||
|
if err == nil {
|
||||||
|
_ = ci
|
||||||
|
ctxt.VarMap().Set("target", target)
|
||||||
|
ctxt.VarMap().Set("photo_url", "/img/builtin/no-user.png")
|
||||||
|
ctxt.VarMap().Set("amsterdam_pageTitle", "Upload User Photo")
|
||||||
|
return "framed_template", "photo_upload.jet", nil
|
||||||
|
}
|
||||||
|
return ui.ErrorPage(ctxt, err)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user