Per-channel retention config, daily scheduled cleanup, slash command and REST API support, plus a single Channel cleanup menu that opens a plugin modal for configure, run-now, and disable actions. Co-authored-by: Cursor <cursoragent@cursor.com>
140 lines
4.8 KiB
Go
140 lines
4.8 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/pluginapi"
|
|
|
|
"github.com/fmartingr/mattermost-plugin-cleanup-channel/server/autocleanup"
|
|
)
|
|
|
|
const (
|
|
cleanupCommandTrigger = "cleanup-channel"
|
|
autoCleanupCommandTrigger = "auto-cleanup-channel"
|
|
)
|
|
|
|
type AutoCleanupStore interface {
|
|
Get(channelID string) (*autocleanup.Config, error)
|
|
Set(channelID string, offsetDays int) error
|
|
Delete(channelID string) error
|
|
}
|
|
|
|
type Handler struct {
|
|
client *pluginapi.Client
|
|
cleanup func(userID, channelID string) (int, error)
|
|
autoCleanupStore AutoCleanupStore
|
|
}
|
|
|
|
type Command interface {
|
|
Handle(args *model.CommandArgs) (*model.CommandResponse, error)
|
|
}
|
|
|
|
func NewCommandHandler(client *pluginapi.Client, autoCleanupStore AutoCleanupStore, cleanup func(userID, channelID string) (int, error)) Command {
|
|
registerCommand(client, cleanupCommandTrigger, "Remove all messages from the current channel (system admins only)")
|
|
registerCommand(client, autoCleanupCommandTrigger, "Configure automatic message cleanup for the current channel (system admins only)")
|
|
|
|
return &Handler{
|
|
client: client,
|
|
cleanup: cleanup,
|
|
autoCleanupStore: autoCleanupStore,
|
|
}
|
|
}
|
|
|
|
func registerCommand(client *pluginapi.Client, trigger, description string) {
|
|
err := client.SlashCommand.Register(&model.Command{
|
|
Trigger: trigger,
|
|
AutoComplete: false,
|
|
AutoCompleteDesc: description,
|
|
})
|
|
if err != nil {
|
|
client.Log.Error("Failed to register command", "trigger", trigger, "error", err)
|
|
}
|
|
}
|
|
|
|
func (c *Handler) Handle(args *model.CommandArgs) (*model.CommandResponse, error) {
|
|
fields := strings.Fields(args.Command)
|
|
if len(fields) == 0 {
|
|
return ephemeralResponse("Empty command"), nil
|
|
}
|
|
|
|
trigger := strings.TrimPrefix(fields[0], "/")
|
|
switch trigger {
|
|
case cleanupCommandTrigger:
|
|
return c.handleCleanup(args)
|
|
case autoCleanupCommandTrigger:
|
|
return c.handleAutoCleanup(args, fields[1:])
|
|
default:
|
|
return ephemeralResponse(fmt.Sprintf("Unknown command: %s", args.Command)), nil
|
|
}
|
|
}
|
|
|
|
func (c *Handler) handleCleanup(args *model.CommandArgs) (*model.CommandResponse, error) {
|
|
if !c.client.User.HasPermissionTo(args.UserId, model.PermissionManageSystem) {
|
|
return ephemeralResponse("This command is only available to system administrators."), nil
|
|
}
|
|
|
|
deleted, err := c.cleanup(args.UserId, args.ChannelId)
|
|
if err != nil {
|
|
c.client.Log.Error("Failed to cleanup channel via slash command", "channel_id", args.ChannelId, "error", err)
|
|
return ephemeralResponse("Failed to remove messages from this channel."), nil
|
|
}
|
|
|
|
return ephemeralResponse(fmt.Sprintf("Removed %d message(s) from this channel.", deleted)), nil
|
|
}
|
|
|
|
func (c *Handler) handleAutoCleanup(args *model.CommandArgs, params []string) (*model.CommandResponse, error) {
|
|
if !c.client.User.HasPermissionTo(args.UserId, model.PermissionManageSystem) {
|
|
return ephemeralResponse("This command is only available to system administrators."), nil
|
|
}
|
|
|
|
if len(params) == 0 {
|
|
config, err := c.autoCleanupStore.Get(args.ChannelId)
|
|
if err != nil {
|
|
c.client.Log.Error("Failed to get auto cleanup config", "channel_id", args.ChannelId, "error", err)
|
|
return ephemeralResponse("Failed to get automatic cleanup settings for this channel."), nil
|
|
}
|
|
if config == nil {
|
|
return ephemeralResponse("Automatic cleanup is not configured for this channel."), nil
|
|
}
|
|
|
|
return ephemeralResponse(fmt.Sprintf(
|
|
"Automatic cleanup is enabled for this channel. Messages older than %d day(s) are removed daily.",
|
|
config.OffsetDays,
|
|
)), nil
|
|
}
|
|
|
|
switch strings.ToLower(params[0]) {
|
|
case "off", "disable", "disabled":
|
|
if err := c.autoCleanupStore.Delete(args.ChannelId); err != nil {
|
|
c.client.Log.Error("Failed to disable auto cleanup", "channel_id", args.ChannelId, "error", err)
|
|
return ephemeralResponse("Failed to disable automatic cleanup for this channel."), nil
|
|
}
|
|
|
|
return ephemeralResponse("Automatic cleanup has been disabled for this channel."), nil
|
|
default:
|
|
offsetDays, err := strconv.Atoi(params[0])
|
|
if err != nil || offsetDays <= 0 {
|
|
return ephemeralResponse("Usage: /auto-cleanup-channel [days|off]. Example: /auto-cleanup-channel 30"), nil
|
|
}
|
|
|
|
if err := c.autoCleanupStore.Set(args.ChannelId, offsetDays); err != nil {
|
|
c.client.Log.Error("Failed to set auto cleanup config", "channel_id", args.ChannelId, "error", err)
|
|
return ephemeralResponse("Failed to configure automatic cleanup for this channel."), nil
|
|
}
|
|
|
|
return ephemeralResponse(fmt.Sprintf(
|
|
"Automatic cleanup enabled. Messages older than %d day(s) will be removed daily from this channel.",
|
|
offsetDays,
|
|
)), nil
|
|
}
|
|
}
|
|
|
|
func ephemeralResponse(text string) *model.CommandResponse {
|
|
return &model.CommandResponse{
|
|
ResponseType: model.CommandResponseTypeEphemeral,
|
|
Text: text,
|
|
}
|
|
}
|