completed manage conference list
This commit is contained in:
@@ -865,3 +865,39 @@ func ManageConferenceList(ctxt ui.AmContext) (string, any) {
|
|||||||
ctxt.SetFrameTitle("Manage Conference List")
|
ctxt.SetFrameTitle("Manage Conference List")
|
||||||
return "framed", "manage_conflist.jet"
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -813,6 +813,131 @@ func (c *Conference) Stats(ctx context.Context) (int, int, error) {
|
|||||||
return ntopic, npost, err
|
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.
|
/* AmGetConference returns a conference given its ID.
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* ctx - Standard Go context value.
|
* ctx - Standard Go context value.
|
||||||
|
|||||||
@@ -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.
|
// Spin off a background task to finish deleting this topic.
|
||||||
myTopicId := t.TopicId
|
myTopicId := t.TopicId
|
||||||
background.Submit(func(ctx context.Context) {
|
background.Submit(func(ctx context.Context) {
|
||||||
|
start := time.Now()
|
||||||
err := backgroundPurgeTopic(ctx, myTopicId)
|
err := backgroundPurgeTopic(ctx, myTopicId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("backgroundTopicPurge FAILED with %v", err)
|
log.Errorf("backgroundTopicPurge FAILED with %v", err)
|
||||||
}
|
}
|
||||||
|
dur := time.Since(start)
|
||||||
|
log.Infof("Topic.Delete task completed in %v", dur)
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+5
-2
@@ -126,10 +126,13 @@ func (m *amMessage) Send() {
|
|||||||
* The new Message.
|
* The new Message.
|
||||||
*/
|
*/
|
||||||
func AmNewEmailMessage(sender int32, ip string) Message {
|
func AmNewEmailMessage(sender int32, ip string) Message {
|
||||||
rc := freeMessages.Get().(*amMessage)
|
var rc *amMessage
|
||||||
if rc == nil {
|
tmp := freeMessages.Get()
|
||||||
|
if tmp == nil {
|
||||||
rc = &amMessage{to: make([]string, 0), cc: make([]string, 0), bcc: make([]string, 0),
|
rc = &amMessage{to: make([]string, 0), cc: make([]string, 0), bcc: make([]string, 0),
|
||||||
headers: make(map[string]string), vars: make(jet.VarMap)}
|
headers: make(map[string]string), vars: make(jet.VarMap)}
|
||||||
|
} else {
|
||||||
|
rc = tmp.(*amMessage)
|
||||||
}
|
}
|
||||||
rc.uid = sender
|
rc.uid = sender
|
||||||
rc.ip = ip
|
rc.ip = ip
|
||||||
|
|||||||
@@ -118,8 +118,10 @@ func setupEcho() *echo.Echo {
|
|||||||
// conference group
|
// conference group
|
||||||
commGroup.GET("/create_conf", ui.AmWrap(CreateConferenceForm))
|
commGroup.GET("/create_conf", ui.AmWrap(CreateConferenceForm))
|
||||||
commGroup.POST("/create_conf", ui.AmWrap(CreateConference))
|
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)
|
commGroup.GET("/conf", ui.AmWrap(Conferences), ui.ValidateConference)
|
||||||
|
|
||||||
confGroup := commGroup.Group("/conf/:confid", ui.ValidateConference, ui.SetConference)
|
confGroup := commGroup.Group("/conf/:confid", ui.ValidateConference, ui.SetConference)
|
||||||
confGroup.GET("", ui.AmWrap(Topics))
|
confGroup.GET("", ui.AmWrap(Topics))
|
||||||
confGroup.GET("/new_topic", ui.AmWrap(NewTopicForm))
|
confGroup.GET("/new_topic", ui.AmWrap(NewTopicForm))
|
||||||
@@ -145,6 +147,7 @@ func setupEcho() *echo.Echo {
|
|||||||
confGroup.GET("/invite", ui.AmWrap(InviteToConference))
|
confGroup.GET("/invite", ui.AmWrap(InviteToConference))
|
||||||
confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts), ui.SetTopic)
|
confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts), ui.SetTopic)
|
||||||
confGroup.POST("/r/:topic", ui.AmWrap(PostInTopic), ui.SetTopic)
|
confGroup.POST("/r/:topic", ui.AmWrap(PostInTopic), ui.SetTopic)
|
||||||
|
|
||||||
opsGroup := confGroup.Group("/op/:topic", ui.SetTopic)
|
opsGroup := confGroup.Group("/op/:topic", ui.SetTopic)
|
||||||
opsGroup.GET("/find", ui.AmWrap(FindPostsPageTopic))
|
opsGroup.GET("/find", ui.AmWrap(FindPostsPageTopic))
|
||||||
opsGroup.POST("/find", ui.AmWrap(FindPostsTopic))
|
opsGroup.POST("/find", ui.AmWrap(FindPostsTopic))
|
||||||
|
|||||||
+5
-2
@@ -524,14 +524,17 @@ var amContextRecycleBin chan *amContext
|
|||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func newContext(ctxt echo.Context) (*amContext, error) {
|
func newContext(ctxt echo.Context) (*amContext, error) {
|
||||||
rc := freeContext.Get().(*amContext)
|
var rc *amContext
|
||||||
if rc == nil {
|
tmp := freeContext.Get()
|
||||||
|
if tmp == nil {
|
||||||
rc = &amContext{
|
rc = &amContext{
|
||||||
rendervars: make(jet.VarMap),
|
rendervars: make(jet.VarMap),
|
||||||
frameTitle: "",
|
frameTitle: "",
|
||||||
frameMeta: make(map[int]map[string]string),
|
frameMeta: make(map[int]map[string]string),
|
||||||
outputType: "",
|
outputType: "",
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rc = tmp.(*amContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -55,3 +55,29 @@ messagedefs:
|
|||||||
tone: "green"
|
tone: "green"
|
||||||
icon: "✗"
|
icon: "✗"
|
||||||
text: "No, Cancel"
|
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"
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap text-center w-12">
|
<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>
|
title="Delete Conference">❌</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-sm">
|
<td class="px-4 py-3 text-sm">
|
||||||
|
|||||||
Reference in New Issue
Block a user