166 lines
4.9 KiB
Go
166 lines
4.9 KiB
Go
package help
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.nakama.town/fmartingr/butterrobot/internal/db"
|
|
"git.nakama.town/fmartingr/butterrobot/internal/model"
|
|
"git.nakama.town/fmartingr/butterrobot/internal/plugin"
|
|
"golang.org/x/exp/slog"
|
|
)
|
|
|
|
// ChannelPluginGetter is an interface for getting channel plugins
|
|
type ChannelPluginGetter interface {
|
|
GetChannelPlugins(channelID int64) ([]*model.ChannelPlugin, error)
|
|
GetChannelPluginsFromPlatformID(platform, platformChannelID string) ([]*model.ChannelPlugin, error)
|
|
}
|
|
|
|
// HelpPlugin provides help information about available commands
|
|
type HelpPlugin struct {
|
|
plugin.BasePlugin
|
|
db ChannelPluginGetter
|
|
}
|
|
|
|
// New creates a new HelpPlugin instance
|
|
func New(db ChannelPluginGetter) *HelpPlugin {
|
|
return &HelpPlugin{
|
|
BasePlugin: plugin.BasePlugin{
|
|
ID: "utility.help",
|
|
Name: "Help",
|
|
Help: "Shows available commands when you type '!help'",
|
|
},
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// OnMessage handles incoming messages
|
|
func (p *HelpPlugin) OnMessage(msg *model.Message, config map[string]interface{}, cache model.CacheInterface) []*model.MessageAction {
|
|
// Check if message is the help command
|
|
if !strings.EqualFold(strings.TrimSpace(msg.Text), "!help") {
|
|
return nil
|
|
}
|
|
|
|
// Get channel plugins from database using platform and platform channel ID
|
|
channelPlugins, err := p.db.GetChannelPluginsFromPlatformID(msg.Channel.Platform, msg.Channel.PlatformChannelID)
|
|
if err != nil && err != db.ErrNotFound {
|
|
slog.Error("Failed to get channel plugins", slog.Any("err", err))
|
|
return []*model.MessageAction{}
|
|
}
|
|
|
|
// If no plugins found, initialize empty slice
|
|
if err == db.ErrNotFound {
|
|
channelPlugins = []*model.ChannelPlugin{}
|
|
}
|
|
|
|
// Get all available plugins
|
|
availablePlugins := plugin.GetAvailablePlugins()
|
|
|
|
// Filter to only enabled plugins for this channel
|
|
enabledPlugins := make(map[string]model.Plugin)
|
|
for _, channelPlugin := range channelPlugins {
|
|
if channelPlugin.Enabled {
|
|
if availablePlugin, exists := availablePlugins[channelPlugin.PluginID]; exists {
|
|
enabledPlugins[channelPlugin.PluginID] = availablePlugin
|
|
}
|
|
}
|
|
}
|
|
|
|
// If no plugins are enabled, return a message
|
|
if len(enabledPlugins) == 0 {
|
|
response := &model.Message{
|
|
Text: "No plugins are currently enabled for this channel.",
|
|
Chat: msg.Chat,
|
|
ReplyTo: msg.ID,
|
|
Channel: msg.Channel,
|
|
Raw: map[string]interface{}{"parse_mode": "Markdown"},
|
|
}
|
|
|
|
return []*model.MessageAction{
|
|
{
|
|
Type: model.ActionSendMessage,
|
|
Message: response,
|
|
Chat: msg.Chat,
|
|
Channel: msg.Channel,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Group plugins by category
|
|
categories := map[string][]model.Plugin{
|
|
"Development": {},
|
|
"Fun and Entertainment": {},
|
|
"Utility": {},
|
|
"Security": {},
|
|
"Social Media": {},
|
|
"Other": {},
|
|
}
|
|
|
|
// Categorize plugins based on their ID prefix
|
|
for _, p := range enabledPlugins {
|
|
category := p.GetID()
|
|
switch {
|
|
case strings.HasPrefix(category, "dev."):
|
|
categories["Development"] = append(categories["Development"], p)
|
|
case strings.HasPrefix(category, "fun."):
|
|
categories["Fun and Entertainment"] = append(categories["Fun and Entertainment"], p)
|
|
case strings.HasPrefix(category, "util.") || strings.HasPrefix(category, "reminder.") || strings.HasPrefix(category, "utility."):
|
|
categories["Utility"] = append(categories["Utility"], p)
|
|
case strings.HasPrefix(category, "security."):
|
|
categories["Security"] = append(categories["Security"], p)
|
|
case strings.HasPrefix(category, "social."):
|
|
categories["Social Media"] = append(categories["Social Media"], p)
|
|
default:
|
|
categories["Other"] = append(categories["Other"], p)
|
|
}
|
|
}
|
|
|
|
// Build the help message
|
|
var helpText strings.Builder
|
|
helpText.WriteString("🤖 **Available Commands**\n\n")
|
|
|
|
// Sort category names for consistent output
|
|
categoryOrder := []string{"Development", "Fun and Entertainment", "Utility", "Security", "Social Media", "Other"}
|
|
|
|
for _, categoryName := range categoryOrder {
|
|
pluginList := categories[categoryName]
|
|
if len(pluginList) == 0 {
|
|
continue
|
|
}
|
|
|
|
// Sort plugins within category by name
|
|
sort.Slice(pluginList, func(i, j int) bool {
|
|
return pluginList[i].GetName() < pluginList[j].GetName()
|
|
})
|
|
|
|
helpText.WriteString(fmt.Sprintf("**%s:**\n", categoryName))
|
|
for _, p := range pluginList {
|
|
if p.GetHelp() == "" {
|
|
continue
|
|
}
|
|
helpText.WriteString(fmt.Sprintf("• **%s** - %s\n", p.GetName(), p.GetHelp()))
|
|
}
|
|
helpText.WriteString("\n")
|
|
}
|
|
|
|
// Add footer
|
|
helpText.WriteString("_Use the specific commands or triggers mentioned above to interact with the bot._")
|
|
|
|
response := &model.Message{
|
|
Text: helpText.String(),
|
|
Chat: msg.Chat,
|
|
ReplyTo: msg.ID,
|
|
Channel: msg.Channel,
|
|
Raw: map[string]interface{}{"parse_mode": "Markdown"},
|
|
}
|
|
|
|
return []*model.MessageAction{
|
|
{
|
|
Type: model.ActionSendMessage,
|
|
Message: response,
|
|
Chat: msg.Chat,
|
|
Channel: msg.Channel,
|
|
},
|
|
}
|
|
}
|