Compare commits

..

No commits in common. "master" and "v0.8.1" have entirely different histories.

9 changed files with 15 additions and 150 deletions

View file

@ -18,12 +18,10 @@ When creating, modifying, or removing plugins:
## Testing ## Testing
**CRITICAL**: After making ANY changes to code files, you MUST run these commands in order: Before committing plugin changes:
1. **Format code**: `make format` - Format all code according to project standards 1. Check files are properly formatted: Run `make format`
2. **Lint code**: `make lint` - Check code style and quality (must show "0 issues") 2. Check code style and linting: Run `make lint`
3. **Run tests**: `make test` - Run all tests to ensure functionality works 3. Test the plugin functionality: Run `make test`
4. Verify documentation accuracy 4. Verify documentation accuracy
5. Ensure all examples work as described 5. Ensure all examples work as described
**These commands are MANDATORY after every code change, no exceptions.**

View file

@ -32,7 +32,7 @@
<input class="form-check-input" type="checkbox" name="enable_all_plugins" value="true" {{if .Channel.EnableAllPlugins}}checked{{end}}> <input class="form-check-input" type="checkbox" name="enable_all_plugins" value="true" {{if .Channel.EnableAllPlugins}}checked{{end}}>
<span class="form-check-label">Enable All Plugins</span> <span class="form-check-label">Enable All Plugins</span>
</label> </label>
<div> <div class="form-help">
When enabled, all registered plugins will be automatically enabled for this channel. Individual plugin settings will be ignored. When enabled, all registered plugins will be automatically enabled for this channel. Individual plugin settings will be ignored.
</div> </div>
</div> </div>
@ -124,4 +124,4 @@
</div> </div>
</div> </div>
</div> </div>
{{end}} {{end}}

View file

@ -200,4 +200,4 @@ func TestEnableAllPlugins(t *testing.T) {
t.Errorf("EnableAllPlugins should be true after update") t.Errorf("EnableAllPlugins should be true after update")
} }
}) })
} }

View file

@ -231,4 +231,4 @@ func TestChannelName(t *testing.T) {
t.Errorf("Expected channel name to fallback to 'fallback-id', got '%s'", result) t.Errorf("Expected channel name to fallback to 'fallback-id', got '%s'", result)
} }
}) })
} }

View file

@ -233,17 +233,9 @@ func (t *TelegramPlatform) SendMessage(msg *model.Message) error {
// Prepare payload // Prepare payload
payload := map[string]interface{}{ payload := map[string]interface{}{
"chat_id": chatID, "chat_id": chatID,
"text": msg.Text, "text": msg.Text,
} "parse_mode": "Markdown",
// Set parse_mode based on plugin preference or default to empty string
if msg.Raw != nil && msg.Raw["parse_mode"] != nil {
// Plugin explicitly set parse_mode
payload["parse_mode"] = msg.Raw["parse_mode"]
} else {
// Default to empty string (no formatting)
payload["parse_mode"] = ""
} }
// Add reply if needed // Add reply if needed

View file

@ -131,15 +131,12 @@ func (p *HLTBPlugin) OnMessage(msg *model.Message, config map[string]interface{}
Channel: msg.Channel, Channel: msg.Channel,
} }
// Set parse mode for markdown formatting
if responseMsg.Raw == nil {
responseMsg.Raw = make(map[string]interface{})
}
responseMsg.Raw["parse_mode"] = "Markdown"
// Add game cover as attachment if available // Add game cover as attachment if available
if game.GameImage != "" { if game.GameImage != "" {
imageURL := p.getFullImageURL(game.GameImage) imageURL := p.getFullImageURL(game.GameImage)
if responseMsg.Raw == nil {
responseMsg.Raw = make(map[string]interface{})
}
responseMsg.Raw["image_url"] = imageURL responseMsg.Raw["image_url"] = imageURL
} }

View file

