landed community join and unjoin functionality
This commit is contained in:
+166
@@ -10,6 +10,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -62,6 +64,7 @@ func ShowCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
}
|
||||
|
||||
ctxt.VarMap().Set("commName", comm.Name)
|
||||
ctxt.VarMap().Set("commAlias", comm.Alias)
|
||||
if ci.PhotoURL != nil && *ci.PhotoURL != "" {
|
||||
ctxt.VarMap().Set("logoURL", *ci.PhotoURL)
|
||||
} else {
|
||||
@@ -132,3 +135,166 @@ func ShowCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Community Profile: "+comm.Name)
|
||||
return "framed_template", "comprofile.jet", nil
|
||||
}
|
||||
|
||||
/* JoinCommunity joins a public community, or starts the process of joining a private one.
|
||||
* 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 JoinCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
me := ctxt.CurrentUser()
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
ctxt.SetLeftMenu("community")
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
mbr, _, _, err := comm.Membership(me)
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if mbr {
|
||||
// already member, this is a no-op
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if comm.TestPermission("Community.Join", me.BaseLevel) {
|
||||
if comm.JoinKey != nil && *comm.JoinKey != "" {
|
||||
dlg, err := ui.AmLoadDialog("join")
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
dlg.SetCommunity(comm)
|
||||
dlg.Field("cc").Value = comm.Alias
|
||||
return dlg.Render(ctxt)
|
||||
}
|
||||
// if get here, this is a public community, and we can join
|
||||
err = comm.SetMembership(me, database.AmDefaultRole("Community.NewUser").Level(), false, me.Uid, ctxt.RemoteIP())
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
} else {
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not permitted to join this community"))
|
||||
}
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
|
||||
/* JoinCommunityWithKey joins a private community with a properly specified join key.
|
||||
* 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 JoinCommunityWithKey(ctxt ui.AmContext) (string, any, error) {
|
||||
me := ctxt.CurrentUser()
|
||||
err := ctxt.SetCommunityContext(ctxt.FormField("cc"))
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
ctxt.SetLeftMenu("community")
|
||||
mbr, _, _, err := comm.Membership(me)
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if mbr {
|
||||
// already member, this is a no-op
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if comm.TestPermission("Community.Join", me.BaseLevel) {
|
||||
dlg, err := ui.AmLoadDialog("join")
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
dlg.SetCommunity(comm)
|
||||
dlg.LoadFromForm(ctxt)
|
||||
action := dlg.WhichButton(ctxt)
|
||||
if action == "cancel" {
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if action == "join_now" {
|
||||
key := dlg.Field("key").Value
|
||||
dlg.Field("key").Value = "" // clear it in case we redisplay the form
|
||||
if key == "" {
|
||||
return dlg.RenderError(ctxt, "No join key specified. Please try again.")
|
||||
}
|
||||
if comm.JoinKey != nil && key != *comm.JoinKey {
|
||||
return dlg.RenderError(ctxt, "The join key does not match the community. Please try again.")
|
||||
}
|
||||
err = comm.SetMembership(me, database.AmDefaultRole("Community.NewUser").Level(), false, me.Uid, ctxt.RemoteIP())
|
||||
if err != nil {
|
||||
return dlg.RenderError(ctxt, fmt.Sprintf("Error joining: %v", err))
|
||||
}
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
return dlg.RenderError(ctxt, "Unknown button pressed on join form.")
|
||||
}
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
|
||||
func UnjoinCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
me := ctxt.CurrentUser()
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
ctxt.SetLeftMenu("community")
|
||||
mbr, lock, _, err := comm.Membership(me)
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if !mbr {
|
||||
// not a member, just redirect to profile
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if lock {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not permitted to unjoin this community"))
|
||||
}
|
||||
ctxt.VarMap().Set("comm", comm)
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Unjoin Community")
|
||||
return "framed_template", "unjoin.jet", nil
|
||||
}
|
||||
|
||||
func UnjoinCommunityConfirm(ctxt ui.AmContext) (string, any, error) {
|
||||
me := ctxt.CurrentUser()
|
||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||
if err != nil {
|
||||
ctxt.SetRC(http.StatusNotFound)
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
comm := ctxt.CurrentCommunity()
|
||||
ctxt.SetLeftMenu("community")
|
||||
mbr, lock, _, err := comm.Membership(me)
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
if !mbr {
|
||||
// not a member, just redirect to profile
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if lock {
|
||||
ctxt.SetRC(http.StatusForbidden)
|
||||
return ui.ErrorPage(ctxt, errors.New("you are not permitted to unjoin this community"))
|
||||
}
|
||||
if ctxt.FormFieldIsSet("cancel") {
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
if ctxt.FormFieldIsSet("unjoin") {
|
||||
err = comm.SetMembership(me, 0, false, me.Uid, ctxt.RemoteIP())
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
ctxt.ClearCommunityContext()
|
||||
return "redirect", fmt.Sprintf("/comm/%s/profile", comm.Alias), nil
|
||||
}
|
||||
return ui.ErrorPage(ctxt, errors.New("unknown button pressed to confirm unjoin"))
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ func (c *Community) SetMembership(u *User, level uint16, locked bool, personUID
|
||||
stuffMembership(c.Id, u.Uid, true, locked, level)
|
||||
}
|
||||
} else {
|
||||
_, err := amdb.Exec("INSERT INTO commmember (comm_id, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
|
||||
_, err := amdb.Exec("INSERT INTO commmember (commid, uid, granted_lvl, locked) VALUES (?, ?, ?, ?)",
|
||||
c.Id, u.Uid, level, locked)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -72,6 +72,10 @@ func setupEcho() *echo.Echo {
|
||||
e.GET("/create_comm", ui.AmWrap(CreateCommunityForm))
|
||||
e.POST("/create_comm", ui.AmWrap(CreateCommunity))
|
||||
e.GET("/comm/:cid/profile", ui.AmWrap(ShowCommunity))
|
||||
e.GET("/comm/:cid/join", ui.AmWrap(JoinCommunity))
|
||||
e.POST("/comm/:cid/join", ui.AmWrap(JoinCommunityWithKey))
|
||||
e.GET("/comm/:cid/unjoin", ui.AmWrap(UnjoinCommunity))
|
||||
e.POST("/comm/:cid/unjoin", ui.AmWrap(UnjoinCommunityConfirm))
|
||||
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))
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# 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/.
|
||||
#
|
||||
name: "join"
|
||||
formName: "joinkeyform"
|
||||
menuSelector: "community"
|
||||
title: "Join Community"
|
||||
subtitle: "[CNAME]"
|
||||
action: "/comm/[CID]/join"
|
||||
instructions: >
|
||||
You must specify a join key before you can join this community. You might have received the join key from
|
||||
the community's host, or via an invitation e-mail message. Please enter it in the box below.
|
||||
fields:
|
||||
- type: "hidden"
|
||||
name: "cc"
|
||||
value: ""
|
||||
- type: "text"
|
||||
name: "key"
|
||||
caption: "Join Key"
|
||||
size: 32
|
||||
maxLength: 64
|
||||
- type: "button"
|
||||
name: "join_now"
|
||||
caption: "Join Now"
|
||||
param: "blue"
|
||||
- type: "button"
|
||||
name: "cancel"
|
||||
caption: "Cancel"
|
||||
param: "red"
|
||||
@@ -33,7 +33,7 @@
|
||||
</div>
|
||||
{{ if isset(canJoin) }}
|
||||
<div class="text-center">
|
||||
<a href="/TODO/comm/join"
|
||||
<a href="/comm/{{ commAlias }}/join"
|
||||
class="inline-block bg-blue-600 hover:bg-blue-700 text-white px-4 py-1 rounded text-xs font-medium transition-colors">
|
||||
Join Now
|
||||
</a>
|
||||
@@ -41,7 +41,7 @@
|
||||
{{ end }}
|
||||
{{ if isset(canInvite) }}
|
||||
<div class="text-center">
|
||||
<a href="/TODO/comm/invite"
|
||||
<a href="/TODO/comm/{{ commAlias }}/invite"
|
||||
class="inline-block bg-blue-600 hover:bg-blue-700 text-white px-4 py-1 rounded text-xs font-medium transition-colors">
|
||||
Invite
|
||||
</a>
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if .IsMember() && !.IsMemberLocked() }}
|
||||
<div class="mb-1"><a href="/TODO/comm/{{ comm.Alias }}/unjoin" class="text-red-700 hover:text-red-900">⚠️ Unjoin</a></div>
|
||||
<div class="mb-1"><a href="/comm/{{ comm.Alias }}/unjoin" class="text-red-700 hover:text-red-900">⚠️ Unjoin</a></div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{*
|
||||
* 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">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-blue-800 text-4xl font-bold mb-2">Unjoin Community</h1>
|
||||
<span class="text-blue-800 text-2xl font-bold ml-2">{{ comm.Name }}</span>
|
||||
<hr class="border-2 border-gray-400 w-4/5 mb-4">
|
||||
</div>
|
||||
|
||||
<div class="bg-yellow-50 p-6 rounded-lg">
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-lg font-bold text-black mb-4">⚠️ Warning</h2>
|
||||
<p class="text-black">
|
||||
You are about to unjoin the {{ comm.Name }} community.
|
||||
{{ if comm.MembersOnly }}
|
||||
You will lose access to all content of the community, as well as the ability to interact with
|
||||
the community as a whole.
|
||||
{{ else }}
|
||||
You will lose the ability to interact with the community's members and content.
|
||||
{{ end }}
|
||||
</p>
|
||||
<p class="text-black">Please confirm if you wish to proceed.</p>
|
||||
</div>
|
||||
<div class="flex justify-center gap-4 mt-6">
|
||||
<form method="POST" action="/comm/{{ comm.Alias }}/unjoin">
|
||||
<button type="submit" name="cancel"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded font-medium transition-colors">Cancel</button>
|
||||
<button type="submit" name="unjoin"
|
||||
class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded font-medium transition-colors">
|
||||
Unjoin {{ comm.Name }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user