Landed conference list page - still needs some work (doesn't crash, but some display info is incorrect)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
// Package main contains the high-level Amsterdam logic.
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
"git.erbosoft.com/amy/amsterdam/ui"
|
||||
)
|
||||
|
||||
// conferencesPrequel consolidates some of the basic conference checks into one function.
|
||||
func conferencesPrequel(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()
|
||||
b, err := database.AmTestService(comm, "Conference")
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if !b {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, errors.New("this community does not use conferencing services"))
|
||||
}
|
||||
if comm.MembersOnly && !ctxt.IsMember() {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not a member of this community"))
|
||||
}
|
||||
if !comm.TestPermission("Community.Read", ctxt.EffectiveLevel()) {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not authorized access to conferences"))
|
||||
}
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
/* Conferences displayes the list of conferences in a community.
|
||||
* 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 Conferences(ctxt ui.AmContext) (string, any, error) {
|
||||
cmd, arg, err := conferencesPrequel(ctxt)
|
||||
if cmd != "" {
|
||||
return cmd, arg, err
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("commAlias", comm.Alias)
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Conference Listing: "+comm.Name)
|
||||
clist, err := database.AmGetCommunityConferences(comm.Id,
|
||||
comm.TestPermission("Community.ShowHiddenObjects", ctxt.EffectiveLevel()))
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
ctxt.VarMap().Set("conferences", clist)
|
||||
return "framed_template", "conflist.jet", err
|
||||
}
|
||||
+92
-2
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
// Conference struct is the top-level structure for a conference.
|
||||
type Conference struct {
|
||||
Mutex sync.Mutex
|
||||
ConfId int32 `db:"confid"`
|
||||
CreateDate time.Time `db:"createdate"`
|
||||
LastUpdate *time.Time `db:"lastupdate"`
|
||||
@@ -27,8 +28,8 @@ type Conference struct {
|
||||
CreateLevel uint16 `db:"create_lvl"`
|
||||
HideLevel uint16 `db:"hide_lvl"`
|
||||
NukeLevel uint16 `db:"nuke_lvl"`
|
||||
ChangeLevel uint16 `db:"change_level"`
|
||||
DeleteLevel uint16 `db:"delete_level"`
|
||||
ChangeLevel uint16 `db:"change_lvl"`
|
||||
DeleteLevel uint16 `db:"delete_lvl"`
|
||||
TopTopic int16 `db:"top_topic"`
|
||||
Name string `db:"name"`
|
||||
Description *string `db:"descr"`
|
||||
@@ -54,6 +55,95 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// Aliases returns the list of aliases for this conference.
|
||||
func (c *Conference) Aliases() ([]string, error) {
|
||||
rs, err := amdb.Query("SELECT alias FROM confalias WHERE confid = ? ORDER BY alias", c.ConfId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc := make([]string, 0, 5)
|
||||
for rs.Next() {
|
||||
var a string
|
||||
rs.Scan(&a)
|
||||
rc = append(rc, a)
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// AliasesQ returns the list of aliases for this conference, quietly.
|
||||
func (c *Conference) AliasesQ() []string {
|
||||
rc, _ := c.Aliases()
|
||||
return rc
|
||||
}
|
||||
|
||||
// Hosts returns the list of users that host this conference.
|
||||
func (c *Conference) Hosts() ([]*User, error) {
|
||||
rs, err := amdb.Query("SELECT uid FROM confmember WHERE confid = ? AND granted_lvl = ?",
|
||||
c.ConfId, AmRole("Conference.Host").Level())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc := make([]*User, 0, 5)
|
||||
for rs.Next() {
|
||||
var uid int32
|
||||
rs.Scan(&uid)
|
||||
u, err := AmGetUser(uid)
|
||||
if err == nil {
|
||||
rc = append(rc, u)
|
||||
}
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// Hosts returns the list of users that host this conference, quietly.
|
||||
func (c *Conference) HostsQ() []*User {
|
||||
rc, _ := c.Hosts()
|
||||
return rc
|
||||
}
|
||||
|
||||
// Membership returns a membership flag and granted level for the user in this conference.
|
||||
func (c *Conference) Membership(u *User) (bool, uint16, error) {
|
||||
rs, err := amdb.Query("SELECT granted_lvl FROM confmember WHERE confid = ? AND uid = ?", c.ConfId, u.Uid)
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
if rs.Next() {
|
||||
var level uint16
|
||||
rs.Scan(&level)
|
||||
return true, level, nil
|
||||
}
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
/* TestPermission is shorthand that tests if a user has a permission with respect to the conference.
|
||||
* Parameters:
|
||||
* user - The user to be checked.
|
||||
* perm - The permission to be tested.
|
||||
* Returns:
|
||||
* true if the user has the permission, false if not.
|
||||
* Standard Go error status.
|
||||
*/
|
||||
func (c *Conference) TestPermission(perm string, level uint16) bool {
|
||||
switch perm {
|
||||
case "Conference.Read":
|
||||
return level >= c.ReadLevel
|
||||
case "Conference.Post":
|
||||
return level >= c.PostLevel
|
||||
case "Conference.Create":
|
||||
return level >= c.CreateLevel
|
||||
case "Conference.Hide":
|
||||
return level >= c.HideLevel
|
||||
case "Conference.Nuke":
|
||||
return level >= c.NukeLevel
|
||||
case "Conference.Change":
|
||||
return level >= c.ChangeLevel
|
||||
case "Conference.Delete":
|
||||
return level >= c.DeleteLevel
|
||||
default:
|
||||
return AmTestPermission(perm, level)
|
||||
}
|
||||
}
|
||||
|
||||
/* AmGetConference returns a conference given its ID.
|
||||
* Parameters:
|
||||
* id - The ID of the conference.
|
||||
|
||||
@@ -43,7 +43,7 @@ domains:
|
||||
requirePermission: "Community.Read"
|
||||
requireRole: ""
|
||||
linkSequence: 500
|
||||
link: "/TODO/comm/[CID]/conf"
|
||||
link: "/comm/[CID]/conf"
|
||||
title: "Conferences"
|
||||
- id: "Members"
|
||||
index: 4
|
||||
|
||||
@@ -246,3 +246,15 @@ func AmOnUserLeaveCommunityServices(c *Community, u *User) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AmTestService(c *Community, serviceId string) (bool, error) {
|
||||
arr, err := AmGetCommunityServices(c.Id)
|
||||
if err == nil {
|
||||
for _, svc := range arr {
|
||||
if svc.Id == serviceId {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ func setupEcho() *echo.Echo {
|
||||
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))
|
||||
e.GET("/comm/:cid/conf", ui.AmWrap(Conferences))
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
{*
|
||||
* 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/.
|
||||
*}
|
||||
<div class="p-4">
|
||||
<!-- Page Title -->
|
||||
<div class="mb-6">
|
||||
<h1 class="text-blue-800 text-4xl font-bold inline">Conference List:</h1>
|
||||
<span class="text-blue-800 text-2xl font-bold ml-2">{{ commName }}</span>
|
||||
<hr class="border-2 border-gray-400 w-4/5 mt-2 mb-6">
|
||||
</div>
|
||||
|
||||
<!-- Conference Listing -->
|
||||
<div class="max-w-4xl">
|
||||
<div class="bg-gray-50 p-6 rounded-lg mb-6">
|
||||
<div class="space-y-6">
|
||||
{{ range _, c := conferences }}
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-lg pt-0.5 flex-shrink-0">🟣</span>
|
||||
<div class="flex-1">
|
||||
<div class="mb-2">
|
||||
<a href="/TODO/comm/{{ commAlias }}/conf/{{ c.AliasesQ()[0] }}"
|
||||
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>
|
||||
</div>
|
||||
<div class="text-sm text-gray-700 mb-1">
|
||||
{{ hl := c.HostsQ() }}
|
||||
{{ if len(hl) == 1 }}
|
||||
<span class="font-medium">Host:</span>
|
||||
{{ else }}
|
||||
<span class="font-medium">Hosts:</span>
|
||||
{{ end }}
|
||||
{{ if len(hl) > 0 }}
|
||||
{{ range i, u := hl }}
|
||||
{{ if i > 0 }}, {{ end }}
|
||||
<a href="/users/{{ u.Username }}" class="text-blue-700 hover:text-blue-900">{{ u.Username }}</a>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
None
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="italic text-gray-600 text-sm">{{ c.Description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4">
|
||||
<a href="/find?mode=PST"
|
||||
class="inline-block bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded font-medium transition-colors">
|
||||
Find Posts
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Information Note -->
|
||||
<div class="mt-6 p-4 bg-blue-50 border-l-4 border-blue-400">
|
||||
<p class="text-sm text-gray-700">
|
||||
<strong>About Conferences:</strong> Conferences are discussion areas within this community.
|
||||
Click on a conference name to view topics and participate in discussions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user