completed manage conference list

This commit is contained in:
2026-02-20 22:33:27 -07:00
parent 7ae9326292
commit acf65583ca
8 changed files with 205 additions and 6 deletions
+36
View File
@@ -865,3 +865,39 @@ func ManageConferenceList(ctxt ui.AmContext) (string, any) {
ctxt.SetFrameTitle("Manage Conference List")
return "framed", "manage_conflist.jet"
}
/* ManageDeleteConference handles the deletion of a conference from the management menu.
* Parameters:
* ctxt - The AmContext for the request.
* Returns:
* Command string dictating what to be rendered.
* Data as a parameter for the command string.
*/
func ManageDeleteConference(ctxt ui.AmContext) (string, any) {
comm := ctxt.CurrentCommunity()
conf := ctxt.GetScratch("currentConference").(*database.Conference)
myLevel := ctxt.GetScratch("levelInConference").(uint16)
if !conf.TestPermission("Conference.Delete", myLevel) {
return "error", ENOPERM
}
// Load the message box, and, if we have a valid "yes," then perform the delete
mbox, err := ui.AmLoadMessageBox("deleteConf")
if err != nil {
return "error", err
}
if mbox.Validate(ctxt, "yes") {
err := conf.Delete(ctxt.Ctx(), comm, ctxt.CurrentUser(), ctxt.RemoteIP(), ampool)
if err != nil {
return "error", err
}
return "redirect", fmt.Sprintf("/comm/%s/manage_conf", ctxt.CurrentCommunity().Alias)
}
// Set up to display the message box.
mbox.SetMessage(fmt.Sprintf(`You are about to delete the conference <span class="font-bold text-red-600">"%s"</span>
from the <span class="font-bold text-red-600">"%s"</span> community!`, conf.Name, comm.Name))
mbox.SetLink("no", fmt.Sprintf("/comm/%s/manage_conf", ctxt.CurrentCommunity().Alias))
mbox.SetLink("yes", fmt.Sprintf("/comm/%s/manage_conf/del/%s", ctxt.CurrentCommunity().Alias, ctxt.GetScratch("currentAlias")))
return mbox.Render(ctxt)
}
+125
View File
@@ -813,6 +813,131 @@ func (c *Conference) Stats(ctx context.Context) (int, int, error) {
return ntopic, npost, err
}
// backgroundPurgeConference purges out all the conference information in the background.
func backgroundPurgeConference(ctx context.Context, confid int32) error {
// Purge out auxiliary conference tables first.
tx := amdb.MustBegin()
_, err := tx.ExecContext(ctx, "DELETE FROM confmember WHERE confid = ?", confid)
if err != nil {
log.Warnf("backgroundPurgeConference(%d): failed purging confmember: %v", confid, err)
}
_, err = tx.ExecContext(ctx, "DELETE FROM confsettings WHERE confid = ?", confid)
if err != nil {
log.Warnf("backgroundPurgeConference(%d): failed purging confsettings: %v", confid, err)
}
_, err = tx.ExecContext(ctx, "DELETE FROM confhotlist WHERE confid = ?", confid)
if err != nil {
log.Warnf("backgroundPurgeConference(%d): failed purging confhotlist: %v", confid, err)
}
_, err = tx.ExecContext(ctx, "DELETE FROM propconf WHERE confid = ?", confid)
if err != nil {
log.Warnf("backgroundPurgeConference(%d): failed purging propconf: %v", confid, err)
}
_, err = tx.ExecContext(ctx, "DELETE FROM confcustom WHERE confid = ?", confid)
if err != nil {
log.Warnf("backgroundPurgeConference(%d): failed purging confcustom: %v", confid, err)
}
err = tx.Commit()
if err != nil {
tx.Rollback()
return err
}
// Get all topic IDs in this conference.
var topicIds []int32
err = amdb.SelectContext(ctx, &topicIds, "SELECT topicid FROM topics WHERE confid = ?", confid)
if err != nil {
return err
}
// Erase each topic in turn by calling two of the "delete topic" internal functions.
for _, topicId := range topicIds {
tx := amdb.MustBegin()
err = eraseTopicRecords(ctx, tx, topicId)
if err == nil {
err = tx.Commit()
}
if err != nil {
tx.Rollback()
return err
}
err = backgroundPurgeTopic(ctx, topicId)
if err != nil {
return err
}
}
return nil
}
// Delete unlinks this conference from the community, deleting it entirely if the last link is gone.
func (c *Conference) Delete(ctx context.Context, comm *Community, u *User, ipaddr string, background *util.WorkerPool) error {
success := false
tx := amdb.MustBegin()
defer func() {
if !success {
tx.Rollback()
}
}()
getConferenceMutex.Lock()
defer getConferenceMutex.Unlock()
// any references to conference other than this community?
row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM commtoconf WHERE confid = ? AND commid <> ?", c.ConfId, comm.Id)
refCount := 0
err := row.Scan(&refCount)
if err != nil {
return err
}
// break the link with the community
if _, err = tx.ExecContext(ctx, "DELETE FROM commtoconf WHERE commid = ? AND confid = ?", comm.Id, c.ConfId); err != nil {
return err
}
if refCount == 0 {
// We have to delete all the conference core data now.
_, err = tx.ExecContext(ctx, "DELETE FROM confs WHERE confid = ?", c.ConfId)
if err == nil {
_, err = tx.ExecContext(ctx, "DELETE FROM confalias WHERE confid = ?", c.ConfId)
}
}
if err != nil {
return err
}
if err = tx.Commit(); err != nil {
return err
}
success = true
if refCount == 0 {
// kick the conference out of the cache
conferenceCache.Remove(c.ConfId)
// add an audit record
AmStoreAudit(AmNewAudit(AuditConferenceDelete, u.Uid, ipaddr, fmt.Sprintf("confid=%d", c.ConfId)))
// set up a background job to purge the rest of the data
confid := c.ConfId
background.Submit(func(ctx context.Context) {
start := time.Now()
// Just dump the whole conference property cache
getConferencePropMutex.Lock()
conferencePropCache.Purge()
getConferencePropMutex.Unlock()
// purge the conference data
err := backgroundPurgeConference(ctx, confid)
if err != nil {
log.Errorf("Conference purge(#%d) background job failed: %v", confid, err)
}
dur := time.Since(start)
log.Infof("Conference.Delete task completed in %v", dur)
})
}
return nil
}
/* AmGetConference returns a conference given its ID.
* Parameters:
* ctx - Standard Go context value.
+3
View File
@@ -478,10 +478,13 @@ func (t *Topic) Delete(ctx context.Context, u *User, ipaddr string, background *
// Spin off a background task to finish deleting this topic.
myTopicId := t.TopicId
background.Submit(func(ctx context.Context) {
start := time.Now()
err := backgroundPurgeTopic(ctx, myTopicId)
if err != nil {
log.Errorf("backgroundTopicPurge FAILED with %v", err)
}
dur := time.Since(start)
log.Infof("Topic.Delete task completed in %v", dur)
})
return nil
+5 -2
View File
@@ -126,10 +126,13 @@ func (m *amMessage) Send() {
* The new Message.
*/
func AmNewEmailMessage(sender int32, ip string) Message {
rc := freeMessages.Get().(*amMessage)
if rc == nil {
var rc *amMessage
tmp := freeMessages.Get()
if tmp == nil {
rc = &amMessage{to: make([]string, 0), cc: make([]string, 0), bcc: make([]string, 0),
headers: make(map[string]string), vars: make(jet.VarMap)}
} else {
rc = tmp.(*amMessage)
}
rc.uid = sender
rc.ip = ip
+4 -1
View File
@@ -118,8 +118,10 @@ 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("/manage_conf", ui.AmWrap(ManageConferenceList), ui.ValidateConference)
commGroup.GET("/manage_conf/del/:confid", ui.AmWrap(ManageDeleteConference), ui.ValidateConference, ui.SetConference)
commGroup.GET("/conf", ui.AmWrap(Conferences), ui.ValidateConference)
confGroup := commGroup.Group("/conf/:confid", ui.ValidateConference, ui.SetConference)
confGroup.GET("", ui.AmWrap(Topics))
confGroup.GET("/new_topic", ui.AmWrap(NewTopicForm))
@@ -145,6 +147,7 @@ func setupEcho() *echo.Echo {
confGroup.GET("/invite", ui.AmWrap(InviteToConference))
confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts), ui.SetTopic)
confGroup.POST("/r/:topic", ui.AmWrap(PostInTopic), ui.SetTopic)
opsGroup := confGroup.Group("/op/:topic", ui.SetTopic)
opsGroup.GET("/find", ui.AmWrap(FindPostsPageTopic))
opsGroup.POST("/find", ui.AmWrap(FindPostsTopic))
+5 -2
View File
@@ -524,14 +524,17 @@ var amContextRecycleBin chan *amContext
* Standard Go error status.
*/
func newContext(ctxt echo.Context) (*amContext, error) {
rc := freeContext.Get().(*amContext)
if rc == nil {
var rc *amContext
tmp := freeContext.Get()
if tmp == nil {
rc = &amContext{
rendervars: make(jet.VarMap),
frameTitle: "",
frameMeta: make(map[int]map[string]string),
outputType: "",
}
} else {
rc = tmp.(*amContext)
}
var err error
+26
View File
@@ -55,3 +55,29 @@ messagedefs:
tone: "green"
icon: "✗"
text: "No, Cancel"
- id: "deleteConf"
title: "Delete Conference"
tone: "red"
destructive: true
message: "You are about to delete a conference!"
warningIcon: "💣"
warningLines:
- text: "Warning: This action cannot be undone!"
bold: true
- text: "Deleting this conference will permanently remove it and all its topics from the system."
bold: false
- text: "Hundreds or even thousands of conference posts will be lost forever."
bold: false
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"
+1 -1
View File
@@ -70,7 +70,7 @@
{{ 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"
<a href="{{ baseUrl }}/del/{{ c.Alias }}" class="text-2xl hover:scale-125 inline-block transition-transform"
title="Delete Conference">❌</a>
</td>
<td class="px-4 py-3 text-sm">