Archived
1

Work on squads, some refactoring

Closes #14
See #8
This commit is contained in:
Vladimir Hodakov 2017-11-19 22:16:11 +04:00
parent 95a9a2146a
commit e4102e9a90
26 changed files with 587 additions and 112 deletions

View File

@ -1,4 +1,4 @@
# i2_bot: бот лиги Инстинкт игры @PokememBroBot
Для запуска нужен правильный ``config.json``.
Для запуска нужен правильный ``config.yml``.
Управление зависимостями осуществляет [dep](https://github.com/golang/dep).

View File

@ -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. =")

View File

@ -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")

View 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
View 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...")
}

View File

@ -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
View 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
View 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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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":

View File

@ -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
View 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
View 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
}

View 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
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"

View File

@ -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)
}

View File

@ -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"
}