display of "manage conference list" page
This commit is contained in:
+6
-3
@@ -40,15 +40,18 @@ func Conferences(ctxt ui.AmContext) (string, any) {
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("commAlias", comm.Alias)
|
||||
ctxt.SetFrameTitle("Conference Listing: " + comm.Name)
|
||||
clist, err := database.AmGetCommunityConferences(ctxt.Ctx(), comm.Id,
|
||||
comm.TestPermission("Community.ShowHiddenObjects", ctxt.EffectiveLevel()))
|
||||
clist, err := database.AmListConferences(ctxt.Ctx(), comm.Id, comm.TestPermission("Community.ShowHiddenObjects", ctxt.EffectiveLevel()))
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
ctxt.VarMap().Set("conferences", clist)
|
||||
if len(clist) > 0 {
|
||||
newflag := make([]bool, len(clist))
|
||||
for i, conf := range clist {
|
||||
for i, c := range clist {
|
||||
conf, err := c.Conf(ctxt.Ctx())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
msgCount, err := conf.UnreadMessages(ctxt.Ctx(), ctxt.CurrentUser())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
|
||||
@@ -789,3 +789,43 @@ func CreateConference(ctxt ui.AmContext) (string, any) {
|
||||
log.Infof("Created conference '%s'", conf.Name)
|
||||
return "redirect", fmt.Sprintf("/comm/%s/conf/%s", comm.Alias, alias)
|
||||
}
|
||||
|
||||
/* ManageConferenceList displays the list for managing conferences.
|
||||
* Parameters:
|
||||
* ctxt - The AmContext for the request.
|
||||
* Returns:
|
||||
* Command string dictating what to be rendered.
|
||||
* Data as a parameter for the command string.
|
||||
*/
|
||||
func ManageConferenceList(ctxt ui.AmContext) (string, any) {
|
||||
comm := ctxt.CurrentCommunity()
|
||||
if !comm.TestPermission("Community.Create", ctxt.EffectiveLevel()) {
|
||||
return "error", ENOPERM
|
||||
}
|
||||
|
||||
clist, err := database.AmListConferences(ctxt.Ctx(), comm.Id, true)
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
|
||||
ntopics := make([]int, len(clist))
|
||||
nposts := make([]int, len(clist))
|
||||
for i, c := range clist {
|
||||
conf, err := c.Conf(ctxt.Ctx())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
ntopics[i], nposts[i], err = conf.Stats(ctxt.Ctx())
|
||||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
}
|
||||
ctxt.VarMap().Set("confs", clist)
|
||||
ctxt.VarMap().Set("ntopics", ntopics)
|
||||
ctxt.VarMap().Set("nposts", nposts)
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("baseUrl", fmt.Sprintf("/comm/%s/manage_conf", comm.Alias))
|
||||
ctxt.VarMap().Set("returnUrl", fmt.Sprintf("/comm/%s/conf", comm.Alias))
|
||||
ctxt.SetFrameTitle("Manage Conference List")
|
||||
return "framed", "manage_conflist.jet"
|
||||
}
|
||||
|
||||
+47
-14
@@ -70,6 +70,23 @@ type ConferenceProperties struct {
|
||||
Data *string `db:"data"` // property data
|
||||
}
|
||||
|
||||
// ConferenceSummary represents summary information about a conference.
|
||||
type ConferenceSummary struct {
|
||||
ConfId int32 // conference ID
|
||||
Name string // conference name
|
||||
Alias string // an alias for the conference
|
||||
LastUpdate *time.Time // last update date/time
|
||||
Hosts []string // usernames of the hosts
|
||||
Description string // description string
|
||||
Sequence int16 // sequence number in the list
|
||||
Hidden bool // hidden in list?
|
||||
}
|
||||
|
||||
// Conf gets the conference from the summary.
|
||||
func (cs *ConferenceSummary) Conf(ctx context.Context) (*Conference, error) {
|
||||
return AmGetConference(ctx, cs.ConfId)
|
||||
}
|
||||
|
||||
// Default spacing between sequence numbers in commtoconf table.
|
||||
const COMMTOCONF_SEQ_SPACING = 10
|
||||
|
||||
@@ -786,6 +803,15 @@ func (c *Conference) GetActiveUserEMailAddrs(ctx context.Context, userSelect, da
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// Stats retrieves the number of topics and posts in this conference.
|
||||
func (c *Conference) Stats(ctx context.Context) (int, int, error) {
|
||||
row := amdb.QueryRowContext(ctx, "SELECT COUNT(*), SUM(top_message + 1) FROM topics WHERE confid = ?", c.ConfId)
|
||||
ntopic := 0
|
||||
npost := 0
|
||||
err := row.Scan(&ntopic, &npost)
|
||||
return ntopic, npost, err
|
||||
}
|
||||
|
||||
/* AmGetConference returns a conference given its ID.
|
||||
* Parameters:
|
||||
* ctx - Standard Go context value.
|
||||
@@ -864,37 +890,44 @@ func AmGetConferenceByAliasInCommunity(ctx context.Context, cid int32, alias str
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* AmGetCommunityConferences returns all conferences for a given community.
|
||||
/* AmListConferences returns all conferences for a given community.
|
||||
* Parameters:
|
||||
* ctx - Standard Go context value.
|
||||
* cid - Community ID to get conferences for.
|
||||
* showHidden - true to show hidden conferences.
|
||||
* Returns:
|
||||
* Array containing the COnference pointers, or nil.
|
||||
* Array containing the ConferenceSummary pointers, or nil.
|
||||
* Stanbard Go error status.
|
||||
*/
|
||||
func AmGetCommunityConferences(ctx context.Context, cid int32, showHidden bool) ([]*Conference, error) {
|
||||
func AmListConferences(ctx context.Context, cid int32, showHidden bool) ([]*ConferenceSummary, error) {
|
||||
q := ""
|
||||
if !showHidden {
|
||||
q = " AND x.hide_list = 0"
|
||||
}
|
||||
rs, err := amdb.QueryContext(ctx, `SELECT x.confid FROM commtoconf x, confs c WHERE x.confid = c.confid
|
||||
AND x.commid = ?`+q+" ORDER BY x.sequence, c.name", cid)
|
||||
rs, err := amdb.QueryContext(ctx, `SELECT x.confid, c.name, c.lastupdate, c.descr, x.sequence, x.hide_list FROM commtoconf x, confs c
|
||||
WHERE x.confid = c.confid AND x.commid = ?`+q+" ORDER BY x.sequence, c.name", cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc := make([]*Conference, 0, 6)
|
||||
rc := make([]*ConferenceSummary, 0)
|
||||
for rs.Next() {
|
||||
var confid int32
|
||||
if err = rs.Scan(&confid); err == nil {
|
||||
conf, err := AmGetConference(ctx, confid)
|
||||
if err == nil {
|
||||
rc = append(rc, conf)
|
||||
var cs ConferenceSummary
|
||||
if err = rs.Scan(&(cs.ConfId), &(cs.Name), &(cs.LastUpdate), &(cs.Description), &(cs.Sequence), &(cs.Hidden)); err == nil {
|
||||
rc = append(rc, &cs)
|
||||
} else {
|
||||
log.Errorf("AmGetCommunityConferences conference error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
log.Errorf("AmGetCommunityConferences scan error: %v", err)
|
||||
}
|
||||
for i := range rc {
|
||||
row := amdb.QueryRowContext(ctx, "SELECT alias FROM confalias WHERE confid = ?", rc[i].ConfId)
|
||||
err = row.Scan(&(rc[i].Alias))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = amdb.SelectContext(ctx, &(rc[i].Hosts), `SELECT u.username FROM confmember m, users u WHERE u.uid = m.uid AND m.confid = ?
|
||||
AND m.granted_lvl = ? ORDER BY u.username`, rc[i].ConfId, AmRole("Conference.Host").Level())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return rc, nil
|
||||
|
||||
@@ -117,6 +117,7 @@ func setupEcho() *echo.Echo {
|
||||
// conference group
|
||||
commGroup.GET("/create_conf", ui.AmWrap(CreateConferenceForm))
|
||||
commGroup.POST("/create_conf", ui.AmWrap(CreateConference))
|
||||
commGroup.GET("/manage_conf", ui.AmWrap(ManageConferenceList))
|
||||
commGroup.GET("/conf", ui.AmWrap(Conferences), ui.ValidateConference)
|
||||
confGroup := commGroup.Group("/conf/:confid", ui.ValidateConference, ui.SetConference)
|
||||
confGroup.GET("", ui.AmWrap(Topics))
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<span class="text-lg pt-0.5 flex-shrink-0">🟣</span>
|
||||
<div class="flex-1">
|
||||
<div class="mb-2">
|
||||
<a href="/comm/{{ commAlias }}/conf/{{ c.AliasesQ(.Ctx())[0] }}"
|
||||
<a href="/comm/{{ commAlias }}/conf/{{ c.Alias }}"
|
||||
class="text-blue-700 hover:text-blue-900 font-bold text-lg">{{ c.Name }}</a>
|
||||
<span class="text-gray-600 text-sm ml-2">- Latest activity: {{ DisplayActivity(c.LastUpdate, .) }}</span>
|
||||
{{ if newflag[i] }}
|
||||
@@ -31,16 +31,15 @@
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-700 mb-1">
|
||||
{{ hl := c.HostsQ(.Ctx()) }}
|
||||
{{ if len(hl) == 1 }}
|
||||
{{ if len(c.Hosts) == 1 }}
|
||||
<span class="font-medium">Host:</span>
|
||||
{{ else }}
|
||||
<span class="font-medium">Hosts:</span>
|
||||
{{ end }}
|
||||
{{ if len(hl) > 0 }}
|
||||
{{ range j, u := hl }}
|
||||
{{ if len(c.Hosts) > 0 }}
|
||||
{{ range j, u := c.Hosts }}
|
||||
{{ if j > 0 }}, {{ end }}
|
||||
<a href="/users/{{ u.Username }}" class="text-blue-700 hover:text-blue-900">{{ u.Username }}</a>
|
||||
<a href="/users/{{ u }}" class="text-blue-700 hover:text-blue-900">{{ u }}</a>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
None
|
||||
@@ -60,7 +59,7 @@
|
||||
Find Posts
|
||||
</a>
|
||||
{{ if canManage }}
|
||||
<a href="TODO"
|
||||
<a href="/comm/{{ commAlias }}/manage_conf"
|
||||
class="inline-block bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded font-medium transition-colors">
|
||||
Manage
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
{*
|
||||
* 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">
|
||||
<!-- Top Title -->
|
||||
<div class="mb-2">
|
||||
<div class="flex items-baseline gap-3 mb-2">
|
||||
<h1 class="text-blue-800 text-4xl font-bold">Manage Conference List</h1>
|
||||
<h2 class="text-blue-800 text-2xl font-bold">Community: {{ commName }}</h2>
|
||||
</div>
|
||||
<hr class="border-2 border-gray-400 w-4/5 mt-2 mb-6">
|
||||
</div>
|
||||
|
||||
<!-- Backlink -->
|
||||
<div class="mb-4">
|
||||
<a class="text-blue-700 hover:text-blue-900 text-sm flex items-center gap-2 w-fit" href="{{ returnUrl }}">
|
||||
<span>←</span>
|
||||
Return to Conference List
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Conference Table -->
|
||||
<div class="max-w-4xl mb-8">
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
{{ if len(confs) > 0 }}
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-100 border-b-2 border-gray-300">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-center text-xs font-bold text-gray-700 uppercase tracking-wider w-20" colspan="4"> </th>
|
||||
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Conference Name</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Topics</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Posts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
{{ range i, c := confs }}
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center w-12">
|
||||
{{ if c.Hidden }}
|
||||
<a href="{{ baseUrl }}?t={{ c.ConfId }}" class="inline-block text-3xl hover:scale-110 transition-transform"
|
||||
title="Click to display">
|
||||
⚫
|
||||
</a>
|
||||
{{ else }}
|
||||
<a href="{{ baseUrl }}?t={{ c.ConfId }}" class="inline-block text-3xl hover:scale-110 transition-transform"
|
||||
title="Click to hide">
|
||||
🟢
|
||||
</a>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center w-12">
|
||||
{{ if i < (len(confs) - 1) }}
|
||||
<a href="{{ baseUrl }}?m={{ i }}&n=1" class="text-2xl hover:scale-125 inline-block transition-transform"
|
||||
title="Move Down">⬇️</a>
|
||||
{{ else }}
|
||||
<span class="text-2xl text-gray-300"> </span>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center w-12">
|
||||
{{ if i > 0 }}
|
||||
<a href="{{ baseUrl }}?m={{ i }}&n=-1" class="text-2xl hover:scale-125 inline-block transition-transform"
|
||||
title="Move Up">⬆️</a>
|
||||
{{ else }}
|
||||
<span class="text-2xl text-gray-300"> </span>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center w-12">
|
||||
<a href="/TODO" class="text-2xl hover:scale-125 inline-block transition-transform"
|
||||
title="Delete Conference">❌</a>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
<div class="font-bold text-black">{{ c.Name }}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
<div class="text-black">{{ ntopics[i] }}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm">
|
||||
<div class="text-black">{{ nposts[i] }}</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ else }}
|
||||
<span class="text-gray-800"><i>No conferences in this community.</i></span>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Legend -->
|
||||
<div class="max-w-4xl mb-6">
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<h2 class="text-blue-800 font-bold text-lg mb-3">How to update the community's conference list:</h2>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl">🟢</span>
|
||||
<span class="text-gray-700">This indicates that the conference is displayed in the community's conference list. Click the symbol to hide it.</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl">⚫</span>
|
||||
<span class="text-gray-700">This indicates that the conference is hidden in the community's conference list. Click the symbol to display it.</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl">⬇️</span>
|
||||
<span class="text-gray-700">Click this symbol to move the specified conference down in the community's conference list.</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl">⬆️</span>
|
||||
<span class="text-gray-700">Click this symbol to move the specified conference up in the community's conference list.</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl">❌</span>
|
||||
<span class="text-gray-700">Click this symbol to delete the specified conference. You will be prompted to confirm this action.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user