landed Community Admin - Set Community Category

This commit is contained in:
2026-02-22 17:56:04 -07:00
parent ac22181a19
commit 59c1db1f27
8 changed files with 170 additions and 11 deletions
+57
View File
@@ -422,6 +422,63 @@ func CommunityAudit(ctxt ui.AmContext) (string, any) {
return "framed", "audit.jet"
}
/* CommunityCategory handles setting the community category.
* 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 CommunityCategory(ctxt ui.AmContext) (string, any) {
if ctxt.GlobalFlags().Get(database.GlobalFlagNoCategories) {
return "error", "This instance of Amsterdam does not use the categorization system."
}
comm := ctxt.CurrentCommunity()
if !comm.TestPermission("Community.Write", ctxt.EffectiveLevel()) {
return "error", ENOACCESS
}
if setId := ctxt.QueryParamInt("set", -1); setId >= 0 {
err := comm.SetCategory(ctxt.Ctx(), int32(setId), ctxt.CurrentUser(), ctxt.RemoteIP())
if err != nil {
return "error", err
}
return "redirect", fmt.Sprintf("/comm/%s/admin", comm.Alias)
}
currentCat, err := database.AmGetCategory(ctxt.Ctx(), comm.CategoryId)
if err != nil {
return "error", err
}
displayId := ctxt.QueryParamInt("d", int(comm.CategoryId))
var newCat []*database.Category
if displayId >= 0 {
newCat, err = database.AmGetCategoryHierarchy(ctxt.Ctx(), int32(displayId))
if err != nil {
return "error", err
}
} else {
newCat = make([]*database.Category, 0)
}
subCats, err := database.AmGetSubCategories(ctxt.Ctx(), int32(displayId))
if err != nil {
return "error", err
}
ctxt.VarMap().Set("commName", comm.Name)
ctxt.VarMap().Set("oldCat", currentCat)
ctxt.VarMap().Set("newCat", newCat)
ctxt.VarMap().Set("newCatId", displayId)
ctxt.VarMap().Set("subCats", subCats)
ctxt.VarMap().Set("backLink", fmt.Sprintf("/comm/%s/admin", comm.Alias))
ctxt.VarMap().Set("selfLink", fmt.Sprintf("/comm/%s/admin/category", comm.Alias))
ctxt.SetFrameTitle("Set Community Category")
return "framed", "comm_category.jet"
}
/* CreateCommunityForm renders the form for creating a new community.
* Parameters:
* ctxt - The AmContext for the request.
+2 -5
View File
@@ -143,11 +143,8 @@ func AmGetCategoryHierarchy(ctx context.Context, catid int32) ([]*Category, erro
p = c.Parent
}
// reverse the array for return
rc := make([]*Category, 0, len(ia))
for i := range ia {
rc = append(rc, ia[len(ia)-(i+1)])
}
return rc, nil
slices.Reverse(ia)
return ia, nil
}
/* AmGetSubCategories returns a list of all subcategories of the given category ID.
+14
View File
@@ -461,6 +461,20 @@ func (c *Community) SaveFlags(ctx context.Context, f *util.OptionSet) error {
return err
}
// SetCategory sets the community's category ID.
func (c *Community) SetCategory(ctx context.Context, catId int32, u *User, ipaddr string) error {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, err := amdb.ExecContext(ctx, "UPDATE communities SET catid = ? WHERE commid = ?", catId, c.Id)
if err == nil {
if catId != c.CategoryId {
AmStoreAudit(AmNewCommAudit(AuditCommunityCategory, u.Uid, c.Id, ipaddr, fmt.Sprintf("catid=%d", catId)))
}
c.CategoryId = catId
}
return err
}
// SetProfileData sets all the "settable" profile data
func (c *Community) SetProfileData(ctx context.Context, name string, alias string, synopsis *string, rules *string, language *string,
joinkey *string, membersonly bool, hideDirectory bool, hideSearch bool, read_lvl uint16, write_lvl uint16,
+1 -1
View File
@@ -24,7 +24,7 @@ _(italicized items can be deferred)_
- ~~Create New~~
- ~~Conferences List honor "hide in list" flag~~
- Community Admin Menu:
- Set Community Category
- ~~Set Community Category~~
- Membership Control
- E-Mail to All Members
- ~~Display Audit Records~~
+1
View File
@@ -116,6 +116,7 @@ func setupEcho() *echo.Echo {
commGroup.GET("/admin/logo", ui.AmWrap(CommunityLogoForm))
commGroup.POST("/admin/logo", ui.AmWrap(EditCommunityLogo))
commGroup.Match(GetAndPost, "/admin/audit", ui.AmWrap(CommunityAudit))
commGroup.GET("/admin/category", ui.AmWrap(CommunityCategory))
// conference group
commGroup.GET("/create_conf", ui.AmWrap(CreateConferenceForm))
+2 -2
View File
@@ -53,7 +53,7 @@ menudefs:
link: "/TODO/sysadmin/import"
permission: "Global.SysAdminAccess"
- id: "communityadmin"
title: "Community Administration"
title: "Community Administration:"
subtitle: "[CNAME]"
permSet: "community"
warning: >
@@ -64,7 +64,7 @@ menudefs:
link: "/comm/[CID]/admin/profile"
permission: "Community.Write"
- text: "Set Community Category"
link: "/TODO/comm/[CID]/admin/category"
link: "/comm/[CID]/admin/category"
permission: "Community.Write"
ifdef: "USECAT"
- text: "Set Community Services"
+86
View File
@@ -0,0 +1,86 @@
{*
* Amsterdam Web Communities System
* 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
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*}
<div class="p-4">
<!-- Page Title -->
<div class="mb-6">
<div class="flex items-baseline gap-3 mb-2">
<h1 class="text-blue-800 text-4xl font-bold">Set Community Category:</h1>
<h2 class="text-blue-800 text-2xl font-bold">{{ commName }}</h2>
</div>
<hr class="border-2 border-gray-400 w-4/5 mb-6">
</div>
<!-- Backlink -->
<div class="mb-6">
<a href="{{ backLink }}"
class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded text-sm font-medium transition-colors">
Cancel
</a>
</div>
<div class="mb-6">
<div class="text-sm text-black"><b>Previous community category:</b> {{ oldCat.Name }}</div>
</div>
<div class="mb-6">
<div class="text-sm text-black font-bold">Current category:</div>
<div class="text-sm text-black">
{{ if len(newCat) == 0 }}
<span class="text-sm">Top</span>
{{ else }}
<span class="text-sm font-bold"><a class="text-blue-700 hover:text-blue-900" href="{{ selfLink }}?d=-1">Top</a>:</span>
{{ range i, c := newCat }}
{{ if i == (len(newCat) - 1) }}
<span class="text-sm">{{ c.Name }}</span>
{{ else }}
<span class="text-sm font-bold"><a class="text-blue-700 hover:text-blue-900" href="{{ selfLink }}?d={{ c.CatId }}">{{ c.Name }}</a>:</span>
{{ end }}
{{ end }}
{{ if oldCat.CatId != newCatId }}
<span class="text-lg"><a href="{{ selfLink }}?set={{ newCatId }}" title="Set Category">*️⃣</a></span>
{{ end }}
{{ end }}
</div>
</div>
<div class="mb-6">
<div class="text-sm text-black font-bold">Subcategories:</div>
{{ if len(subCats) == 0 }}
<div class="text-sm text-black italic">(None)</div>
{{ else }}
<table class="border-none">
<tbody>
{{ range i, c := subCats }}
<tr>
<td class="px-2 py-1">
<span class="text-sm pt-0.5">🟣</span>
<a class="text-blue-700 hover:text-blue-900 font-bold" href="{{ selfLink }}?d={{ c.CatId }}">{{ c.Name }}</a>
</td>
<td class="px-2 py-1">
{{ if c.CatId != oldCat.CatId }}
<span class="text-lg"><a href="{{ selfLink }}?set={{ c.CatId }}" title="Set Category">*️⃣</a></span>
{{ else }}
&nbsp;
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
</div>
<!-- Information Note -->
<div class="mt-6 p-4 bg-blue-50 border-l-4 border-blue-400">
<p class="text-base text-gray-700 font-bold">Changing the Community's Category:</p>
<p class="text-sm text-gray-700">Click on a subcategory name to make that category the currently-displayed one.</p>
<p class="text-sm text-gray-700">Click on a *️⃣ icon to set that category as the community's new category and return to the <b>Community Administration</b> menu.</p>
</div>
</div>
+7 -3
View File
@@ -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
@@ -9,9 +9,13 @@
<div class="p-4">
<!-- Page Title -->
<div class="mb-6">
<h1 class="text-blue-800 text-4xl font-bold mb-2">{{ menu.Title }}</h1>
{{ if menu.Subtitle != "" }}
<span class="text-blue-800 text-2xl font-bold ml-2">{{ menu.Subtitle }}</span>
<div class="flex items-baseline gap-3 mb-2">
<h1 class="text-blue-800 text-4xl font-bold">{{ menu.Title }}</h1>
<h2 class="text-blue-800 text-2xl font-bold">{{ menu.Subtitle }}</h2>
</div>
{{ else }}
<h1 class="text-blue-800 text-4xl font-bold mb-2">{{ menu.Title }}</h1>
{{ end }}
<hr class="border-2 border-gray-400 w-4/5 mb-4">
</div>