parent
95a9a2146a
commit
e4102e9a90
@ -1,4 +1,4 @@
|
||||
# i2_bot: бот лиги Инстинкт игры @PokememBroBot
|
||||
|
||||
Для запуска нужен правильный ``config.json``.
|
||||
Для запуска нужен правильный ``config.yml``.
|
||||
Управление зависимостями осуществляет [dep](https://github.com/golang/dep).
|
||||
|
@ -6,12 +6,14 @@ package main
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/chatter"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/forwarder"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/getters"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/migrations"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/parsers"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/pinner"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/router"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/squader"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/talkers"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/welcomer"
|
||||
"time"
|
||||
@ -33,6 +35,8 @@ func main() {
|
||||
talkers.New(c)
|
||||
getters.New(c)
|
||||
welcomer.New(c)
|
||||
chatter.New(c)
|
||||
squader.New(c)
|
||||
|
||||
c.Log.Info("=======================")
|
||||
c.Log.Info("= i2_bot initialized. =")
|
||||
|
@ -6,6 +6,7 @@ package appcontext
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/chatter/chatterinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/config"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/connections"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/forwarder/forwarderinterface"
|
||||
@ -14,6 +15,7 @@ import (
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/parsers/parsersinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/pinner/pinnerinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/router/routerinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/squader/squaderinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/talkers/talkersinterface"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/welcomer/welcomerinterface"
|
||||
"lab.pztrn.name/golibs/mogrus"
|
||||
@ -34,6 +36,8 @@ type Context struct {
|
||||
Getters gettersinterface.GettersInterface
|
||||
Welcomer welcomerinterface.WelcomerInterface
|
||||
Pinner pinnerinterface.PinnerInterface
|
||||
Chatter chatterinterface.ChatterInterface
|
||||
Squader squaderinterface.SquaderInterface
|
||||
}
|
||||
|
||||
// Init is a initialization function for context
|
||||
@ -106,6 +110,18 @@ func (c *Context) RegisterForwarderInterface(fi forwarderinterface.ForwarderInte
|
||||
c.Forwarder.Init()
|
||||
}
|
||||
|
||||
// RegisterChatterInterface registers chatter interface in application
|
||||
func (c *Context) RegisterChatterInterface(ci chatterinterface.ChatterInterface) {
|
||||
c.Chatter = ci
|
||||
c.Chatter.Init()
|
||||
}
|
||||
|
||||
// RegisterSquaderInterface registers squader interface in application
|
||||
func (c *Context) RegisterSquaderInterface(si squaderinterface.SquaderInterface) {
|
||||
c.Squader = si
|
||||
c.Squader.Init()
|
||||
}
|
||||
|
||||
// RunDatabaseMigrations applies migrations on bot's startup
|
||||
func (c *Context) RunDatabaseMigrations() {
|
||||
c.Migrations.SetDialect("mysql")
|
||||
|
24
lib/chatter/chatterinterface/chatterinterface.go
Normal file
24
lib/chatter/chatterinterface/chatterinterface.go
Normal file
@ -0,0 +1,24 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package chatterinterface
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
|
||||
)
|
||||
|
||||
// ChatterInterface implements Chatter for importing via appcontext.
|
||||
type ChatterInterface interface {
|
||||
Init()
|
||||
|
||||
GetOrCreateChat(update *tgbotapi.Update) (dbmapping.Chat, bool)
|
||||
GetChatByID(chatID int64) (dbmapping.Chat, bool)
|
||||
GetAllPrivateChats() ([]dbmapping.Chat, bool)
|
||||
GetAllGroupChats() ([]dbmapping.Chat, bool)
|
||||
|
||||
UpdateChatTitle(chatRaw *dbmapping.Chat, newTitle string) (*dbmapping.Chat, bool)
|
||||
UpdateChatTelegramID(update *tgbotapi.Update) (*dbmapping.Chat, bool)
|
||||
|
||||
GroupsList(update *tgbotapi.Update) string
|
||||
}
|
28
lib/chatter/exported.go
Normal file
28
lib/chatter/exported.go
Normal file
@ -0,0 +1,28 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package chatter
|
||||
|
||||
import (
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/chatter/chatterinterface"
|
||||
)
|
||||
|
||||
var (
|
||||
c *appcontext.Context
|
||||
)
|
||||
|
||||
// Chatter is a function-handling struct for package chatter.
|
||||
type Chatter struct{}
|
||||
|
||||
// New is an initialization function for appcontext
|
||||
func New(ac *appcontext.Context) {
|
||||
c = ac
|
||||
ct := &Chatter{}
|
||||
c.RegisterChatterInterface(chatterinterface.ChatterInterface(ct))
|
||||
}
|
||||
|
||||
// Init is a initialization function for package
|
||||
func (ct *Chatter) Init() {
|
||||
c.Log.Info("Initializing Chatter...")
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package getters
|
||||
package chatter
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
@ -9,8 +9,43 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ct *Chatter) getAllGroupChatsWithSquads() ([]dbmapping.ChatSquad, bool) {
|
||||
chatsSquads := []dbmapping.ChatSquad{}
|
||||
groupChats := []dbmapping.Chat{}
|
||||
|
||||
err := c.Db.Select(&groupChats, "SELECT * FROM chats WHERE chat_type IN ('group', 'supergroup')")
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return chatsSquads, false
|
||||
}
|
||||
|
||||
for i := range groupChats {
|
||||
chatSquad := dbmapping.ChatSquad{}
|
||||
squad := dbmapping.Squad{}
|
||||
err = c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id=?"), groupChats[i].ID)
|
||||
if err != nil {
|
||||
c.Log.Debug(err)
|
||||
} else {
|
||||
chatSquad.ChatRole = "squad"
|
||||
}
|
||||
err = c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE flood_chat_id=?"), groupChats[i].ID)
|
||||
if err != nil {
|
||||
c.Log.Debug(err)
|
||||
} else {
|
||||
chatSquad.ChatRole = "flood"
|
||||
}
|
||||
|
||||
chatSquad.Squad = squad
|
||||
chatSquad.Chat = groupChats[i]
|
||||
|
||||
chatsSquads = append(chatsSquads, chatSquad)
|
||||
}
|
||||
|
||||
return chatsSquads, true
|
||||
}
|
||||
|
||||
// GetChatByID returns dbmapping.Chat instance with given ID.
|
||||
func (g *Getters) GetChatByID(chatID int64) (dbmapping.Chat, bool) {
|
||||
func (ct *Chatter) GetChatByID(chatID int64) (dbmapping.Chat, bool) {
|
||||
chatRaw := dbmapping.Chat{}
|
||||
err := c.Db.Get(&chatRaw, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), chatID)
|
||||
if err != nil {
|
||||
@ -23,7 +58,7 @@ func (g *Getters) GetChatByID(chatID int64) (dbmapping.Chat, bool) {
|
||||
|
||||
// GetOrCreateChat seeks for chat in database via Telegram update.
|
||||
// In case, when there is no chat with such ID, new chat will be created.
|
||||
func (g *Getters) GetOrCreateChat(telegramUpdate *tgbotapi.Update) (dbmapping.Chat, bool) {
|
||||
func (ct *Chatter) GetOrCreateChat(telegramUpdate *tgbotapi.Update) (dbmapping.Chat, bool) {
|
||||
chatRaw := dbmapping.Chat{}
|
||||
c.Log.Debug("TGID: ", telegramUpdate.Message.Chat.ID)
|
||||
err := c.Db.Get(&chatRaw, c.Db.Rebind("SELECT * FROM chats WHERE telegram_id=?"), telegramUpdate.Message.Chat.ID)
|
||||
@ -68,7 +103,7 @@ func (g *Getters) GetOrCreateChat(telegramUpdate *tgbotapi.Update) (dbmapping.Ch
|
||||
}
|
||||
|
||||
// GetAllPrivateChats returns all private chats
|
||||
func (g *Getters) GetAllPrivateChats() ([]dbmapping.Chat, bool) {
|
||||
func (ct *Chatter) GetAllPrivateChats() ([]dbmapping.Chat, bool) {
|
||||
privateChats := []dbmapping.Chat{}
|
||||
|
||||
err := c.Db.Select(&privateChats, "SELECT * FROM chats WHERE chat_type='private'")
|
||||
@ -81,7 +116,7 @@ func (g *Getters) GetAllPrivateChats() ([]dbmapping.Chat, bool) {
|
||||
}
|
||||
|
||||
// GetAllGroupChats returns all group chats
|
||||
func (g *Getters) GetAllGroupChats() ([]dbmapping.Chat, bool) {
|
||||
func (ct *Chatter) GetAllGroupChats() ([]dbmapping.Chat, bool) {
|
||||
groupChats := []dbmapping.Chat{}
|
||||
|
||||
err := c.Db.Select(&groupChats, "SELECT * FROM chats WHERE chat_type IN ('group', 'supergroup')")
|
||||
@ -91,47 +126,4 @@ func (g *Getters) GetAllGroupChats() ([]dbmapping.Chat, bool) {
|
||||
}
|
||||
|
||||
return groupChats, true
|
||||
}
|
||||
|
||||
// GetAllGroupChatsWithSquads returns all group chats with squads
|
||||
func (g *Getters) GetAllGroupChatsWithSquads() ([]dbmapping.SquadChat, bool) {
|
||||
chatsSquads := []dbmapping.SquadChat{}
|
||||
groupChats := []dbmapping.Chat{}
|
||||
|
||||
err := c.Db.Select(&groupChats, "SELECT * FROM chats WHERE chat_type IN ('group', 'supergroup')")
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return chatsSquads, false
|
||||
}
|
||||
|
||||
for i := range groupChats {
|
||||
chatSquad := dbmapping.SquadChat{}
|
||||
squad := dbmapping.Squad{}
|
||||
err = c.Db.Select(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id="), groupChats[i].ID)
|
||||
if err != nil {
|
||||
c.Log.Debug(err)
|
||||
chatSquad.IsSquad = false
|
||||
} else {
|
||||
chatSquad.IsSquad = true
|
||||
}
|
||||
|
||||
chatSquad.Squad = squad
|
||||
chatSquad.Chat = groupChats[i]
|
||||
|
||||
chatsSquads = append(chatsSquads, chatSquad)
|
||||
}
|
||||
|
||||
return chatsSquads, true
|
||||
}
|
||||
|
||||
// UpdateChatTitle updates chat title in database
|
||||
func (g *Getters) UpdateChatTitle(chatRaw *dbmapping.Chat, newTitle string) (*dbmapping.Chat, bool) {
|
||||
chatRaw.Name = newTitle
|
||||
_, err := c.Db.NamedExec("UPDATE chats SET name=:name WHERE id=:id", &chatRaw)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return chatRaw, false
|
||||
}
|
||||
|
||||
return chatRaw, true
|
||||
}
|
||||
}
|
42
lib/chatter/responders.go
Normal file
42
lib/chatter/responders.go
Normal file
@ -0,0 +1,42 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package chatter
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// GroupsList lists all chats where bot exist
|
||||
func (ct *Chatter) GroupsList(update *tgbotapi.Update) string {
|
||||
groupChats, ok := ct.getAllGroupChatsWithSquads()
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
message := "*Бот состоит в следующих групповых чатах:*\n"
|
||||
|
||||
for i := range groupChats {
|
||||
message += "---\n"
|
||||
message += "[#" + strconv.Itoa(groupChats[i].Chat.ID) + "] _" + groupChats[i].Chat.Name + "_\n"
|
||||
message += "Telegram ID: " + strconv.FormatInt(groupChats[i].Chat.TelegramID, 10) + "\n"
|
||||
if groupChats[i].ChatRole == "squad" {
|
||||
message += "Статистика отряда:\n"
|
||||
message += c.Squader.SquadStatictics(groupChats[i].Squad.ID)
|
||||
} else if groupChats[i].ChatRole == "flood" {
|
||||
message += "Является флудочатом отряда №" + strconv.Itoa(groupChats[i].Squad.ID) + "\n"
|
||||
} else {
|
||||
message += "Не является отрядом.\n"
|
||||
}
|
||||
}
|
||||
|
||||
message += "\nЧтобы создать отряд, введите команду /make\\_squad _X Y_, где _X_ — номер чата с пинами (в нём позволено писать лишь боту и командирам), а _Y_ — чат-флудилка для общения отряда."
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "ok"
|
||||
}
|
43
lib/chatter/updaters.go
Normal file
43
lib/chatter/updaters.go
Normal file
@ -0,0 +1,43 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package chatter
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
|
||||
)
|
||||
|
||||
// UpdateChatTitle updates chat title in database
|
||||
func (ct *Chatter) UpdateChatTitle(chatRaw *dbmapping.Chat, newTitle string) (*dbmapping.Chat, bool) {
|
||||
chatRaw.Name = newTitle
|
||||
_, err := c.Db.NamedExec("UPDATE chats SET name=:name WHERE id=:id", &chatRaw)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return chatRaw, false
|
||||
}
|
||||
|
||||
return chatRaw, true
|
||||
}
|
||||
|
||||
// UpdateChatTelegramID updates chat's TelegramID when it converts to supergroup
|
||||
func (ct *Chatter) UpdateChatTelegramID(update *tgbotapi.Update) (*dbmapping.Chat, bool) {
|
||||
c.Log.Debug("Updating existing Telegram chat ID...")
|
||||
chatRaw := dbmapping.Chat{}
|
||||
err := c.Db.Get(&chatRaw, c.Db.Rebind("SELECT * FROM chats WHERE telegram_id=?"), update.Message.MigrateFromChatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
return &chatRaw, false
|
||||
}
|
||||
if update.Message.SuperGroupChatCreated {
|
||||
chatRaw.ChatType = "supergroup"
|
||||
}
|
||||
chatRaw.TelegramID = update.Message.MigrateToChatID
|
||||
_, err = c.Db.NamedExec("UPDATE chats SET chat_type=:chat_type, telegram_id=:telegram_id WHERE id=:id", &chatRaw)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
return &chatRaw, false
|
||||
}
|
||||
|
||||
return &chatRaw, true
|
||||
}
|
@ -15,3 +15,10 @@ type Chat struct {
|
||||
TelegramID int64 `db:"telegram_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
// ChatSquad is a stuct, which combines information about chats and squads
|
||||
type ChatSquad struct {
|
||||
Chat Chat
|
||||
Squad Squad
|
||||
ChatRole string
|
||||
}
|
||||
|
@ -9,15 +9,16 @@ import (
|
||||
|
||||
// Squad is a struct, which represents `squads` table item in databse.
|
||||
type Squad struct {
|
||||
ID int `db:"id"`
|
||||
ChatID int `db:"chat_id"`
|
||||
AuthorID int `db:"author_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
ID int `db:"id"`
|
||||
ChatID int `db:"chat_id"`
|
||||
FloodChatID int `db:"flood_chat_id"`
|
||||
AuthorID int `db:"author_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
// SquadChat is a stuct, which combines information about chats and squads
|
||||
type SquadChat struct {
|
||||
Squad Squad
|
||||
Chat Chat
|
||||
IsSquad bool
|
||||
Squad Squad
|
||||
Chat Chat
|
||||
FloodChat Chat
|
||||
}
|
||||
|
@ -15,3 +15,10 @@ type SquadPlayer struct {
|
||||
AuthorID int `db:"author_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
// SquadPlayerFull is a struct, which handles all related information
|
||||
type SquadPlayerFull struct {
|
||||
Squad Squad
|
||||
Player Player
|
||||
Profile Profile
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
package gettersinterface
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
|
||||
)
|
||||
|
||||
@ -14,12 +13,6 @@ type GettersInterface interface {
|
||||
CreateBroadcastMessage(playerRaw *dbmapping.Player, messageBody string, broadcastType string) (dbmapping.Broadcast, bool)
|
||||
GetBroadcastMessageByID(messageID int) (dbmapping.Broadcast, bool)
|
||||
UpdateBroadcastMessageStatus(messageID int, messageStatus string) (dbmapping.Broadcast, bool)
|
||||
GetOrCreateChat(update *tgbotapi.Update) (dbmapping.Chat, bool)
|
||||
GetChatByID(chatID int64) (dbmapping.Chat, bool)
|
||||
GetAllPrivateChats() ([]dbmapping.Chat, bool)
|
||||
GetAllGroupChats() ([]dbmapping.Chat, bool)
|
||||
GetAllGroupChatsWithSquads() ([]dbmapping.SquadChat, bool)
|
||||
UpdateChatTitle(chatRaw *dbmapping.Chat, newTitle string) (*dbmapping.Chat, bool)
|
||||
GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool)
|
||||
GetPlayerByID(playerID int) (dbmapping.Player, bool)
|
||||
PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool
|
||||
|
29
lib/migrations/22_add_flood_chat_id.go
Normal file
29
lib/migrations/22_add_flood_chat_id.go
Normal file
@ -0,0 +1,29 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// AddFloodChatIDUp creates `flood_chat_id` column in `squads` table
|
||||
func AddFloodChatIDUp(tx *sql.Tx) error {
|
||||
_, err := tx.Exec("ALTER TABLE `squads` ADD COLUMN `flood_chat_id` INT(11) NOT NULL DEFAULT 0 COMMENT 'ID группы для общения отряда' AFTER `chat_id`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddFloodChatIDDown destroys `flood_chat_id` column
|
||||
func AddFloodChatIDDown(tx *sql.Tx) error {
|
||||
_, err := tx.Exec("ALTER TABLE `squads` DROP COLUMN `flood_chat_id`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -32,6 +32,7 @@ func (m *Migrations) Init() {
|
||||
goose.AddNamedMigration("19_create_broadcasts.go", CreateBroadcastsUp, CreateBroadcastsDown)
|
||||
goose.AddNamedMigration("20_create_squads.go", CreateSquadsUp, CreateSquadsDown)
|
||||
goose.AddNamedMigration("21_change_telegram_id_column.go", ChangeTelegramIDColumnUp, ChangeTelegramIDColumnDown)
|
||||
goose.AddNamedMigration("22_add_flood_chat_id.go", AddFloodChatIDUp, AddFloodChatIDDown)
|
||||
}
|
||||
|
||||
// Migrate migrates database to current version
|
||||
|
@ -15,7 +15,7 @@ func (p *Pinner) PinMessageToAllChats(update *tgbotapi.Update) string {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
groupChats, ok := c.Getters.GetAllGroupChats()
|
||||
groupChats, ok := c.Chatter.GetAllGroupChats()
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
@ -27,7 +27,17 @@ func (r *Router) routeGroupRequest(update *tgbotapi.Update, playerRaw *dbmapping
|
||||
}
|
||||
// New chat names
|
||||
if update.Message.NewChatTitle != "" {
|
||||
_, ok := c.Getters.UpdateChatTitle(chatRaw, update.Message.NewChatTitle)
|
||||
_, ok := c.Chatter.UpdateChatTitle(chatRaw, update.Message.NewChatTitle)
|
||||
if ok {
|
||||
return "ok"
|
||||
}
|
||||
|
||||
return "fail"
|
||||
}
|
||||
|
||||
// New chat IDs (usually on supergroup creation)
|
||||
if (update.Message.MigrateToChatID != 0) && (update.Message.MigrateFromChatID != 0) {
|
||||
_, ok := c.Chatter.UpdateChatTelegramID(update)
|
||||
if ok {
|
||||
return "ok"
|
||||
}
|
||||
|
@ -78,10 +78,25 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi
|
||||
return "fail"
|
||||
case update.Message.Command() == "group_chats":
|
||||
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
|
||||
c.Talkers.GroupsList(update)
|
||||
c.Chatter.GroupsList(update)
|
||||
return "ok"
|
||||
}
|
||||
|
||||
c.Talkers.AnyMessageUnauthorized(update)
|
||||
return "fail"
|
||||
case update.Message.Command() == "squads":
|
||||
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
|
||||
c.Squader.SquadsList(update)
|
||||
return "ok"
|
||||
}
|
||||
|
||||
c.Talkers.AnyMessageUnauthorized(update)
|
||||
return "fail"
|
||||
case update.Message.Command() == "make_squad":
|
||||
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
|
||||
return c.Squader.CreateSquad(update)
|
||||
}
|
||||
|
||||
c.Talkers.AnyMessageUnauthorized(update)
|
||||
return "fail"
|
||||
case update.Message.Command() == "pin":
|
||||
|
@ -15,7 +15,7 @@ func (r *Router) RouteRequest(update *tgbotapi.Update) string {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
chatRaw, ok := c.Getters.GetOrCreateChat(update)
|
||||
chatRaw, ok := c.Chatter.GetOrCreateChat(update)
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
28
lib/squader/exported.go
Normal file
28
lib/squader/exported.go
Normal file
@ -0,0 +1,28 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package squader
|
||||
|
||||
import (
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/squader/squaderinterface"
|
||||
)
|
||||
|
||||
var (
|
||||
c *appcontext.Context
|
||||
)
|
||||
|
||||
// Squader is a function-handling struct for package squader.
|
||||
type Squader struct{}
|
||||
|
||||
// New is an initialization function for appcontext
|
||||
func New(ac *appcontext.Context) {
|
||||
c = ac
|
||||
s := &Squader{}
|
||||
c.RegisterSquaderInterface(squaderinterface.SquaderInterface(s))
|
||||
}
|
||||
|
||||
// Init is a initialization function for package
|
||||
func (s *Squader) Init() {
|
||||
c.Log.Info("Initializing Squader...")
|
||||
}
|
257
lib/squader/squader.go
Normal file
257
lib/squader/squader.go
Normal file
@ -0,0 +1,257 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package squader
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *Squader) getAllSquadsWithChats() ([]dbmapping.SquadChat, bool) {
|
||||
squadsWithChats := []dbmapping.SquadChat{}
|
||||
squads := []dbmapping.Squad{}
|
||||
|
||||
err := c.Db.Select(&squads, "SELECT * FROM squads")
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squadsWithChats, false
|
||||
}
|
||||
|
||||
for i := range squads {
|
||||
chatSquad := dbmapping.SquadChat{}
|
||||
chat := dbmapping.Chat{}
|
||||
floodChat := dbmapping.Chat{}
|
||||
err = c.Db.Get(&chat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), squads[i].ChatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squadsWithChats, false
|
||||
}
|
||||
err = c.Db.Get(&floodChat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), squads[i].FloodChatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squadsWithChats, false
|
||||
}
|
||||
|
||||
chatSquad.Squad = squads[i]
|
||||
chatSquad.Chat = chat
|
||||
chatSquad.FloodChat = floodChat
|
||||
|
||||
squadsWithChats = append(squadsWithChats, chatSquad)
|
||||
}
|
||||
|
||||
return squadsWithChats, true
|
||||
}
|
||||
|
||||
func (s *Squader) createSquad(update *tgbotapi.Update, chatID int, floodChatID int) (dbmapping.Squad, string) {
|
||||
squad := dbmapping.Squad{}
|
||||
chat := dbmapping.Chat{}
|
||||
floodChat := dbmapping.Chat{}
|
||||
|
||||
// Checking if chats in database exist
|
||||
err := c.Db.Get(&chat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), chatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
err = c.Db.Get(&floodChat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), floodChatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
err2 := c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id IN (?, ?) OR flood_chat_id IN (?, ?)"), chat.ID, floodChat.ID, chat.ID, floodChat.ID)
|
||||
if err2 == nil {
|
||||
return squad, "dup"
|
||||
}
|
||||
c.Log.Debug(err2)
|
||||
|
||||
err = c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id=? AND flood_chat_id=?"), chatID, floodChatID)
|
||||
if err != nil {
|
||||
c.Log.Debug(err)
|
||||
|
||||
playerRaw, ok := c.Getters.GetOrCreatePlayer(update.Message.From.ID)
|
||||
if !ok {
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
squad.AuthorID = playerRaw.ID
|
||||
squad.ChatID = chatID
|
||||
squad.FloodChatID = floodChatID
|
||||
squad.CreatedAt = time.Now().UTC()
|
||||
|
||||
_, err = c.Db.NamedExec("INSERT INTO `squads` VALUES(NULL, :chat_id, :flood_chat_id, :author_id, :created_at)", &squad)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
err = c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id=? AND flood_chat_id=?"), chatID, floodChatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
return squad, "ok"
|
||||
}
|
||||
|
||||
return squad, "dup"
|
||||
}
|
||||
|
||||
func (s *Squader) getSquadByChatID(update *tgbotapi.Update, chatID int) (dbmapping.Squad, string) {
|
||||
squad := dbmapping.Squad{}
|
||||
chat := dbmapping.Chat{}
|
||||
|
||||
// Checking if chat in database exist
|
||||
err := c.Db.Get(&chat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), chatID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
err = c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE chat_id=?"), chat.ID)
|
||||
if err != nil {
|
||||
c.Log.Error(err)
|
||||
return squad, "fail"
|
||||
}
|
||||
|
||||
return squad, "ok"
|
||||
}
|
||||
|
||||
func (s *Squader) squadCreationDuplicate(update *tgbotapi.Update) string {
|
||||
message := "*Отряд уже существует*\n"
|
||||
message += "Проверьте, правильно ли вы ввели команду, и повторите попытку."
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "fail"
|
||||
}
|
||||
|
||||
func (s *Squader) squadCreationFailure(update *tgbotapi.Update) string {
|
||||
message := "*Не удалось добавить отряд в базу*\n"
|
||||
message += "Проверьте, правильно ли вы ввели команду, и повторите попытку."
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "fail"
|
||||
}
|
||||
|
||||
func (s *Squader) squadCreationSuccess(update *tgbotapi.Update) string {
|
||||
message := "*Отряд успешно добавлен в базу*\n"
|
||||
message += "Просмотреть список отрядов можно командой /squads."
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "fail"
|
||||
}
|
||||
|
||||
// External functions
|
||||
|
||||
// CreateSquad creates new squad from chat if not already exist
|
||||
func (s *Squader) CreateSquad(update *tgbotapi.Update) string {
|
||||
commandArugments := update.Message.CommandArguments()
|
||||
argumentsRx := regexp.MustCompile(`(\d+)\s(\d+)`)
|
||||
|
||||
if !argumentsRx.MatchString(commandArugments) {
|
||||
return s.squadCreationFailure(update)
|
||||
}
|
||||
|
||||
chatNumbers := strings.Split(commandArugments, " ")
|
||||
if len(chatNumbers) < 2 {
|
||||
return s.squadCreationFailure(update)
|
||||
}
|
||||
chatID, _ := strconv.Atoi(chatNumbers[0])
|
||||
if chatID == 0 {
|
||||
return s.squadCreationFailure(update)
|
||||
}
|
||||
floodChatID, _ := strconv.Atoi(chatNumbers[1])
|
||||
if floodChatID == 0 {
|
||||
return s.squadCreationFailure(update)
|
||||
}
|
||||
|
||||
_, ok := s.createSquad(update, chatID, floodChatID)
|
||||
if ok == "fail" {
|
||||
return s.squadCreationFailure(update)
|
||||
} else if ok == "dup" {
|
||||
return s.squadCreationDuplicate(update)
|
||||
}
|
||||
|
||||
return s.squadCreationSuccess(update)
|
||||
}
|
||||
|
||||
// SquadsList lists all squads
|
||||
func (s *Squader) SquadsList(update *tgbotapi.Update) string {
|
||||
squads, ok := s.getAllSquadsWithChats()
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
message := "*Наши отряды:*\n"
|
||||
|
||||
for i := range squads {
|
||||
message += "---\n"
|
||||
message += "[#" + strconv.Itoa(squads[i].Squad.ID) + "] _" + squads[i].Chat.Name
|
||||
message += "_ /show\\_squad" + strconv.Itoa(squads[i].Squad.ID) + "\n"
|
||||
message += "Telegram ID: " + strconv.FormatInt(squads[i].Chat.TelegramID, 10) + "\n"
|
||||
message += "Флудилка отряда: _" + squads[i].FloodChat.Name + "_\n"
|
||||
message += "Статистика отряда:\n"
|
||||
message += s.SquadStatictics(squads[i].Squad.ID)
|
||||
}
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// SquadStatictics generates statistics message snippet. Public due to usage in chats list
|
||||
func (s *Squader) SquadStatictics(squadID int) string {
|
||||
squadMembersWithInformation := []dbmapping.SquadPlayerFull{}
|
||||
squadMembers := []dbmapping.SquadPlayer{}
|
||||
squad := dbmapping.Squad{}
|
||||
|
||||
err := c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE id=?"), squadID)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
return "Отряда не существует!"
|
||||
}
|
||||
|
||||
err = c.Db.Select(&squadMembers, c.Db.Rebind("SELECT * FROM squads_players WHERE squad_id=?"), squadID)
|
||||
if err != nil {
|
||||
c.Log.Error(err.Error())
|
||||
return "Невозможно получить информацию о данном отряде. Возможно, он пуст или произошла ошибка."
|
||||
}
|
||||
|
||||
for i := range squadMembers {
|
||||
fullInfo := dbmapping.SquadPlayerFull{}
|
||||
|
||||
playerRaw, _ := c.Getters.GetPlayerByID(squadMembers[i].PlayerID)
|
||||
profileRaw, _ := c.Getters.GetProfile(playerRaw.ID)
|
||||
|
||||
fullInfo.Squad = squad
|
||||
fullInfo.Player = playerRaw
|
||||
fullInfo.Profile = profileRaw
|
||||
|
||||
squadMembersWithInformation = append(squadMembersWithInformation, fullInfo)
|
||||
}
|
||||
|
||||
message := "Количество человек в отряде: " + strconv.Itoa(len(squadMembersWithInformation))
|
||||
message += "\n"
|
||||
|
||||
return message
|
||||
}
|
16
lib/squader/squaderinterface/squaderinterface.go
Normal file
16
lib/squader/squaderinterface/squaderinterface.go
Normal file
@ -0,0 +1,16 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package squaderinterface
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
)
|
||||
|
||||
// SquaderInterface implements Squader for importing via appcontext.
|
||||
type SquaderInterface interface {
|
||||
Init()
|
||||
CreateSquad(update *tgbotapi.Update) string
|
||||
SquadsList(update *tgbotapi.Update) string
|
||||
SquadStatictics(squadID int) string
|
||||
}
|
@ -4,10 +4,10 @@
|
||||
package talkers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AdminBroadcastMessageCompose saves message for future broadcast
|
||||
@ -63,7 +63,7 @@ func (t *Talkers) AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *
|
||||
|
||||
broadcastingMessageBody := messageRaw.Text
|
||||
|
||||
privateChats, ok := c.Getters.GetAllPrivateChats()
|
||||
privateChats, ok := c.Chatter.GetAllPrivateChats()
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
// i2_bot – Instinct PokememBro Bot
|
||||
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
|
||||
|
||||
package talkers
|
||||
|
||||
import (
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// GroupsList lists all chats where bot exist
|
||||
func (t *Talkers) GroupsList(update *tgbotapi.Update) string {
|
||||
groupChats, ok := c.Getters.GetAllGroupChatsWithSquads()
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
message := "*Бот состоит в следующих групповых чатах:*\n"
|
||||
|
||||
for i := range groupChats {
|
||||
message += "---\n"
|
||||
message += "[#" + strconv.Itoa(groupChats[i].Chat.ID) + "] _" + groupChats[i].Chat.Name + "_\n"
|
||||
message += "Telegram ID: " + strconv.FormatInt(groupChats[i].Chat.TelegramID, 10) + "\n"
|
||||
if groupChats[i].IsSquad {
|
||||
message += "Является отрядом <статистика>\n"
|
||||
} else {
|
||||
message += "Не является отрядом. Сделать отрядом: /make\\_squad" + strconv.Itoa(groupChats[i].Chat.ID) + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
|
||||
msg.ParseMode = "Markdown"
|
||||
|
||||
c.Bot.Send(msg)
|
||||
|
||||
return "ok"
|
||||
}
|
@ -20,6 +20,7 @@ func (t *Talkers) HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Play
|
||||
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
|
||||
message += "+ /send\\_all _текст_ — отправить сообщение всем пользователям бота\n"
|
||||
message += "+ /group\\_chats — получить список групп, в которых работает бот.\n"
|
||||
message += "+ /squads — получить список отрядов.\n"
|
||||
message += "+ /pin _текст_ — отправить сообщение во все группы, где находится бот. Сообщение будет автоматически запинено.\n"
|
||||
}
|
||||
message += "+ /help – выводит данное сообщение\n"
|
||||
|
@ -31,8 +31,6 @@ type TalkersInterface interface {
|
||||
AdminBroadcastMessageCompose(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
|
||||
AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
|
||||
|
||||
GroupsList(update *tgbotapi.Update) string
|
||||
|
||||
DurakMessage(update *tgbotapi.Update)
|
||||
MatMessage(update *tgbotapi.Update)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
func (w *Welcomer) alertUserWithoutProfile(update *tgbotapi.Update, newUser *tgbotapi.User) string {
|
||||
alertGroupID, _ := strconv.ParseInt(c.Cfg.Notifications.GroupID, 10, 64)
|
||||
chat, ok := c.Getters.GetOrCreateChat(update)
|
||||
chat, ok := c.Chatter.GetOrCreateChat(update)
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
@ -29,7 +29,7 @@ func (w *Welcomer) alertUserWithoutProfile(update *tgbotapi.Update, newUser *tgb
|
||||
|
||||
func (w *Welcomer) alertSpyUser(update *tgbotapi.Update, newUser *tgbotapi.User) string {
|
||||
alertGroupID, _ := strconv.ParseInt(c.Cfg.Notifications.GroupID, 10, 64)
|
||||
chat, ok := c.Getters.GetOrCreateChat(update)
|
||||
chat, ok := c.Chatter.GetOrCreateChat(update)
|
||||
if !ok {
|
||||
return "fail"
|
||||
}
|
||||
|
Reference in New Issue
Block a user