diff --git a/communityadmin.go b/communityadmin.go
index 875e31d..9f95f76 100644
--- a/communityadmin.go
+++ b/communityadmin.go
@@ -730,6 +730,40 @@ func CommunityEmail(ctxt ui.AmContext) (string, any) {
return "redirect", fmt.Sprintf("/comm/%s/admin", comm.Alias)
}
+/* DeleteCommunity handles the deletion of 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 DeleteCommunity(ctxt ui.AmContext) (string, any) {
+ comm := ctxt.CurrentCommunity()
+ if !comm.TestPermission("Community.Delete", ctxt.EffectiveLevel()) {
+ return "error", ENOACCESS
+ }
+
+ // Load the message box, and, if we have a valid "yes," then perform the delete
+ mbox, err := ui.AmLoadMessageBox("deleteComm")
+ if err != nil {
+ return "error", err
+ }
+ if mbox.Validate(ctxt, "yes") {
+ err := comm.Delete(ctxt.Ctx(), ctxt.CurrentUser(), ctxt.RemoteIP(), ampool)
+ if err != nil {
+ return "error", err
+ }
+ return "redirect", "/"
+ }
+
+ // Set up to display the message box.
+ mbox.SetMessage(fmt.Sprintf(`You are about to permanently delete the "%s" community!`, comm.Name))
+ mbox.SetLink("no", fmt.Sprintf("/comm/%s/admin", comm.Alias))
+ mbox.SetLink("yes", fmt.Sprintf("/comm/%s/admin/delete", comm.Alias))
+ return mbox.Render(ctxt)
+}
+
/* CreateCommunityForm renders the form for creating a new community.
* Parameters:
* ctxt - The AmContext for the request.
diff --git a/database/community.go b/database/community.go
index 57ac1c2..9664d9f 100644
--- a/database/community.go
+++ b/database/community.go
@@ -591,6 +591,51 @@ func (c *Community) GetMemberEMailAddrs(ctx context.Context) ([]string, error) {
return rc, err
}
+// Delete deletes this community.
+func (c *Community) Delete(ctx context.Context, u *User, ipaddr string, background *util.WorkerPool) error {
+ tx, commit, rollback := transaction(ctx)
+ defer rollback()
+
+ // Start by deleting all the community's services. This will purge the conferences, among other things.
+ err := AmDeleteCommunityServices(ctx, tx, c.Id, background)
+ if err != nil {
+ return err
+ }
+
+ // Now erase from the other tables as well: members, bans, properties, and communities themselves.
+ _, err = tx.ExecContext(ctx, "DELETE FROM commmember WHERE commid = ?", c.Id)
+ if err == nil {
+ _, err = tx.ExecContext(ctx, "DELETE FROM commban WHERE commid = ?", c.Id)
+ if err == nil {
+ _, err = tx.ExecContext(ctx, "DELETE FROM propcomm WHERE cid = ?", c.Id)
+ if err == nil {
+ _, err = tx.ExecContext(ctx, "DELETE FROM communities WHERE commid = ?", c.Id)
+ }
+ }
+ }
+ if err != nil {
+ return err
+ }
+ if err = commit(); err != nil {
+ return err
+ }
+
+ // Purge the member and properties caches, and punt this community from the community cache.
+ memberMutex.Lock()
+ memberCache.Purge()
+ memberMutex.Unlock()
+ getCommunityPropMutex.Lock()
+ communityPropCache.Purge()
+ getCommunityPropMutex.Unlock()
+ getCommunityMutex.Lock()
+ communityCache.Remove(c.Id)
+ getCommunityMutex.Unlock()
+
+ // Save off an audit record for the delete.
+ AmStoreAudit(AmNewCommAudit(AuditCommunityDelete, u.Uid, c.Id, ipaddr))
+ return nil
+}
+
/* AmGetCommunity returns a reference to the specified community.
* Parameters:
* ctx - Standard Go context value.
diff --git a/database/conference.go b/database/conference.go
index 678bb9e..cfbd819 100644
--- a/database/conference.go
+++ b/database/conference.go
@@ -937,6 +937,11 @@ func (*conferenceServiceVTable) OnDeleteCommunity(ctx context.Context, tx *sqlx.
if err != nil {
return err
}
+ // Delete any mention of this community from the conference hotlists.
+ _, err = tx.ExecContext(ctx, "DELETE FROM confhotlist WHERE commid = ?", commid)
+ if err != nil {
+ return err
+ }
for i, confid := range confids {
// any references to conference other than this community?
refCount := 0
diff --git a/docs/MISSINGFUNCS.md b/docs/MISSINGFUNCS.md
index 700a884..b2cb793 100644
--- a/docs/MISSINGFUNCS.md
+++ b/docs/MISSINGFUNCS.md
@@ -23,12 +23,12 @@ _(italicized items can be deferred)_
- ~~Manage (reorder/show/hide/delete)~~
- ~~Create New~~
- ~~Conferences List honor "hide in list" flag~~
-- Community Admin Menu:
+- ~~Community Admin Menu:~~
- ~~Set Community Category~~
- ~~Membership Control~~
- ~~E-Mail to All Members~~
- ~~Display Audit Records~~
- - Delete Community
+ - ~~Delete Community~~
- ~~Community Profile: Invite~~
- _Help link atop page headers_
- _Policy page_
diff --git a/main.go b/main.go
index b23127c..93e61af 100644
--- a/main.go
+++ b/main.go
@@ -142,6 +142,7 @@ func setupEcho() *echo.Echo {
adminGroup.Match(GetAndPost, "/members", ui.AmWrap(CommunityMembers))
adminGroup.GET("/massmail", ui.AmWrap(CommunityEmailForm))
adminGroup.POST("/massmail", ui.AmWrap(CommunityEmail))
+ adminGroup.GET("/delete", ui.AmWrap(DeleteCommunity))
// conference group
commGroup.GET("/create_conf", ui.AmWrap(CreateConferenceForm))
diff --git a/ui/menudefs.yaml b/ui/menudefs.yaml
index 0d96513..4f53153 100644
--- a/ui/menudefs.yaml
+++ b/ui/menudefs.yaml
@@ -81,7 +81,7 @@ menudefs:
link: "/comm/[CID]/admin/audit"
permission: "Community.ShowAdmin"
- text: "Delete Community"
- link: "/TODO/comm/[CID]/admin/delete"
+ link: "/comm/[CID]/admin/delete"
permission: "Community.Delete"
hazard: true
- id: "confhost"
diff --git a/ui/messagedefs.yaml b/ui/messagedefs.yaml
index e171a40..c6e202e 100644
--- a/ui/messagedefs.yaml
+++ b/ui/messagedefs.yaml
@@ -105,3 +105,31 @@ messagedefs:
tone: "green"
icon: "✗"
text: "No, Cancel"
+ - id: "deleteComm"
+ title: "Delete Community"
+ tone: "red"
+ destructive: true
+ message: "You are about to delete a community!"
+ warningIcon: "💣"
+ warningLines:
+ - text: "Warning: This action cannot be undone!"
+ bold: true
+ - text: "Deleting this community will permanently remove it and all its contents from the system."
+ bold: false
+ - text: "Hundreds or even thousands of individual contributions will be lost forever."
+ bold: false
+ - text: "Please consider this action very carefully!"
+ bold: true
+ buttons:
+ - id: "yes"
+ link: "placeholder"
+ confirm: true
+ tone: "red"
+ icon: "✓"
+ text: "Yes, Delete It"
+ - id: "no"
+ link: "placeholder"
+ confirm: false
+ tone: "green"
+ icon: "✗"
+ text: "No, Cancel"