added upload and changing of community logo, and fixed logo references in other files
This commit is contained in:
+5
-1
@@ -62,7 +62,11 @@ func ShowCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
}
|
||||
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
// TODO: set photo URL
|
||||
if ci.PhotoURL != nil && *ci.PhotoURL != "" {
|
||||
ctxt.VarMap().Set("logoURL", *ci.PhotoURL)
|
||||
} else {
|
||||
ctxt.VarMap().Set("logoURL", "/img/builtin/default-community.jpg")
|
||||
}
|
||||
tz := prefs.Location()
|
||||
loc := prefs.Localizer()
|
||||
ctxt.VarMap().Set("dateCreated", loc.Strftime("%x %X", comm.CreateDate.In(tz)))
|
||||
|
||||
+120
-1
@@ -15,10 +15,12 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
"git.erbosoft.com/amy/amsterdam/ui"
|
||||
"git.erbosoft.com/amy/amsterdam/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/* CommunityAdminMenu renders the community administration menu.
|
||||
@@ -67,6 +69,22 @@ func setupCommunityProfileDialog(dlg *ui.Dialog, comm *database.Community) {
|
||||
}
|
||||
}
|
||||
|
||||
// communityLogoURL returns the logo URL from the contact info, or a default.
|
||||
func communityLogoURL(ci *database.ContactInfo) string {
|
||||
if ci.PhotoURL != nil && *ci.PhotoURL != "" {
|
||||
return *ci.PhotoURL
|
||||
}
|
||||
return "/img/builtin/default-community.jpg"
|
||||
}
|
||||
|
||||
/* CommunityProfileForm displays the dfialog for editing the community profile.
|
||||
* 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 CommunityProfileForm(ctxt ui.AmContext) (string, any, error) {
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
if err != nil {
|
||||
@@ -97,7 +115,7 @@ func CommunityProfileForm(ctxt ui.AmContext) (string, any, error) {
|
||||
dlg.Field("rules").SetVal(comm.Rules)
|
||||
dlg.Field("language").SetVal(comm.Language)
|
||||
dlg.Field("url").SetVal(ci.URL)
|
||||
// TODO: set logo URL
|
||||
dlg.Field("logo").Value = communityLogoURL(ci)
|
||||
dlg.Field("company").SetVal(ci.Company)
|
||||
dlg.Field("addr1").SetVal(ci.Addr1)
|
||||
dlg.Field("addr2").SetVal(ci.Addr2)
|
||||
@@ -222,3 +240,104 @@ func EditCommunityProfile(ctxt ui.AmContext) (string, any, error) {
|
||||
}
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
|
||||
func CommunityLogoForm(ctxt ui.AmContext) (string, any, error) {
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
if !comm.TestPermission("Community.Write", ctxt.EffectiveLevel()) {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not permitted to access this page"))
|
||||
}
|
||||
ci, err := comm.ContactInfo()
|
||||
if err == nil {
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("commAlias", comm.Alias)
|
||||
ctxt.VarMap().Set("logo_url", communityLogoURL(ci))
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Upload Community Logo: "+comm.Name)
|
||||
return "framed_template", "logo_upload.jet", nil
|
||||
}
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
|
||||
func EditCommunityLogo(ctxt ui.AmContext) (string, any, error) {
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
if !comm.TestPermission("Community.Write", ctxt.EffectiveLevel()) {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not permitted to access this page"))
|
||||
}
|
||||
ci, err := comm.ContactInfo()
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if ctxt.FormFieldIsSet("cancel") {
|
||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||
}
|
||||
if ctxt.FormFieldIsSet("upload") {
|
||||
file, err := ctxt.FormFile("thepic")
|
||||
if err == nil {
|
||||
var imageData []byte
|
||||
var mimeType string
|
||||
imageData, mimeType, err = ui.AmProcessUploadedImage(file, ui.CommunityLogoWidth, ui.CommunityLogoHeight,
|
||||
ui.CommunityLogoMaxBytes)
|
||||
if err == nil {
|
||||
var img *database.ImageStore
|
||||
img, err = database.AmStoreImage(database.ImageTypeCommunityLogo, comm.Id, mimeType, imageData)
|
||||
if err == nil {
|
||||
photourl := fmt.Sprintf("/img/store/%d", img.ImgId)
|
||||
ci.PhotoURL = &photourl
|
||||
_, err = ci.Save()
|
||||
if err == nil {
|
||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctxt.VarMap().Set("errorMessage", err.Error())
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("commAlias", comm.Alias)
|
||||
ctxt.VarMap().Set("logo_url", communityLogoURL(ci))
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Upload Community Logo: "+comm.Name)
|
||||
return "framed_template", "logo_upload.jet", nil
|
||||
}
|
||||
if ctxt.FormFieldIsSet("remove") {
|
||||
purl := ci.PhotoURL
|
||||
happy := false
|
||||
if purl == nil || *purl == "" {
|
||||
// this is a no-op
|
||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||
}
|
||||
if strings.HasPrefix(*purl, "/img/store/") {
|
||||
id, err := strconv.Atoi((*purl)[11:])
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
defer func() {
|
||||
if happy {
|
||||
go func() {
|
||||
err := database.AmDeleteImage(int32(id))
|
||||
if err != nil {
|
||||
log.Errorf("unable to delete image ID %d: %v", id, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
ci.PhotoURL = nil
|
||||
_, err := ci.Save()
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
happy = true
|
||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||
}
|
||||
return ui.ErrorPage(ctxt, errors.New("invalid button detected in logo upload"))
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ func setupEcho() *echo.Echo {
|
||||
e.GET("/comm/:cid/admin", ui.AmWrap(CommunityAdminMenu))
|
||||
e.GET("/comm/:cid/admin/profile", ui.AmWrap(CommunityProfileForm))
|
||||
e.POST("/comm/:cid/admin/profile", ui.AmWrap(EditCommunityProfile))
|
||||
e.GET("/comm/:cid/admin/logo", ui.AmWrap(CommunityLogoForm))
|
||||
e.POST("/comm/:cid/admin/logo", ui.AmWrap(EditCommunityLogo))
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ fields:
|
||||
- type: "communitylogo"
|
||||
name: "logo"
|
||||
caption: "Community logo"
|
||||
param: "/TODO/comm/[CID]/admin/logo"
|
||||
param: "/comm/[CID]/admin/logo"
|
||||
- type: "header"
|
||||
name: "header2"
|
||||
caption: "Location"
|
||||
|
||||
+6
-5
@@ -35,11 +35,12 @@ var static_images embed.FS
|
||||
|
||||
// Constants for default photo sizes.
|
||||
const (
|
||||
UserPhotoWidth = 100
|
||||
UserPhotoHeight = 100
|
||||
UserPhotoMaxBytes = 2097152 // 2 Mb
|
||||
CommunityLogoWidth = 110
|
||||
CommunityLogoHeight = 60
|
||||
UserPhotoWidth = 100
|
||||
UserPhotoHeight = 100
|
||||
UserPhotoMaxBytes = 2097152 // 2 Mb
|
||||
CommunityLogoWidth = 110
|
||||
CommunityLogoHeight = 60
|
||||
CommunityLogoMaxBytes = 2097152 // 2 Mb
|
||||
)
|
||||
|
||||
/* mimeTypeFromFilenane returns the MIME type of a file, given its filename.
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<!-- Left Column: Image and Metadata -->
|
||||
<div class="flex-shrink-0 w-32">
|
||||
<div class="border-2 border-gray-300 rounded mb-4">
|
||||
<img src="/img/builtin/default-community.jpg"
|
||||
alt="{{ commName}} community logo" class="w-full h-auto">
|
||||
<img src="{{ logoURL }}"
|
||||
alt="{{ commName }} community logo" class="w-full h-auto">
|
||||
</div>
|
||||
<div class="text-xs text-gray-700 space-y-2 mb-4">
|
||||
<div><strong>Community created:</strong><br>{{ dateCreated }}</div>
|
||||
|
||||
+2
-2
@@ -243,11 +243,11 @@
|
||||
{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }} (click to change):</label>
|
||||
<input type="hidden" name="{{ .Name }}_data" value="{{ .Value }}"/>
|
||||
{{ if .Disabled }}
|
||||
<img src="/img/builtin/default-community.jpg" class="w-28 h-16 rounded">
|
||||
<img src="{{ .Value }}" class="w-28 h-16 rounded">
|
||||
{{ else }}
|
||||
<a href="{{ .Param }}"
|
||||
class="border-2 border-gray-300 rounded hover:border-blue-500 transition-colors">
|
||||
<img src="/img/builtin/default-community.jpg" alt="Click to upload logo" class="w-28 h-16 rounded">
|
||||
<img src="{{ .Value }}" alt="Click to upload logo" class="w-28 h-16 rounded">
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
{*
|
||||
* 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 Community Logo:</h1>
|
||||
<span class="text-blue-800 text-2xl font-bold ml-2">{{ commName }}</span>
|
||||
<hr class="border-2 border-gray-400 w-4/5 mb-4">
|
||||
</div>
|
||||
|
||||
{{ if isset(errorMessage) }}
|
||||
<!-- Error Message Banner -->
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6" id="error-banner">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<span class="text-red-500 text-xl">⚠️</span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium" id="error-message">{{ CapitalizeString(errorMessage) }}.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Upload Form -->
|
||||
<form method="POST" enctype="multipart/form-data" action="/comm/{{ commAlias }}/admin/logo" class="max-w-2xl">
|
||||
<div class="bg-gray-50 p-6 rounded-lg">
|
||||
<div class="flex items-start gap-6">
|
||||
<!-- Current Logo -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="border-2 border-gray-300 rounded">
|
||||
<img src="{{ logo_url }}" alt="Current community logo" class="w-28 h-16 rounded">
|
||||
</div>
|
||||
<p class="text-xs text-gray-600 text-center mt-2">Current Logo</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 community logo:
|
||||
</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: 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 Logo
|
||||
</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">Logo Image Guidelines:</h3>
|
||||
<ul class="text-xs text-blue-800 space-y-1 list-disc list-inside">
|
||||
<li>Your logo 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 logo display</li>
|
||||
<li>You can update or remove the communiity logo at any time</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
Reference in New Issue
Block a user