Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Add new message.CommandName filters #159

Open
wants to merge 1 commit into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 7 additions & 33 deletions ext/handlers/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package handlers

import (
"strings"
"unicode/utf8"

"github.com/PaulSonOfLars/gotgbot/v2"
"github.com/PaulSonOfLars/gotgbot/v2/ext"
"github.com/PaulSonOfLars/gotgbot/v2/ext/handlers/filters/message"
)

// Command is the go-to handler for setting up Commands in your bot. By default, it will use telegram-native commands
Expand All @@ -23,6 +23,8 @@ type Command struct {
// NewCommand creates a new case-insensitive command.
// By default, commands do not work on edited messages, or channel posts. These can be enabled by setting the
// AllowEdited and AllowChannel fields respectively.
//
// Note: If more control over commands is desired, consider using NewMessage with a message.CommandName filter.
func NewCommand(c string, r Response) Command {
return Command{
Triggers: []rune{'/'},
Expand Down Expand Up @@ -56,29 +58,29 @@ func (c Command) CheckUpdate(b *gotgbot.Bot, ctx *ext.Context) bool {
if ctx.Message.GetText() == "" {
return false
}
return c.checkMessage(b, ctx.Message)
return message.CommandNameTriggers(b, c.Command, c.Triggers)(ctx.Message)
}

// if no edits and message is edited
if c.AllowEdited && ctx.EditedMessage != nil {
if ctx.EditedMessage.GetText() == "" {
return false
}
return c.checkMessage(b, ctx.EditedMessage)
return message.CommandNameTriggers(b, c.Command, c.Triggers)(ctx.EditedMessage)
}
// if no channel and message is channel message
if c.AllowChannel && ctx.ChannelPost != nil {
if ctx.ChannelPost.GetText() == "" {
return false
}
return c.checkMessage(b, ctx.ChannelPost)
return message.CommandNameTriggers(b, c.Command, c.Triggers)(ctx.ChannelPost)
}
// if no channel, no edits, and post is edited
if c.AllowChannel && c.AllowEdited && ctx.EditedChannelPost != nil {
if ctx.EditedChannelPost.GetText() == "" {
return false
}
return c.checkMessage(b, ctx.EditedChannelPost)
return message.CommandNameTriggers(b, c.Command, c.Triggers)(ctx.EditedChannelPost)
}

return false
Expand All @@ -91,31 +93,3 @@ func (c Command) HandleUpdate(b *gotgbot.Bot, ctx *ext.Context) error {
func (c Command) Name() string {
return "command_" + c.Command
}

func (c Command) checkMessage(b *gotgbot.Bot, msg *gotgbot.Message) bool {
text := msg.GetText()

var cmd string
for _, t := range c.Triggers {
if r, _ := utf8.DecodeRuneInString(text); r != t {
continue
}

split := strings.Split(strings.ToLower(strings.Fields(text)[0]), "@")
if len(split) > 1 && split[1] != strings.ToLower(b.User.Username) {
return false
}
cmd = split[0][1:]
break
}
if cmd == "" {
return false
}

ents := msg.GetEntities()
if len(ents) != 0 && ents[0].Offset == 0 && ents[0].Type != "bot_command" {
return false
}

return cmd == c.Command
}
45 changes: 45 additions & 0 deletions ext/handlers/filters/message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"regexp"
"strings"
"unicode/utf8"

"github.com/PaulSonOfLars/gotgbot/v2"
"github.com/PaulSonOfLars/gotgbot/v2/ext/handlers/filters"
Expand Down Expand Up @@ -134,11 +135,55 @@ func Caption(msg *gotgbot.Message) bool {
return msg.Caption != ""
}

// Command returns true if the message starts with a bot_command entitiy.
func Command(msg *gotgbot.Message) bool {
ents := msg.GetEntities()
return len(ents) > 0 && ents[0].Type == "bot_command" && ents[0].Offset == 0
}

// CommandName returns true if the message starts with a bot_command entity matching the name provided.
// The bot object is required to ensure that the /command@username format is respected.
func CommandName(b *gotgbot.Bot, name string) func(msg *gotgbot.Message) bool {
return CommandNameTriggers(b, name, []rune("/"))
}

// CommandNameTriggers returns true is the message starts with one of the triggers provided, and expects position 0 to
// either be a bot_command entity or no entity at all.
// This means that this filter will not trigger if it has a a code/bold/italics entity at position 0, allowing bot users
// to "escape" commands.
//
// Note: if you are looking to standardise the triggers across your bot, it could be a good idea to create a helper
// function around this to define all your triggers in one place.
func CommandNameTriggers(b *gotgbot.Bot, command string, triggers []rune) func(msg *gotgbot.Message) bool {
return func(msg *gotgbot.Message) bool {
text := msg.GetText()

var msgCmd string
for _, t := range triggers {
if r, _ := utf8.DecodeRuneInString(text); r != t {
continue
}

split := strings.Split(strings.ToLower(strings.Fields(text)[0]), "@")
if len(split) > 1 && split[1] != strings.ToLower(b.User.Username) {
return false
}
msgCmd = split[0][1:]
break
}
if msgCmd == "" {
return false
}

ents := msg.GetEntities()
if len(ents) != 0 && ents[0].Offset == 0 && ents[0].Type != "bot_command" {
return false
}

return msgCmd == command
}
}

func Animation(msg *gotgbot.Message) bool {
return msg.Animation != nil
}
Expand Down
Loading