Pictures in Posts now works!
This commit is contained in:
@@ -436,6 +436,23 @@ func templateBozo(args jet.Arguments) reflect.Value {
|
||||
return reflect.ValueOf(rc)
|
||||
}
|
||||
|
||||
// templateProfileImage returns the user profile image associated with this post.
|
||||
func templateProfileImage(args jet.Arguments) reflect.Value {
|
||||
post := args.Get(0).Convert(reflect.TypeFor[*database.PostHeader]()).Interface().(*database.PostHeader)
|
||||
ctxt := args.Get(1).Convert(reflect.TypeFor[ui.AmContext]()).Interface().(ui.AmContext)
|
||||
rc := "/img/builtin/no-user.png"
|
||||
user, err := post.Creator(ctxt.Ctx())
|
||||
if err == nil {
|
||||
ci, err := user.ContactInfo(ctxt.Ctx())
|
||||
if err == nil {
|
||||
if ci.PhotoURL != nil {
|
||||
rc = *ci.PhotoURL
|
||||
}
|
||||
}
|
||||
}
|
||||
return reflect.ValueOf(rc)
|
||||
}
|
||||
|
||||
/* ReadPosts displays posts in a topic.
|
||||
* Parameters:
|
||||
* ctxt - The AmContext for the request.
|
||||
@@ -555,6 +572,16 @@ func ReadPosts(ctxt ui.AmContext) (string, any) {
|
||||
}
|
||||
ctxt.VarMap().Set("pseud", pseud)
|
||||
|
||||
// Get property flags from conference and user.
|
||||
cflags, err := conf.Flags(ctxt.Ctx())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
uflags, err := ctxt.CurrentUser().Flags(ctxt.Ctx())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
|
||||
// Set permission and status flags.
|
||||
confHidePerm := conf.TestPermission("Conference.Hide", myLevel)
|
||||
ctxt.VarMap().Set("canFreeze", confHidePerm)
|
||||
@@ -568,6 +595,7 @@ func ReadPosts(ctxt ui.AmContext) (string, any) {
|
||||
confPostPerm := conf.TestPermission("Conference.Post", myLevel)
|
||||
ctxt.VarMap().Set("canPost", (!(topic.Frozen || topic.Archived) || confHidePerm) && confPostPerm)
|
||||
ctxt.VarMap().Set("showFrozenArchiveMessages", confPostPerm)
|
||||
ctxt.VarMap().Set("showPics", cflags.Get(database.ConferenceFlagPicturesInPosts) && uflags.Get(database.UserFlagPicturesInPosts))
|
||||
|
||||
// Set advanced controls.
|
||||
advancedControls := ctxt.HasParameter("ac") && (len(posts) == 1)
|
||||
@@ -622,6 +650,7 @@ func ReadPosts(ctxt ui.AmContext) (string, any) {
|
||||
ctxt.VarMap().SetFunc("post_getUserName", templateExtractUserName)
|
||||
ctxt.VarMap().SetFunc("post_getAttachmentInfo", templateAttachmentInfo)
|
||||
ctxt.VarMap().SetFunc("post_isBozo", templateBozo)
|
||||
ctxt.VarMap().SetFunc("post_profileImage", templateProfileImage)
|
||||
ctxt.VarMap().Set("post_stem", fmt.Sprintf("%s/r/%d", urlStem, topic.Number))
|
||||
ctxt.VarMap().Set("post_max", topic.TopMessage)
|
||||
ctxt.VarMap().Set("posts", posts)
|
||||
|
||||
@@ -90,6 +90,7 @@ type AmConfig struct {
|
||||
CountryList struct {
|
||||
Prioritize string `yaml:"prioritize"`
|
||||
} `yaml:"countryList"`
|
||||
VeniceCompatibleImageURLs bool `yaml:"veniceCompatibleImageURLs"`
|
||||
} `yaml:"rendering"`
|
||||
Posting struct {
|
||||
ExternalDictionary string `yaml:"externalDictionary"`
|
||||
@@ -198,6 +199,17 @@ func overlayInt(loaded int, defaulted int) int {
|
||||
return defaulted
|
||||
}
|
||||
|
||||
/* overlayOptionFlag is a helper that takes a loaded or defaulted option flag and returns it.
|
||||
* Parameters:
|
||||
* loaded - The option flag loaded from a configuration file.
|
||||
* defaulted - The default value of this option flag.
|
||||
* Returns:
|
||||
* Combined value.
|
||||
*/
|
||||
func overlayOptionFlag(loaded, defaulted bool) bool {
|
||||
return loaded || defaulted
|
||||
}
|
||||
|
||||
/* overlayConfig takes two configuration structures and overlays them to create the third.
|
||||
* Parameters:
|
||||
* dest - Points to the destination copnfiguration structure.
|
||||
@@ -230,6 +242,7 @@ func overlayConfig(dest *AmConfig, loaded *AmConfig, defaults *AmConfig) {
|
||||
dest.Rendering.TemplateDir = overlayString(loaded.Rendering.TemplateDir, defaults.Rendering.TemplateDir)
|
||||
dest.Rendering.CookieKey = overlayString(loaded.Rendering.CookieKey, defaults.Rendering.CookieKey)
|
||||
dest.Rendering.CountryList.Prioritize = overlayString(loaded.Rendering.CountryList.Prioritize, defaults.Rendering.CountryList.Prioritize)
|
||||
dest.Rendering.VeniceCompatibleImageURLs = overlayOptionFlag(loaded.Rendering.VeniceCompatibleImageURLs, defaults.Rendering.VeniceCompatibleImageURLs)
|
||||
dest.Posting.ExternalDictionary = overlayString(loaded.Posting.ExternalDictionary, defaults.Posting.ExternalDictionary)
|
||||
dest.Posting.Uploads.MaxSize = overlayString(loaded.Posting.Uploads.MaxSize, defaults.Posting.Uploads.MaxSize)
|
||||
dest.Posting.Uploads.NoCompressTypes = overlayStringArray(loaded.Posting.Uploads.NoCompressTypes, defaults.Posting.Uploads.NoCompressTypes)
|
||||
|
||||
@@ -43,6 +43,7 @@ rendering:
|
||||
cookiekey: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
countryList:
|
||||
prioritize: US
|
||||
veniceCompatibleImageURLs: false
|
||||
posting:
|
||||
externalDictionary: ""
|
||||
uploads:
|
||||
|
||||
@@ -72,7 +72,7 @@ _(italicized items can be deferred)_
|
||||
- Import Messages
|
||||
- ~~Delete Conference~~
|
||||
- ~~Add to Hotlist/Remove from Hotlist~~
|
||||
- Actually implement pictures in posts
|
||||
- ~~Actually implement pictures in posts~~
|
||||
- ~~Related to bugs in Export Messages caused by bad data:~~
|
||||
- ~~Provide a per-conference flag that will set BuggyAttachment behavior~~
|
||||
- ~~New feature: remove attachment from message (requires Conference.Nuke permission)~~
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
* Copyright (c) 2025-2026 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
|
||||
@@ -34,6 +34,12 @@ var ENOACCOUNT error = errors.New("you cannot create a new account while logged
|
||||
func LoginForm(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -63,6 +69,12 @@ func Login(ctxt ui.AmContext) (string, any) {
|
||||
if err == nil {
|
||||
dlg.LoadFromForm(ctxt)
|
||||
target := dlg.Field("tgt").Value
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -166,6 +178,12 @@ func Logout(ctxt ui.AmContext) (string, any) {
|
||||
func VerifyEmailForm(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -222,6 +240,12 @@ func VerifyEMail(ctxt ui.AmContext) (string, any) {
|
||||
if err == nil {
|
||||
dlg.LoadFromForm(ctxt)
|
||||
target := dlg.Field("tgt").Value
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -276,6 +300,12 @@ func VerifyEMail(ctxt ui.AmContext) (string, any) {
|
||||
func NewAccountUserAgreement(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -302,6 +332,12 @@ func NewAccountUserAgreement(ctxt ui.AmContext) (string, any) {
|
||||
func NewAccountForm(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -337,6 +373,12 @@ func NewAccount(ctxt ui.AmContext) (string, any) {
|
||||
if err == nil {
|
||||
dlg.LoadFromForm(ctxt)
|
||||
target := dlg.Field("tgt").Value
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ func setupEcho() *echo.Echo {
|
||||
e.RouteNotFound("/*", ui.AmWrap(AmNotFoundHandler), uiset...)
|
||||
e.Match(GetAndPost, "/TODO/*", ui.AmWrap(NotImplPage), uiset...)
|
||||
e.GET("/img/*", ui.AmServeImage)
|
||||
if config.GlobalConfig.Rendering.VeniceCompatibleImageURLs {
|
||||
e.GET("/venice/imagedata/:id", ui.AmServeVeniceCompatibleImage)
|
||||
}
|
||||
e.GET("/static/*", ui.AmStaticFileHandler())
|
||||
e.GET("/go/:postlink", ui.AmWrap(JumpToShortcut))
|
||||
|
||||
|
||||
@@ -23,14 +23,12 @@ fields:
|
||||
- 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"
|
||||
|
||||
+22
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
* Copyright (c) 2025-2026 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
|
||||
@@ -89,6 +89,27 @@ func AmServeImage(c echo.Context) error {
|
||||
return c.String(http.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
/* AmServeVeniceCompatibleImage serves an image from the image store under a Venice-compatible URI.
|
||||
* Parameters:
|
||||
* c - The Echo context for this request.
|
||||
* Returns:
|
||||
* Standard Go error return.
|
||||
*/
|
||||
func AmServeVeniceCompatibleImage(c echo.Context) error {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err == nil {
|
||||
var img *database.ImageStore
|
||||
img, err = database.AmLoadImage(c.Request().Context(), int32(id))
|
||||
if err == nil {
|
||||
return c.Blob(http.StatusOK, img.MimeType, img.Data)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
err = fmt.Errorf("image not found: %s", c.Request().URL.Path)
|
||||
}
|
||||
return c.String(http.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
/* AmProcessUploadedImage takes an image and resizes it to a specified size, returning its data.
|
||||
* Parameters:
|
||||
* fileheader - The multipart file header from the uploaded file.
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
{{ post_overrideLink := "" }}
|
||||
{{ post_attach := nil }}
|
||||
{{ post_bozo := false }}
|
||||
{{ post_profile_pic := "" }}
|
||||
{{ range i, p := posts }}
|
||||
{{ post_cur = p }}
|
||||
{{ post_userName = post_getUserName(p, .) }}
|
||||
@@ -118,6 +119,9 @@
|
||||
{{ post_overrideLink = post_getOverrideLink(p, post_topicPermalink) }}
|
||||
{{ post_attach = post_getAttachmentInfo(p, .) }}
|
||||
{{ post_bozo = post_isBozo(p, post_topic, .) }}
|
||||
{{ if showPics }}
|
||||
{{ post_profile_pic = post_profileImage(p, .) }}
|
||||
{{ end }}
|
||||
{{ include "singlepost.jet" }}
|
||||
{{ if advancedControls }}
|
||||
<div class="flex flex-col gap-2">
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
<!-- Left Column: Photo and Metadata -->
|
||||
<div class="flex-shrink-0 w-40">
|
||||
<div class="border-2 border-gray-300 rounded mb-4">
|
||||
<img src="{{ photoURL }}" alt="{{ username }}'s photo" class="w-full h-auto">
|
||||
<img src="{{ photoURL }}" alt="{{ username }}'s photo" class="w-full h-auto rounded-3xl border-2 border-gray-300"
|
||||
onerror="this.src='/img/builtin/no-user.png'">
|
||||
</div>
|
||||
<div class="text-xs text-gray-700 space-y-2">
|
||||
<div>
|
||||
|
||||
+50
-39
@@ -7,45 +7,56 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*}
|
||||
<div class="flex-1 border-2 border-gray-300 rounded-lg p-4 bg-white">
|
||||
<div class="flex justify-between items-start mb-3">
|
||||
<div class="text-sm text-gray-600">
|
||||
<a href="{{ post_stem }}?r={{ post_cur.Num }}&ac=1" class="text-blue-700 hover:text-blue-900 font-mono">{{ post_cur.Num }}</a> of
|
||||
<a href="{{ post_stem }}?r={{ post_max }}&ac=1" class="text-blue-700 hover:text-blue-900 font-mono">{{ post_max }}</a>
|
||||
<a href="{{ post_topicPermalink }}.{{ post_cur.Num }}" class="ml-2 text-xs text-blue-700 hover:text-blue-900"
|
||||
title="Permalink to this post">🔗<{{ post_confRef }}.{{ post_cur.Num }}></a>
|
||||
<div class="flex gap-2">
|
||||
{{ if !post_bozo && isset(post_profile_pic) && (post_profile_pic != "") }}
|
||||
<div class="flex-shrink-0">
|
||||
<img src="{{ post_profile_pic }}" alt="Profile image: {{ post_userName }}"
|
||||
class="w-16 h-16 rounded-lg border-2 border-gray-300"
|
||||
onerror="this.src='/img/builtin/no-user.png'">
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start mb-3">
|
||||
<div class="text-sm text-gray-600">
|
||||
<a href="{{ post_stem }}?r={{ post_cur.Num }}&ac=1" class="text-blue-700 hover:text-blue-900 font-mono">{{ post_cur.Num }}</a> of
|
||||
<a href="{{ post_stem }}?r={{ post_max }}&ac=1" class="text-blue-700 hover:text-blue-900 font-mono">{{ post_max }}</a>
|
||||
<a href="{{ post_topicPermalink }}.{{ post_cur.Num }}" class="ml-2 text-xs text-blue-700 hover:text-blue-900"
|
||||
title="Permalink to this post">🔗<{{ post_confRef }}.{{ post_cur.Num }}></a>
|
||||
</div>
|
||||
</div>
|
||||
{{ if post_bozo }}
|
||||
<div class="mt-4 mb-2">
|
||||
<span class="italic font-bold">
|
||||
(User filtered; <a class="text-blue-700 hover:text-blue-900" href="{{ post_stem }}?r={{ post_cur.Num }}&ac=1&bozo=0">remove filter</a>)
|
||||
</span>
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="mb-2">
|
||||
<strong class="text-lg">{{ post_cur.Pseud | raw }}</strong>
|
||||
<span class="text-gray-600 text-sm ml-2">(<em>
|
||||
<a href="/user/{{ post_userName }}" target="_blank" class="text-blue-700 hover:text-blue-900">{{ post_userName }}</a>,
|
||||
{{ DisplayDateTime(post_cur.Posted, .) }}</em>)
|
||||
{{ if post_attach.Filename != "" }}
|
||||
<a href="/attachment/{{ post_cur.PostId }}" title="(Attachment {{ post_attach.Filename }} - {{ post_attach.Length }} bytes)"
|
||||
{{ if hasPrefix(post_attach.MIMEType, "text/") || hasPrefix(post_attach.MIMEType, "image/" )}}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="text-lg">📎</a>
|
||||
{{ end }}
|
||||
</span>
|
||||
</div>
|
||||
{{ if post_overrideLine != "" }}
|
||||
<div class="mb-2">
|
||||
{{ if post_overrideLink != "" }}
|
||||
<a href="{{ post_overrideLink }}" target="_blank" class="text-blue-700 hover:text-blue-900"><span class="italic font-bold">{{ post_overrideLine }}</span></a>
|
||||
{{ else }}
|
||||
<span class="italic text-bold">{{ post_overrideLine }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ else }}
|
||||
<pre class="amsPost font-mono text-sm whitespace-pre-wrap bg-gray-50 p-4 rounded border border-gray-200">{{ post_text | postRewrite | raw }}</pre>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ if post_bozo }}
|
||||
<div class="mt-4 mb-2">
|
||||
<span class="italic font-bold">
|
||||
(User filtered; <a class="text-blue-700 hover:text-blue-900" href="{{ post_stem }}?r={{ post_cur.Num }}&ac=1&bozo=0">remove filter</a>)
|
||||
</span>
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="mb-2">
|
||||
<strong class="text-lg">{{ post_cur.Pseud | raw }}</strong>
|
||||
<span class="text-gray-600 text-sm ml-2">(<em>
|
||||
<a href="/user/{{ post_userName }}" target="_blank" class="text-blue-700 hover:text-blue-900">{{ post_userName }}</a>,
|
||||
{{ DisplayDateTime(post_cur.Posted, .) }}</em>)
|
||||
{{ if post_attach.Filename != "" }}
|
||||
<a href="/attachment/{{ post_cur.PostId }}" title="(Attachment {{ post_attach.Filename }} - {{ post_attach.Length }} bytes)"
|
||||
{{ if hasPrefix(post_attach.MIMEType, "text/") || hasPrefix(post_attach.MIMEType, "image/" )}}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="text-lg">📎</a>
|
||||
{{ end }}
|
||||
</span>
|
||||
</div>
|
||||
{{ if post_overrideLine != "" }}
|
||||
<div class="mb-2">
|
||||
{{ if post_overrideLink != "" }}
|
||||
<a href="{{ post_overrideLink }}" target="_blank" class="text-blue-700 hover:text-blue-900"><span class="italic font-bold">{{ post_overrideLine }}</span></a>
|
||||
{{ else }}
|
||||
<span class="italic text-bold">{{ post_overrideLine }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ else }}
|
||||
<pre class="amsPost font-mono text-sm whitespace-pre-wrap bg-gray-50 p-4 rounded border border-gray-200">{{ post_text | postRewrite | raw }}</pre>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
+25
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
* Copyright (c) 2025-2026 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
|
||||
@@ -45,6 +45,12 @@ func userPhotoURL(ci *database.ContactInfo) string {
|
||||
func EditProfileForm(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -125,6 +131,12 @@ func EditProfile(ctxt ui.AmContext) (string, any) {
|
||||
if err == nil {
|
||||
dlg.LoadFromForm(ctxt)
|
||||
target := dlg.Field("tgt").Value
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -228,6 +240,12 @@ func EditProfile(ctxt ui.AmContext) (string, any) {
|
||||
func ProfilePhotoForm(ctxt ui.AmContext) (string, any) {
|
||||
// Get target URI.
|
||||
target := ctxt.Parameter("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
@@ -264,6 +282,12 @@ func ProfilePhoto(ctxt ui.AmContext) (string, any) {
|
||||
return "error", err
|
||||
}
|
||||
target := ctxt.FormField("tgt")
|
||||
if target == "" {
|
||||
v := ctxt.GetSession("lastKnownGood")
|
||||
if v != nil {
|
||||
target = v.(string)
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
target = "/"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user