@ -74,7 +74,6 @@ func (p *HelpPlugin) OnMessage(msg *model.Message, config map[string]interface{}
Chat: msg.Chat, Chat: msg.Chat,
ReplyTo: msg.ID, ReplyTo: msg.ID,
Channel: msg.Channel, Channel: msg.Channel,
Raw: map[string]interface{}{"parse_mode": "Markdown"},
} }
return []*model.MessageAction{ return []*model.MessageAction{
@ -152,7 +151,6 @@ func (p *HelpPlugin) OnMessage(msg *model.Message, config map[string]interface{}
Chat: msg.Chat, Chat: msg.Chat,
ReplyTo: msg.ID, ReplyTo: msg.ID,
Channel: msg.Channel, Channel: msg.Channel,
Raw: map[string]interface{}{"parse_mode": "Markdown"},
} }
return []*model.MessageAction{ return []*model.MessageAction{

View file

@ -328,4 +328,4 @@ func TestPluginRegistry(t *testing.T) {
t.Errorf("Expected error when getting plugin after clearing registry, got nil") t.Errorf("Expected error when getting plugin after clearing registry, got nil")
} }
}) })
} }

View file

@ -1,120 +0,0 @@
package social
import (
"testing"
"git.nakama.town/fmartingr/butterrobot/internal/model"
)
func TestTwitterExpander_OnMessage(t *testing.T) {
plugin := NewTwitterExpander()
tests := []struct {
name string
input string
config map[string]interface{}
expected string
hasReply bool
}{
{
name: "Twitter URL with default domain",
input: "https://twitter.com/user/status/123456789",
config: map[string]interface{}{},
expected: "https://fxtwitter.com/user/status/123456789",
hasReply: true,
},
{
name: "X.com URL with custom domain",
input: "https://x.com/elonmusk/status/987654321",
config: map[string]interface{}{"domain": "vxtwitter.com"},
expected: "https://vxtwitter.com/elonmusk/status/987654321",
hasReply: true,
},
{
name: "Twitter URL with tracking parameters",
input: "https://twitter.com/openai/status/555?ref_src=twsrc%5Etfw&s=20",
config: map[string]interface{}{},
expected: "https://fxtwitter.com/openai/status/555",
hasReply: true,
},
{
name: "www.twitter.com URL",
input: "https://www.twitter.com/user/status/789",
config: map[string]interface{}{"domain": "nitter.net"},
expected: "https://nitter.net/user/status/789",
hasReply: true,
},
{
name: "Mixed text with Twitter URL",
input: "Check this out: https://twitter.com/user/status/123 amazing!",
config: map[string]interface{}{},
expected: "Check this out: https://fxtwitter.com/user/status/123 amazing!",
hasReply: true,
},
{
name: "No Twitter URLs",
input: "Just some regular text https://youtube.com/watch?v=abc",
config: map[string]interface{}{},
expected: "",
hasReply: false,
},
{
name: "Empty message",
input: "",
config: map[string]interface{}{},
expected: "",
hasReply: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
msg := &model.Message{
ID: "test_msg",
Text: tt.input,
Chat: "test_chat",
Channel: &model.Channel{
ID: 1,
Platform: "telegram",
PlatformChannelID: "test_chat",
},
}
actions := plugin.OnMessage(msg, tt.config, nil)
if !tt.hasReply {
if len(actions) != 0 {
t.Errorf("Expected no actions, got %d", len(actions))
}
return
}
if len(actions) != 1 {
t.Errorf("Expected 1 action, got %d", len(actions))
return
}
action := actions[0]
if action.Type != model.ActionSendMessage {
t.Errorf("Expected ActionSendMessage, got %s", action.Type)
}
if action.Message == nil {
t.Error("Expected message in action, got nil")
return
}
if action.Message.Text != tt.expected {
t.Errorf("Expected '%s', got '%s'", tt.expected, action.Message.Text)
}
if action.Message.ReplyTo != msg.ID {
t.Errorf("Expected ReplyTo '%s', got '%s'", msg.ID, action.Message.ReplyTo)
}
if action.Message.Raw == nil || action.Message.Raw["parse_mode"] != "" {
t.Error("Expected parse_mode to be empty string to disable markdown parsing")
}
})
}
}