@@ -12,9 +12,16 @@ import (
1212 "strings"
1313 "sync"
1414
15- tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
15+ telegram "github.com/go-telegram-bot-api/telegram-bot-api"
1616)
1717
18+ // TrollShieldBot aggregate the methods used by my bot to keep mocking easier
19+ type TrollShieldBot interface {
20+ GetChatMember (telegram.ChatConfigWithUser ) (telegram.ChatMember , error )
21+ KickChatMember (telegram.KickChatMemberConfig ) (telegram.APIResponse , error )
22+ Send (telegram.Chattable ) (telegram.Message , error )
23+ }
24+
1825// blacklist groups, member from that groups will be kicked automatically
1926var trollGroups = []string {
2027 "@ccppbrasil" ,
@@ -31,16 +38,78 @@ const logfile = "troll-shield.log"
3138
3239var log = logger .New (os .Stderr , "" , logger .LstdFlags )
3340
34- // findTrollHouse return the troll house group name if is well-known
35- // otherwise, returns a empty string
36- func findTrollHouses (bot * tgbotapi.BotAPI , userID int ) string {
41+ // messageEvent return true if is a message event
42+ func messageEvent (update * telegram.Update ) bool {
43+ return update .Message != nil
44+ }
45+
46+ // newChatMemberEvent return true if a new member joined to chat
47+ func newChatMemberEvent (update * telegram.Update ) bool {
48+ return messageEvent (update ) && update .Message .NewChatMembers != nil
49+ }
50+
51+ // fromChatEvent return true if the message is from a specific chat
52+ func fromChatEvent (update * telegram.Update , username string ) bool {
53+ chat := update .Message .Chat
54+ return messageEvent (update ) && chat != nil && (chat .UserName == username || chat .Title == username )
55+ }
56+
57+ // getUserName return the most meaningful name available from a telegram user
58+ // if it has a @username, return it
59+ // if not, try to return FirstName + LastName
60+ // otherwise, only return the FirstName
61+ func getUserName (user telegram.User ) string {
62+ username := user .FirstName
63+ if user .UserName != "" {
64+ username = fmt .Sprintf ("@%v" , user .UserName )
65+ } else if user .LastName != "" {
66+ username = fmt .Sprintf ("%s %s" , user .FirstName , user .LastName )
67+ }
68+ return username
69+ }
70+
71+ func getUpdates (bot * telegram.BotAPI ) telegram.UpdatesChannel {
72+ u := telegram .NewUpdate (0 )
73+ u .Timeout = 60
74+ updates , err := bot .GetUpdatesChan (u )
75+ if err != nil {
76+ log .Printf ("getUpdates error: %v" , err )
77+ }
78+
79+ return updates
80+ }
81+
82+ func reply (bot TrollShieldBot , update * telegram.Update , text string ) {
83+ msg := telegram .NewMessage (update .Message .Chat .ID , text )
84+ msg .ReplyToMessageID = update .Message .MessageID
85+
86+ _ , err := bot .Send (msg )
87+ if err != nil {
88+ log .Printf ("[!] Send msg failed: %v" , err )
89+ }
90+ }
91+
92+ func welcomeMessage (bot TrollShieldBot , update * telegram.Update , member telegram.User ) {
93+ username := getUserName (member )
94+ text := fmt .Sprintf (
95+ `Olá %s! Seja bem-vindo ao grupo oficial de Common Lisp do Brasil.
96+ Leia as regras em: https://lisp.com.br/rules.html.` ,
97+ username ,
98+ )
99+ reply (bot , update , text )
100+ }
101+
102+ // findTrollHouses return a string with groups separeted by comma,
103+ // that groups are well-known to being troll houses.
104+ // otherwise, if nothing is found returns a empty string
105+ func findTrollHouses (bot TrollShieldBot , userID int ) string {
37106 ch := make (chan string , len (trollGroups ))
38107 var wait sync.WaitGroup
39108 for _ , trollGroup := range trollGroups {
40109 wait .Add (1 )
41110 go func (group string ) {
42111 defer wait .Done ()
43- c , _ := bot .GetChatMember (tgbotapi .ChatConfigWithUser {
112+ c , _ := bot .GetChatMember (telegram .ChatConfigWithUser {
44113 SuperGroupUsername : group ,
45114 UserID : userID ,
46115 })
@@ -66,20 +135,29 @@ func findTrollHouses(bot *tgbotapi.BotAPI, userID int) string {
66135 return strings .Join (houses , ", " )
67136}
68137
69- // messageEvent: return true if is a message event
70- func messageEvent (update * tgbotapi.Update ) bool {
71- return update .Message != nil
72- }
73-
74- // newChatMemberEvent: return true if a new member joined to chat
75- func newChatMemberEvent (update * tgbotapi.Update ) bool {
76- return messageEvent (update ) && update .Message .NewChatMembers != nil
77- }
78-
79- // fromChatEvent: return true if the message is from a specific chat
80- func fromChatEvent (update * tgbotapi.Update , username string ) bool {
81- chat := update .Message .Chat
82- return messageEvent (update ) && chat != nil && (chat .UserName == username || chat .Title == username )
138+ // kickTroll ban the troll and send a message about where we can found the trolls
139+ func kickTroll (bot TrollShieldBot , update * telegram.Update , user telegram.User , trollHouse string ) {
140+ chatMember := telegram.ChatMemberConfig {
141+ ChatID : update .Message .Chat .ID ,
142+ UserID : user .ID ,
143+ }
144+ resp , err := bot .KickChatMember (
145+ telegram.KickChatMemberConfig {ChatMemberConfig : chatMember },
146+ )
147+
148+ if ! resp .Ok || err != nil {
149+ log .Printf (
150+ "[!] Kicking %q did not work, error code %v: %v" ,
151+ user .FirstName , resp .ErrorCode , resp .Description ,
152+ )
153+ } else {
154+ username := getUserName (user )
155+ text := fmt .Sprintf (
156+ "%v foi banido porque é membro do grupo: %v. Adeus." ,
157+ username , trollHouse ,
158+ )
159+ reply (bot , update , text )
160+ }
83161}
84162
85163func setupLogging () {
@@ -92,39 +170,18 @@ func setupLogging() {
92170
93171 log .SetOutput (wrt )
94172 // register log to BotLoggt
95- err = tgbotapi .SetLogger (log )
173+ err = telegram .SetLogger (log )
96174 if err != nil {
97175 log .Printf ("Set Telegram Bot Logging error: %v" , err )
98176 }
99177}
100178
101- func getUserName (user tgbotapi.User ) string {
102- username := user .FirstName
103- if user .UserName != "" {
104- username = fmt .Sprintf ("@%v" , user .UserName )
105- } else if user .LastName != "" {
106- username = fmt .Sprintf ("%s %s" , user .FirstName , user .LastName )
107- }
108- return username
109- }
110-
111- func reply (bot * tgbotapi.BotAPI , update * tgbotapi.Update , text string ) {
112- msg := tgbotapi .NewMessage (update .Message .Chat .ID , text )
113- msg .ReplyToMessageID = update .Message .MessageID
114-
115- _ , err := bot .Send (msg )
116- if err != nil {
117- log .Printf ("[!] Send msg failed: %v" , err )
118- }
119- }
120-
121- func main () {
122- setupLogging ()
179+ func setupBot () * telegram.BotAPI {
123180 token , exists := os .LookupEnv ("TELEGRAM_BOT_TOKEN" )
124181 if ! exists {
125182 log .Fatal ("TELEGRAM_BOT_TOKEN env should be defined." )
126183 }
127- bot , err := tgbotapi .NewBotAPI (token )
184+ bot , err := telegram .NewBotAPI (token )
128185
129186 if err != nil {
130187 log .Panic (err )
@@ -134,12 +191,13 @@ func main() {
134191
135192 log .Printf ("Authorized on account @%s" , bot .Self .UserName )
136193
137- u := tgbotapi .NewUpdate (0 )
138- u .Timeout = 60
139-
140- updates , err := bot .GetUpdatesChan (u )
194+ return bot
195+ }
141196
142- for update := range updates {
197+ func main () {
198+ setupLogging ()
199+ bot := setupBot ()
200+ for update := range getUpdates (bot ) {
143201 if messageEvent (& update ) {
144202 if update .Message .Text == "/lelerax" {
145203 reply (bot , & update , "Estou vivo." )
@@ -149,37 +207,9 @@ func main() {
149207 if newChatMemberEvent (& update ) {
150208 for _ , member := range * update .Message .NewChatMembers {
151209 if trollHouse := findTrollHouses (bot , member .ID ); trollHouse != "" {
152- chatMember := tgbotapi.ChatMemberConfig {
153- ChatID : update .Message .Chat .ID ,
154- UserID : member .ID ,
155- }
156- resp , err := bot .KickChatMember (
157- tgbotapi.KickChatMemberConfig {ChatMemberConfig : chatMember },
158- )
159-
160- if resp .Ok == false || err != nil {
161- log .Printf (
162- "[!] Kicking %q did not work, error code %v: %v" ,
163- member .FirstName , resp .ErrorCode , resp .Description ,
164- )
165- } else {
166- username := getUserName (member )
167- text := fmt .Sprintf (
168- "%v foi banido porque é membro do grupo: %v. Adeus." ,
169- username , trollHouse ,
170- )
171- reply (bot , & update , text )
172- }
173- } else {
174- if fromChatEvent (& update , "commonlispbr" ) && ! member .IsBot {
175- username := getUserName (member )
176- text := fmt .Sprintf (
177- `Olá %s! Seja bem-vindo ao grupo oficial de Common Lisp do Brasil.
178- Leia as regras em: https://lisp.com.br/rules.html.` ,
179- username ,
180- )
181- reply (bot , & update , text )
182- }
210+ kickTroll (bot , & update , member , trollHouse )
211+ } else if fromChatEvent (& update , "commonlispbr" ) && ! member .IsBot {
212+ welcomeMessage (bot , & update , member )
183213 }
184214 }
185215 }
0 commit comments