Compare commits

..

7 commits

Author SHA1 Message Date
377b1723c3
fix: default parse mode to text
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/tag/release Pipeline was successful
2025-06-24 08:10:56 +02:00
60ceaffd82
fix: enable all plugins help text
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
2025-06-23 11:43:42 +02:00
3a5b5c216d
chore: try to ensure that code is checked after each session
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
2025-06-23 11:35:30 +02:00
bdc797d5c1
chore: make format 2025-06-23 11:34:27 +02:00
0edf41c792
fix: markdown parse mode breaking some plugins
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/tag/release Pipeline was successful
2025-06-23 11:32:34 +02:00
35c14ce8a8
chore: update CLAUDE.md 2025-06-23 11:20:21 +02:00
e0ff369cff
chore: make format
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
2025-06-23 11:19:22 +02:00
9 changed files with 150 additions and 15 deletions

View file

@ -18,10 +18,12 @@ When creating, modifying, or removing plugins:
## Testing ## Testing
Before committing plugin changes: **CRITICAL**: After making ANY changes to code files, you MUST run these commands in order:
1. Check files are properly formatted: Run `make format` 1. **Format code**: `make format` - Format all code according to project standards
2. Check code style and linting: Run `make lint` 2. **Lint code**: `make lint` - Check code style and quality (must show "0 issues")
3. Test the plugin functionality: Run `make test` 3. **Run tests**: `make test` - Run all tests to ensure functionality works
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 class="form-help"> <div>
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>

View file

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

View file

@ -74,6 +74,7 @@ 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{
@ -151,6 +152,7 @@ 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

@ -0,0 +1,120 @@
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")
}
})
}
}