mattermost-plugin-cleanup-c.../server/command/command.go
Felipe M. 85e2a38f17
Some checks failed
ci / test (push) Successful in 3m7s
ci / lint (push) Failing after 2m50s
ci / build (push) Successful in 4m21s
release / release (push) Successful in 5m43s
Add automatic channel cleanup with unified modal UI.
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>
2026-07-28 18:35:24 +02:00

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,
}
}